Observation only, no defect in the gate's verdicts — the message it prints alongside a correct verdict is what misleads. Found while acting on #11204 (PR #11489). Filed unassigned; searched open issues first and found none.
The message
scripts/check-type-check-coverage.mjs prints this for every graduation candidate:
ℹ <pkg>: TEST_DEBT records N, and tsc now reports 0 -- graduation candidate. Onboard it (add "typecheck": "tsc --noEmit", or drop the test exclusion, and delete the ledger entry in the same PR).
Two remedies, joined by "or", with nothing saying they can differ. On @objectstack/trigger-record-change both halves were wrong, in opposite directions:
The first was already done. The package has carried "typecheck": "tsc --noEmit" for its whole life. That branch describes DEBT's hole ("src does not check"); the package was in TEST_DEBT's ("src checks, tests are hidden"). The gate's own header states that distinction three screens above the message — the message just does not carry it. A taker following the message adds a script that is already there, or concludes the reading is wrong.
The second reds main. Dropping **/*.test.ts from the build tsconfig resolves exactly the 10-file program the re-measure scored at 0 (tsc --showConfig) and leaves dist/ byte-identical, so the two obvious checks both pass. It still fails, one gate over: the re-admitted tests import four workspace packages the build config's program never held, and check:type-source-resolution goes exit 0 → exit 1 naming all four, against a shrink-only registry whose own message rules that widening the entry is not the remedy.
Nothing in either gate's output connects those two facts. The failure only appears if you run a gate the graduation message never mentions.
Why the "or" is load-bearing
The two remedies are equivalent exactly when the excluded tests import nothing the src layer does not — a per-package property, cheap to measure and impossible to know from the message. Where they differ, the second one is the attractive-looking option: it is one line, it deletes a config rather than adding one, and Zone-3-style advice ("prefer the remedy that puts more code under tsc") points straight at it.
There are 19 packages still hiding their tests, so this message has 19 more chances to be read.
Shape of a fix (not prescribing)
Cheap version: make the message branch on what the gate already knows — it computes scripts.typecheck and the hidden-test list on every run, so "add a typecheck script" can simply not print for a package that has one. Fuller version: name check:type-source-resolution in the drop-the-exclusion branch, since that is the gate that decides whether the branch is available.
Whatever the shape, the message is pinned by --self-test cases, so this is a real edit rather than a string tweak.
Generated by Claude Code
Observation only, no defect in the gate's verdicts — the message it prints alongside a correct verdict is what misleads. Found while acting on #11204 (PR #11489). Filed unassigned; searched open issues first and found none.
The message
scripts/check-type-check-coverage.mjsprints this for every graduation candidate:Two remedies, joined by "or", with nothing saying they can differ. On
@objectstack/trigger-record-changeboth halves were wrong, in opposite directions:The first was already done. The package has carried
"typecheck": "tsc --noEmit"for its whole life. That branch describes DEBT's hole ("src does not check"); the package was in TEST_DEBT's ("src checks, tests are hidden"). The gate's own header states that distinction three screens above the message — the message just does not carry it. A taker following the message adds a script that is already there, or concludes the reading is wrong.The second reds
main. Dropping**/*.test.tsfrom the build tsconfig resolves exactly the 10-file program the re-measure scored at 0 (tsc --showConfig) and leavesdist/byte-identical, so the two obvious checks both pass. It still fails, one gate over: the re-admitted tests import four workspace packages the build config's program never held, andcheck:type-source-resolutiongoes exit 0 → exit 1 naming all four, against a shrink-only registry whose own message rules that widening the entry is not the remedy.Nothing in either gate's output connects those two facts. The failure only appears if you run a gate the graduation message never mentions.
Why the "or" is load-bearing
The two remedies are equivalent exactly when the excluded tests import nothing the src layer does not — a per-package property, cheap to measure and impossible to know from the message. Where they differ, the second one is the attractive-looking option: it is one line, it deletes a config rather than adding one, and Zone-3-style advice ("prefer the remedy that puts more code under tsc") points straight at it.
There are 19 packages still hiding their tests, so this message has 19 more chances to be read.
Shape of a fix (not prescribing)
Cheap version: make the message branch on what the gate already knows — it computes
scripts.typecheckand the hidden-test list on every run, so "add atypecheckscript" can simply not print for a package that has one. Fuller version: namecheck:type-source-resolutionin the drop-the-exclusion branch, since that is the gate that decides whether the branch is available.Whatever the shape, the message is pinned by
--self-testcases, so this is a real edit rather than a string tweak.Generated by Claude Code