test(gates): the snapshot holds a config per scope, not a path per file

gates.snapshot.json listed ~800 file paths under their config, so every
new or deleted frontend file regenerated it (31% of commits, E34 S2) and
the regen diff buried the gate changes it exists to show. Now a scope is
named by path (scopeOf: src, src tests, ui, lib tests, …), the snapshot
holds one effective config per scope (2345 → 1456 lines), and a new test
fails when a file's config is not its scope's.

Not narrowed: a new file in a known place changes nothing (it gets its
scope's config, checked), a glob that moves one file into another config
fails (seen: an override on Feed.tsx → "src: src/components/Feed.tsx"), a
scope whose rules change is a snapshot diff, and a file no config lints
is still a register miss.
This commit is contained in:
2026-10-05 00:19:39 +02:00
parent f2fe0fc0df
commit a42f346a32
4 changed files with 1341 additions and 2120 deletions
+8 -6
View File
@@ -13,16 +13,18 @@ name its invariant. Whatever is left narrowed is listed here, and
**effective** configuration and fails when a narrowing is not on this page. A row here is a decision,
not an oversight; a narrowing missing from here is a test failure.
**The snapshot.** ESLint's effective config for every code file `eslint .` reaches, and the lines
that run the lanes (`scripts/check.sh`, `backend/docker-compose.test.yml`,
**The snapshot.** ESLint's effective config for every scope `eslint .` reaches, and the lines that
run the lanes (`scripts/check.sh`, `backend/docker-compose.test.yml`,
`backend/Dockerfile.test`, the npm scripts, `vitest.config.ts`, `.prettierignore`), are committed in
[`frontend/src/lib/gates.snapshot.json`](../frontend/src/lib/gates.snapshot.json). The test fails on
ANY difference — a rule, an option, a glob that moves one file to another config, a new ignore, a gate
flag. So a change to a gate is always a diff of that file in review, never a shape a detector failed
ANY difference — a rule, an option, a new ignore, a gate flag. A scope is named by path (`scopeOf` in
the test: `src`, `src tests`, `ui`, …) and every file in it must get the same config, so a glob that
moves one file into another config fails too, while a new file in a known place changes nothing
(until E35 the snapshot listed every file, and 31% of commits regenerated it). So a change to a gate is always a diff of that file in review, never a shape a detector failed
to model (E32 review: three rounds of a cleverer detector each found a bypass of the last one's
fixes). Regenerate it with `GATE_SNAPSHOT=update npx vitest run src/lib/gates.contract.test.ts`
(from `frontend/`), and read its diff as a gate change: a new file only adds its path; anything else
needs a reason. A new code file is part of that diff by design.
(from `frontend/`), and read its diff as a gate change. A new kind of file (a new config, a new place)
needs a line in `scopeOf`.
**How the register is matched:** each narrowing must appear in a table row below as its
`code-quoted` id, in a row whose **Scope** cell names the scope exactly as the test reports it (a cell