Filed by the dev seat implementing #8519 (PR to follow). Unassigned and unlabeled for triage. Same surface as #8519: the gate farm / developer ergonomics.
⚠️ No gate is asked to be weakened. The gate is correct. This is about which remedy its output teaches, exactly as #8435 and #8519 framed it.
The finding
#8519's census reported five live instances of the #8435 shape. Re-running that census from a clean worktree cut from origin/main reproduces all five — and finds a sixth:
scripts/check-test-typecheck.mts:147
`${file}: ${count} type error(s) in a file the ledger does not cover. Fix them — this file is
inside the checked zone, which is the point of ${PROJECT}. (A deleted `@ts-expect-error`
shows up exactly here, as TS2578/TS2694.) Only with a reason: add the file to ${LEDGER_NAME}.`
LEDGER_NAME is the per-package test-typecheck-debt.json. It is unambiguously a shrink-only debt ratchet, and this script says so itself in two places:
- its own
LEDGER_COMMENT (line 104): "EXACT ratchet, judged by re-running tsc: a file that gains errors is red, a file that loses them is red until its number is re-recorded, a file that reaches zero is red until its entry is deleted";
- its own sibling message 12 lines below: "the ledger only ratchets down".
AGENTS.md calls the same file "the per-file, shrink-only <package>/test-typecheck-debt.json".
So Only with a reason: add the file to test-typecheck-debt.json is the co-equal weakening remedy, unmarked — precisely the #8435 shape.
Why the census missed it — a mechanism, not an oversight
#8519's sweep is stated on the card as covering "all 76 scripts/*.mjs". That count is exactly right and reproduces today. But scripts/ also holds two .mts files, which a *.mjs glob cannot reach:
$ ls scripts/*.mjs | wc -l -> 76
$ ls scripts/*.mts | wc -l -> 2
check-test-typecheck.mts is one of them. The miss is structural in the sweep's file filter, so any future census of this convention should glob scripts/*.{mjs,mts} — otherwise it will keep reporting a complete count that is short by whatever lives in the two .mts files.
Other instance kinds this gate has, deliberately NOT counted
For the same reason #8519 listed its exclusions — so a future sweep does not re-litigate them:
check-test-typecheck.mts:160 — "the debt SHRANK, which is the goal. Re-record it so the number stays true". Ratchet down; squarely the author's job.
check-test-typecheck.mts:175 — "it GRADUATED … Delete its entry". Ratchet tightening; the author's job.
Only the line-147 message expands the ledger.
Two borderline cases, recorded rather than counted
Both are exemption maps whose entries bless a violation rather than declare a legal answer, which is closer to the ratchet shape than to the declaration registries #8519 excluded. Neither is mechanically shrink-only (no count, no ratchet direction), and both are documented as Object.create(null) "empty by design", so calling them instances would be a judgment call rather than a measurement. Recording them so triage can rule, not folding them into the count:
scripts/check-meta-type-normalized.mjs:271 — "If a site genuinely must read the raw spelling, add it to EXEMPT".
scripts/check-tenant-chokepoint.mjs:544 — "If a door genuinely must build unscoped, add it to EXEMPT". Note this one blesses a read door that returns other tenants' data, so if any exemption map deserves the marker it is this.
Confirmed not instances on re-measurement (they refuse the weakening remedy outright, which is the stronger check-driver-memory-census.mjs precedent, or offer only the tightening direction): check-query-options-erasure-ratchet.mjs ("The grandfather list is not a mute button"), check-slot-lookup-ratchet.mjs ("the baseline never grows"), check-i18n-coverage.mjs (--update offered only for ratchet-down), check-startup-registry-verdict.mjs and check-durability-degradation.baseline.json's own path (stale-entry deletion only), check-osv-exemptions.mjs. Confirmed declaration registries, entry is the correct fix: check-error-code-casing.mjs EXEMPT_FILES, check-single-authz-resolver.mjs ALLOW, check-skill-compatibility-version.mjs EXEMPT.
Suggested shape (not decided here)
The same copyable block the other five now carry: the greppable ⛔ MAINTAINER-ONLY token on the ledger-expanding line, a detector regex, a pure ratchetRemedyCarriesAuthority() predicate, and non-overlapping self-test assertions. One wrinkle specific to this file: it is TypeScript, run through a different harness than the .mjs gates, so where its self-test assertions live needs checking rather than assuming.
Related: #8435 (established the convention), PR #8517 (covered 2), #8519 (covers 3). #8519 is not addressed here and remains open on its own three gates.
Generated by Claude Code
Filed by the dev seat implementing #8519 (PR to follow). Unassigned and unlabeled for triage. Same surface as #8519: the gate farm / developer ergonomics.
The finding
#8519's census reported five live instances of the #8435 shape. Re-running that census from a clean worktree cut from
origin/mainreproduces all five — and finds a sixth:scripts/check-test-typecheck.mts:147LEDGER_NAMEis the per-packagetest-typecheck-debt.json. It is unambiguously a shrink-only debt ratchet, and this script says so itself in two places:LEDGER_COMMENT(line 104): "EXACT ratchet, judged by re-running tsc: a file that gains errors is red, a file that loses them is red until its number is re-recorded, a file that reaches zero is red until its entry is deleted";AGENTS.md calls the same file "the per-file, shrink-only
<package>/test-typecheck-debt.json".So
Only with a reason: add the file to test-typecheck-debt.jsonis the co-equal weakening remedy, unmarked — precisely the #8435 shape.Why the census missed it — a mechanism, not an oversight
#8519's sweep is stated on the card as covering "all 76
scripts/*.mjs". That count is exactly right and reproduces today. Butscripts/also holds two.mtsfiles, which a*.mjsglob cannot reach:check-test-typecheck.mtsis one of them. The miss is structural in the sweep's file filter, so any future census of this convention should globscripts/*.{mjs,mts}— otherwise it will keep reporting a complete count that is short by whatever lives in the two.mtsfiles.Other instance kinds this gate has, deliberately NOT counted
For the same reason #8519 listed its exclusions — so a future sweep does not re-litigate them:
check-test-typecheck.mts:160— "the debt SHRANK, which is the goal. Re-record it so the number stays true". Ratchet down; squarely the author's job.check-test-typecheck.mts:175— "it GRADUATED … Delete its entry". Ratchet tightening; the author's job.Only the line-147 message expands the ledger.
Two borderline cases, recorded rather than counted
Both are exemption maps whose entries bless a violation rather than declare a legal answer, which is closer to the ratchet shape than to the declaration registries #8519 excluded. Neither is mechanically shrink-only (no count, no ratchet direction), and both are documented as
Object.create(null)"empty by design", so calling them instances would be a judgment call rather than a measurement. Recording them so triage can rule, not folding them into the count:scripts/check-meta-type-normalized.mjs:271— "If a site genuinely must read the raw spelling, add it to EXEMPT".scripts/check-tenant-chokepoint.mjs:544— "If a door genuinely must build unscoped, add it to EXEMPT". Note this one blesses a read door that returns other tenants' data, so if any exemption map deserves the marker it is this.Confirmed not instances on re-measurement (they refuse the weakening remedy outright, which is the stronger
check-driver-memory-census.mjsprecedent, or offer only the tightening direction):check-query-options-erasure-ratchet.mjs("The grandfather list is not a mute button"),check-slot-lookup-ratchet.mjs("the baseline never grows"),check-i18n-coverage.mjs(--updateoffered only for ratchet-down),check-startup-registry-verdict.mjsandcheck-durability-degradation.baseline.json's own path (stale-entry deletion only),check-osv-exemptions.mjs. Confirmed declaration registries, entry is the correct fix:check-error-code-casing.mjsEXEMPT_FILES,check-single-authz-resolver.mjsALLOW,check-skill-compatibility-version.mjsEXEMPT.Suggested shape (not decided here)
The same copyable block the other five now carry: the greppable
⛔ MAINTAINER-ONLYtoken on the ledger-expanding line, a detector regex, a pureratchetRemedyCarriesAuthority()predicate, and non-overlapping self-test assertions. One wrinkle specific to this file: it is TypeScript, run through a different harness than the.mjsgates, so where its self-test assertions live needs checking rather than assuming.Related: #8435 (established the convention), PR #8517 (covered 2), #8519 (covers 3). #8519 is not addressed here and remains open on its own three gates.
Generated by Claude Code