Skip to content

fix(pm): declare the type-check ledger's root-program coupling so dispatch-gates can derive it (#8551) - #8603

Merged
hotlong merged 1 commit into
mainfrom
claude/issue-8551-coverage-coupling-hint
Aug 14, 2026
Merged

fix(pm): declare the type-check ledger's root-program coupling so dispatch-gates can derive it (#8551)#8603
hotlong merged 1 commit into
mainfrom
claude/issue-8551-coverage-coupling-hint

Conversation

@hotlong

Copy link
Copy Markdown
Contributor

Fixes#8551

scripts/check-type-check-coverage.mjs holds a root ledger entry for @objectstack/spec-monorepo recorded at 80 errors, of which scripts/check-test-typecheck.mts alone accounts for 29 — the root program has no types:["node"], so in that file every console. reference costs one TS2584 and every process. reference one TS2591. Editing that script moves a number this gate ratchets.

The coupling was written down all along, inside the ledger note's prose. extractWatchHints accepts a quoted literal only when the whole string is path-shaped, so a path named mid-sentence is discarded: the family scored silent — neither matched nor undetermined, and therefore printed nowhere at all — and a card editing that script was told no check family names its paths.

What changed

Direction B, per the seat ruling recorded on the card. Two files, no behavioural delta on any gate:

  1. scripts/check-type-check-coverage.mjs — the coupled path is hoisted into a module-body constant holding the bare path string, in the shape the existing extractor already reads. The ledger note references the constant instead of spelling the path inside its sentence; the 29-of-80 accounting keeps its meaning verbatim.
  2. scripts/pm/dispatch-gates.mjsself-test section only: a live pin, reading both real files, that a card editing that script derives check:type-check-coverage through the constant. A future deletion of the declaration reddens check:pm-dispatch-gates instead of going quietly SILENT again.

⛔ Direction A was declined by the ruling and is not attempted here: extractWatchHints' whole-literal rule, hintCovers and the masking are untouched, so the false-MATCHED direction the precision work removed stays closed. No gate is weakened anywhere.

Zero behavioural delta — measured, not asserted

  • The note string is byte-identical: 950 chars before and after, same sha256 prefix 80a7e1d9f4f3bb45, evaluated from both file versions with the constant in scope.
  • errors: 80 is untouched; no ledger number moves. The two edited files are .mjs and the root tsconfig.json sets no allowJs, so neither is in any tsc program at all.
  • check:type-check-coverage prints the same line before and after: 64/77 workspace packages type-checked (plus the root), 13 in the DEBT ledger (436 frozen raw errors), 1 exempt and 20 package(s) ... 867 files hidden ... 1533 frozen raw errors in TEST_DEBT.

Verification

Red baseline, re-measured live on origin/main @ 8c433a8 (three PRs after the card's own measurement):

$ node scripts/pm/dispatch-gates.mjs scripts/check-test-typecheck.mts
No check family names the given paths in its own source.

Via the script's own exported functions: 36 hints extracted, none naming the coupled script, classifyEntry verdict silent.

After:

$ node scripts/pm/dispatch-gates.mjs scripts/check-test-typecheck.mts
Local gates for this card (paste into the dispatch prompt):
- pnpm check:type-check-coverage [lint.yml] matched via scripts/check-test-typecheck.mts ⇢ 'scripts/check-test-typecheck.mts'
- pnpm check:type-check-debt [lint.yml] matched via scripts/check-test-typecheck.mts ⇢ 'scripts/check-test-typecheck.mts'

37 hints (+1, exactly the new constant; none lost), verdict matched, provenance the constant itself. check:type-check-debt rides along because it resolves to the same script — a real coupling the card's own gate list already named.

Reverse verification, direction predicted before running: removing the constant returns the derivation to SILENT, reddens exactly the two new cases, and leaves the coverage gate's numbers identical. All three confirmed — ✗ dispatch-gates self-test: 2 of 103 case(s) failed, and the coverage gate printed the same counts and exited 0. Restored from the commit (git checkout HEAD -- ...), tree clean, green again.

Gates run locally, all green:

gateresult
check:pm-dispatch-gates✓ dispatch-gates self-test: 103 cases pass (was 101; +2 new pins)
check:type-check-coverageOK — 64/77 ... 13 in the DEBT ledger (436 frozen raw errors), 1 exempt — identical before and after
check:type-check-debtrefused without the built closure, so the closure was built as lint.yml does (turbo run build --filter=./packages/* --filter=./packages/*/*, 70 tasks successful) — then OK — 33 ledger entr(ies) re-measured in 302.4s, 1969 raw tsc error(s) total, none above its recorded number / surplus: none — every entry sits exactly at its measurement
check:nul-bytesOK (scanned 7740 text file(s) ... no raw ASCII control bytes)
ESLintclean on both changed files

Re-derived against the actual diff (node scripts/pm/dispatch-gates.mjs scripts/check-type-check-coverage.mjs scripts/pm/dispatch-gates.mjs): check:pm-dispatch-gates, check:type-check-coverage, check:type-check-debt — the families the dispatch prompt named, and nothing further.

skip-changeset: this PR touches scripts/ only and releases nothing.


Generated by Claude Code

…patch-gates can derive it (#8551)
`scripts/check-type-check-coverage.mjs` holds a root ledger entry for
`@objectstack/spec-monorepo` recorded at 80 errors, of which
`scripts/check-test-typecheck.mts` alone accounts for 29 -- the root program has
no `types:["node"]`, so in that file every `console.` reference costs one TS2584
and every `process.` reference one TS2591. Editing it moves a number this gate
ratchets.
The coupling was written down all along, inside the ledger note's prose. Watch-
hint extraction accepts a quoted literal only when the WHOLE string is
path-shaped, so a path named mid-sentence is discarded: the family scored
`silent` -- neither matched nor undetermined, printed nowhere at all -- and a
card editing that script was told no check family names its paths.
Direction B, per the seat ruling on the card: hoist the path into a module-body
constant the existing extractor already reads, and have the note reference the
constant instead of spelling it inside a sentence. `extractWatchHints`'
whole-literal rule, `hintCovers` and the masking are untouched, so the
false-MATCHED direction the precision work removed stays closed.
Zero behavioural delta on the gate: the note string is byte-identical (950
chars, same sha256 prefix), `errors: 80` is untouched, and no ledger number
moves.
A live pin in dispatch-gates' own self-test holds the declaration: it reads both
real files and asserts a card editing that script derives
`check:type-check-coverage` through the constant, so deleting the constant
reddens `check:pm-dispatch-gates` instead of restoring the silence.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018WuTtyckQa1VcXwgd52JpN
@vercel

vercelBot commented Aug 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 14, 2026 1:05am

Request Review

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@hotlong@claude