Compare commits

..
Author SHA1 Message Date
Paul Bakaus af889a59d8 Fix: reclaim unused Stop notice budget
Re-render the displayed new-finding prefix without a discarded attribution reserve. Keep omitted unknown findings behind the cap so reclaimed space cannot expose them without guidance. Cover both finding-count and character limits.

AI assistance: Codex, under maintainer direction.
2026-09-06 16:55:43 -07:00
Paul Bakaus 2595fc8e58 Fix: prioritize Stop findings over notices
Keep stale design reminders opportunistic, compact attribution guidance at small budgets, and emit unknown guidance only for displayed findings. Add regressions for deduplication, finding caps, and single/grouped output limits.

AI assistance: Codex, under maintainer direction.
2026-09-06 16:45:50 -07:00
Paul Bakaus f5c7e294ab Fix: distinguish existing Stop findings from new debt
Capture verified first-edit Claude text baselines without consulting Git HEAD or persisting source. Suppress matching prior findings; label new and unknown attribution, keeping dependency-sensitive and unsupported inputs unknown. Retire exemptions after a fix or scan suppression. Leave explicit scans and per-edit behavior unchanged.

Related to #522. Added regressions and two engine oracle cases; reviewed four existing Stop golden updates for attribution-only output changes. Generated provider output intentionally omitted.

AI assistance: Codex, under maintainer direction.
2026-09-06 16:36:17 -07:00
6 changed files with 57 additions and 98 deletions
+52 -55
View File
@@ -11,9 +11,6 @@ on:
schedule:
- cron: '0 7 * * *'
permissions:
contents: read
concurrency:
# Scheduled runs get their own group: the 07:00 UTC nightly and a push to
# main share github.ref, and cancel-in-progress would let them kill each
@@ -37,12 +34,12 @@ jobs:
live_svelte_adapter_deepseek: ${{ steps.plan.outputs.live_svelte_adapter_deepseek }}
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@v7
with:
node-version: 24
@@ -62,15 +59,15 @@ jobs:
node-version: [22.18.0, 24]
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@v7
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@v7
with:
node-version: ${{ matrix.node-version }}
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
@@ -105,7 +102,7 @@ jobs:
if: needs.changes.outputs.detector == 'true'
run: rustup show && rustup target add wasm32-unknown-unknown
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
- uses: Swatinem/rust-cache@v2
if: needs.changes.outputs.detector == 'true'
- name: Install wasm-pack
@@ -143,7 +140,7 @@ jobs:
run: git diff --exit-code -- .agents .claude .cursor .dsh .gemini .github/skills plugin extension/detector
- name: Upload build artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/upload-artifact@v7
with:
name: impeccable-build-node-${{ matrix.node-version }}
# Ship the packaged zips, not the unpacked Firefox staging tree.
@@ -160,14 +157,14 @@ jobs:
if: needs.changes.outputs.rust == 'true'
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@v7
# rust-toolchain.toml names the channel; `rustup show` installs it.
# Never override the toolchain here.
- name: Install the pinned toolchain
run: rustup show
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
- uses: Swatinem/rust-cache@v2
- name: Build
run: cargo build --workspace --all-targets
@@ -184,10 +181,10 @@ jobs:
if: needs.changes.outputs.rust == 'true'
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@v7
- name: Install the pinned toolchain
run: rustup show
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
- uses: Swatinem/rust-cache@v2
- run: cargo build --workspace --all-targets
- run: cargo test --workspace --no-fail-fast
@@ -197,9 +194,9 @@ jobs:
if: needs.changes.outputs.core == 'true'
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@v7
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@v7
with:
node-version: 24
- name: Exercise Windows launcher downloads and verification
@@ -216,15 +213,15 @@ jobs:
if: needs.changes.outputs.oracle == 'true' || needs.changes.outputs.rust == 'true'
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@v7
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@v7
with:
node-version: 24
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
@@ -234,7 +231,7 @@ jobs:
- name: Install the pinned toolchain
run: rustup show
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
- uses: Swatinem/rust-cache@v2
- name: Build the engine from source
run: cargo build --release -p impeccable
@@ -258,10 +255,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@v7
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@v7
with:
node-version: 24
@@ -294,15 +291,15 @@ jobs:
if: needs.changes.outputs.cli_remote_e2e == 'true'
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@v7
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@v7
with:
node-version: 24
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
@@ -314,7 +311,7 @@ jobs:
- name: Install the pinned toolchain
run: rustup show
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
- uses: Swatinem/rust-cache@v2
- name: Build the engine
run: cargo build --release -p impeccable
@@ -340,20 +337,20 @@ jobs:
fixtures: vite8-react-css-modules,vite8-react-insert,vite8-react-plain
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@v7
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@v7
with:
node-version: 24
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Cache fixture npm downloads
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
uses: actions/cache@v6
with:
path: ~/.npm
key: ${{ runner.os }}-fixture-npm-${{ hashFiles('tests/framework-fixtures/**/files/package.json') }}
@@ -361,7 +358,7 @@ jobs:
${{ runner.os }}-fixture-npm-
- name: Cache Playwright Chromium
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
uses: actions/cache@v6
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-chromium-${{ hashFiles('package.json', 'bun.lock') }}
@@ -379,7 +376,7 @@ jobs:
- name: Install the pinned toolchain
run: rustup show
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
- uses: Swatinem/rust-cache@v2
- name: Build the engine
run: cargo build --release -p impeccable
@@ -396,7 +393,7 @@ jobs:
- name: Upload live E2E failure artifacts
if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/upload-artifact@v7
with:
name: live-e2e-smoke-${{ matrix.group }}-artifacts
path: test-results/live-e2e
@@ -426,20 +423,20 @@ jobs:
fixtures: vite8-react-tailwindv3,vite8-react-tailwindv4,vite8-react-ts,vite8-react-tsx-repeated-aside,vite8-react-unocss,vite8-react-vanilla-extract
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@v7
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@v7
with:
node-version: 24
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Cache fixture npm downloads
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
uses: actions/cache@v6
with:
path: ~/.npm
key: ${{ runner.os }}-fixture-npm-${{ hashFiles('tests/framework-fixtures/**/files/package.json') }}
@@ -447,7 +444,7 @@ jobs:
${{ runner.os }}-fixture-npm-
- name: Cache Playwright Chromium
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
uses: actions/cache@v6
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-chromium-${{ hashFiles('package.json', 'bun.lock') }}
@@ -465,7 +462,7 @@ jobs:
- name: Install the pinned toolchain
run: rustup show
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
- uses: Swatinem/rust-cache@v2
- name: Build the engine
run: cargo build --release -p impeccable
@@ -481,7 +478,7 @@ jobs:
- name: Upload live E2E failure artifacts
if: failure()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
uses: actions/upload-artifact@v7
with:
name: live-e2e-full-${{ matrix.group }}-artifacts
path: test-results/live-e2e
@@ -502,23 +499,23 @@ jobs:
- name: Checkout repository
if: ${{ env.ANTHROPIC_API_KEY != '' || env.DEEPSEEK_API_KEY != '' }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@v7
- name: Setup Node
if: ${{ env.ANTHROPIC_API_KEY != '' || env.DEEPSEEK_API_KEY != '' }}
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@v7
with:
node-version: 24
- name: Setup Bun
if: ${{ env.ANTHROPIC_API_KEY != '' || env.DEEPSEEK_API_KEY != '' }}
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Cache fixture npm downloads
if: ${{ env.ANTHROPIC_API_KEY != '' || env.DEEPSEEK_API_KEY != '' }}
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
uses: actions/cache@v6
with:
path: ~/.npm
key: ${{ runner.os }}-fixture-npm-${{ hashFiles('tests/framework-fixtures/**/files/package.json') }}
@@ -527,7 +524,7 @@ jobs:
- name: Cache Playwright Chromium
if: ${{ env.ANTHROPIC_API_KEY != '' || env.DEEPSEEK_API_KEY != '' }}
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
uses: actions/cache@v6
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-chromium-${{ hashFiles('package.json', 'bun.lock') }}
@@ -548,7 +545,7 @@ jobs:
if: ${{ env.ANTHROPIC_API_KEY != '' || env.DEEPSEEK_API_KEY != '' }}
run: rustup show
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
- uses: Swatinem/rust-cache@v2
if: ${{ env.ANTHROPIC_API_KEY != '' || env.DEEPSEEK_API_KEY != '' }}
- name: Build the engine
@@ -579,23 +576,23 @@ jobs:
- name: Checkout repository
if: ${{ env.DEEPSEEK_API_KEY != '' }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@v7
- name: Setup Node
if: ${{ env.DEEPSEEK_API_KEY != '' }}
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@v7
with:
node-version: 24
- name: Setup Bun
if: ${{ env.DEEPSEEK_API_KEY != '' }}
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Cache fixture npm downloads
if: ${{ env.DEEPSEEK_API_KEY != '' }}
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
uses: actions/cache@v6
with:
path: ~/.npm
key: ${{ runner.os }}-fixture-npm-${{ hashFiles('tests/framework-fixtures/**/files/package.json') }}
@@ -604,7 +601,7 @@ jobs:
- name: Cache Playwright Chromium
if: ${{ env.DEEPSEEK_API_KEY != '' }}
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
uses: actions/cache@v6
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-chromium-${{ hashFiles('package.json', 'bun.lock') }}
@@ -625,7 +622,7 @@ jobs:
if: ${{ env.DEEPSEEK_API_KEY != '' }}
run: rustup show
- uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
- uses: Swatinem/rust-cache@v2
if: ${{ env.DEEPSEEK_API_KEY != '' }}
- name: Build the engine
@@ -646,15 +643,15 @@ jobs:
GOOGLE_CLOUD_API_KEY: ${{ secrets.GOOGLE_CLOUD_API_KEY }}
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@v7
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@v7
with:
node-version: 24
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
+2 -2
View File
@@ -48,10 +48,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@v7
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@v7
with:
node-version: 24
+3 -3
View File
@@ -49,7 +49,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
uses: actions/checkout@v7
with:
fetch-depth: 0
# Optional PAT or GitHub App token. With the default GITHUB_TOKEN,
@@ -57,12 +57,12 @@ jobs:
token: ${{ secrets.SYNC_GENERATED_OUTPUT_TOKEN || github.token }}
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
uses: actions/setup-node@v7
with:
node-version: 24
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
-2
View File
@@ -432,8 +432,6 @@ npx impeccable update
Live mode edits a local checkout through a development server or local static HTML. Injecting its localhost HTTP helper into a deployed production site, including an HTTPS site, is not supported. Do not disable browser security or weaken production CSP to make it work.
Use live mode only in projects you trust to run locally. Applying copy edits automatically runs `package.json`'s optional `scripts["impeccable:manual-edit-validate"]` command in a shell, with your user permissions; review that script before using live mode in an unfamiliar checkout.
For production inspection, use `npx impeccable detect https://example.com` or the browser extension. These inspect the rendered page; they do not provide live variant editing or write changes back to your source.
## CLI
-1
View File
@@ -52,7 +52,6 @@ export const SUITES = {
'tests/validate-plugin-manifest.test.js',
'tests/plugin-paths.test.js',
'tests/release-engine-workflow.test.js',
'tests/workflow-security.test.js',
],
},
{
-35
View File
@@ -1,35 +0,0 @@
import { describe, expect, test } from 'bun:test';
import { readFileSync, readdirSync } from 'node:fs';
const directory = new URL('../.github/workflows/', import.meta.url);
const workflows = Object.fromEntries(readdirSync(directory)
.filter(name => /\.ya?ml$/.test(name))
.map(name => [name, Bun.YAML.parse(readFileSync(new URL(name, directory), 'utf8'))]));
describe('workflow execution boundaries', () => {
test('repository actions are pinned to full commit SHAs', () => {
for (const [name, workflow] of Object.entries(workflows)) {
for (const [jobName, job] of Object.entries(workflow.jobs)) {
for (const step of job.steps || []) {
if (!step.uses || step.uses.startsWith('./')) continue;
expect(step.uses, `${name}: ${jobName}`).toMatch(/@[a-f0-9]{40}$/);
}
}
}
});
test('CI uses a read-only repository token without job-level escalation', () => {
const ci = workflows['ci.yml'];
expect(ci.permissions).toEqual({ contents: 'read' });
for (const job of Object.values(ci.jobs)) {
expect(job.permissions).toBeUndefined();
}
});
test('generated-output sync and sheriff retain their required write access', () => {
expect(workflows['sync-generated-output.yml'].permissions).toEqual({ contents: 'write' });
expect(workflows['sheriff.yml'].permissions).toEqual({
actions: 'read', checks: 'read', contents: 'read', issues: 'write', 'pull-requests': 'write',
});
});
});