Skip to content

fix(scripts): type-check-coverage stale-entry messages carry no card-ending keyword - #9898

Merged
os-justin merged 1 commit into
mainfrom
claude/issue-9598-type-check-coverage-closing-keyword
Sep 18, 2026
Merged

os-justin merged 1 commit into
mainfrom
claude/issue-9598-type-check-coverage-closing-keyword

Conversation

@os-justin

Copy link
Copy Markdown
Collaborator

Fixes #9598

Part 1 only. The maintainer's ruling on this card (batch #152 item 3, letter 1) authorised the two-site repair and refused Part 2: 「a new required gate is the human floor and the maintainer's standing direction is no further gate development」. This branch therefore adds no check:* entry point, no package.json script, no workflow, no hook and no ratchet. See What this pull request deliberately does not do below.

scripts/check-type-check-coverage.mjs emitted a GitHub closing keyword immediately before an interpolated issue anchor at both of its stale-entry ratchets — rule 2 (DEBT) and rule 6 (TEST_DEBT) — inside messages a contributor is told to quote into a pull-request body. Quoting one ends the anchor card silently, from a body whose author was being careful: GitHub's parser does no sentence parsing, so hedging the surrounding sentence buys nothing. The DEBT tail was a byte-identical twin of the one already replaced in scripts/check-lint-coverage.mjs.

Repaired onto the form already landed on the sibling gates (check-lint-coverage.mjs, check-action-forward-parity.mjs): the keyword becomes "can be ended", and the anchor is spelled objectui# rather than a bare #, so the reference cannot match the closing grammar at all. The instruction survives in full. A banner at each ratchet states the rule for whoever words the next entry.

⚠️ Anchors below are written unresolved, as ${debt[name].issue} / ${spec.issue}, exactly as the source carries them. The resolved form of the before text is deliberately not reproduced in this body — that form is the defect this pull request removes.

Both ledgers are empty, and that is why the shape survived

DEBT and TEST_DEBT are both {} in this tree, so neither message is reachable here. ⛔ Dormant is not fixed: each is one ledger entry away from rendering, and the entry that reopens it is written by exactly the person who will then need to quote the message. An empty ledger is why this class has now needed four one-at-a-time repairs (objectui#9535, objectui#9595, objectui#9597 and this one) rather than a reason to leave the fourth standing.

Instrument readings — and the two counting rules do NOT agree

Run on the file's whole text, before and after. PRIMARY is the collapsed instrument (\n escapes to spaces, string-chunk concatenation joined, physical wrapping flattened); CONTROL is the naive single-line match the card warns can under-count.

counting rule instrument before after
A — keyword immediately before an interpolated anchor (the card's and the dispatch order's rule) primary (collapsed) 2 0
A control (single-line) 2 0
B — the CLOSING_TRIGGER the four landed pins share byte-for-byte (interpolated or literal anchor, optional owner/repo / objectui / objectstack qualifier) primary (collapsed) 3 1
B control (single-line) 3 1

Two readings worth stating plainly:

  1. The concatenation trap is check-action-forward-parity.mjs's, not this file's. Primary and control agree at every cell. A third, looser probe — any keyword within 40 characters of any # in the collapsed text, which would catch a sentence split by variable concatenation — also returns 3 before, on the same three sites. There is no split emitter here.
  2. Rule B's residual 1 is NOT an emitter. It is prose in the TEST_DEBT table comment: the noun fix immediately before a bare objectstack-prefixed anchor (issue 4074) — a reference form GitHub does not resolve, in a source comment that reaches no rendered diagnostic. It matches the shape the landed pins' regex keeps out and nothing else. ⛔ Out of scope here and not touched: the ruling authorised two sites, and both are emitters. Recorded below and reported to the dispatching seat. This is the same class the objectui#9755 author recorded as "shape-only, lowest severity" rather than repairing.

Rendered before / after — both sites

Rendered by driving the real exported collect() + auditPackages() over throwaway package trees with a seeded ledger row, not by reading the template.

Site 1 — rule 2, stale DEBT entry

  • before: NAME now has a "type-check" script — delete its DEBT entry so the gap cannot reopen + ${debt[name].issue ? (and close #${debt[name].issue} if it is done) : ""}.
  • after: NAME now has a "type-check" script — delete its DEBT entry so the gap cannot reopen + ${debt[name].issue ? , and objectui#${debt[name].issue} can be ended once that work is done : ""}.

Site 2 — rule 6, stale TEST_DEBT entry

  • before: NAME type-checks its tests now — delete its TEST_DEBT entry so the gap cannot reopen + ${spec.issue ? (and close #${spec.issue} if the list is empty) : ""}.
  • after: NAME type-checks its tests now — delete its TEST_DEBT entry so the gap cannot reopen + ${spec.issue ? , and objectui#${spec.issue} can be ended once the list is empty : ""}.

The pin — one rendered leg per site, red before and green after

scripts/__tests__/check-type-check-coverage-closing-keyword.test.ts. This gate already exports collect(repoRoot) and auditPackages(packages, tables) — the audit takes its ledgers as a parameter — so each leg seeds a ledger row directly and asserts on the text the gate really produced. ⛔ No copy-the-gate-into-a-throwaway-workspace harness, the one objectui#9595's pin had to build.

Every leg carries a control that must fire: that the seeded ratchet is the one that reported (toHaveLength(1) plus a distinguishing phrase), and that the regex catches the pre-repair wording. Without them a ratchet that printed nothing and a regex that matches nothing read exactly like a clean message.

RED, against the pre-repair gate. The repaired file was replaced on disk with its pre-repair blob taken from the merge-base commit, the substitution proved by git hash-object against that commit's blob (f6747edd… on disk, matching), and the marker counts flipped (can be ended once 2 to 0, the pre-repair tail 0 to 2) before anything was run:

$ pnpm exec vitest run scripts/__tests__/check-type-check-coverage-closing-keyword.test.ts
 × …and the DEBT message the gate actually renders carries no trigger
 × …and the TEST_DEBT message the gate actually renders carries no trigger
 × …while both still tell the reader what to do with the anchor
 × both ratchet SOURCES carry no trigger either, comments included
 Test Files  1 failed (1)
      Tests  4 failed | 1 passed (5)
   vitest EXIT=1

The one passing leg is the control — it asserts the regex fires on the wording this card replaced, so it must be green in both states. Restoration was proved by state, not by an exit code: git checkout HEAD -- PATH (naming HEAD, never the bare form that would take the mutation back out of the index at exit 0), then the on-disk hash back to b47a3c40… and git diff HEAD empty.

GREEN, on this branch:

$ pnpm exec vitest run scripts/__tests__/check-type-check-coverage-closing-keyword.test.ts
 Test Files  1 passed (1)
      Tests  5 passed (5)

Verification

Run as a contributor runs them, with no flag that narrows what is reported.

command verdict
pnpm lint:root (the root-level eslint that covers scripts/; ⛔ no --no-inline-config, no narrowing flag) exit 0 — 0 errors, 32 warnings, none in either changed file
pnpm type-check:scripts (tsc -p tsconfig.scripts.json) exit 0
pnpm type-check:coverage (this gate, on the real tree) exit 0, both green lines printed
pnpm exec vitest run scripts/ (the whole affected suite) exit 0 — 174 passed, 2 skipped
pnpm check:control-bytes · check:new-line-citations · check:test-path-roots · check:vi-mock-specifiers · check:entry-guard exit 0 each
node scripts/check-changeset-presence.mjs exit 0 — "No source or published contract of a released package changed in this range, so no changeset is owed"
node scripts/check-governed-queue-guard.mjs --test on both paths NOT GOVERNED

⚠️ pnpm type-check:scripts's coverage of the new pin is measured, not assumed: tsc -p tsconfig.scripts.json --listFiles lists the new test file (1 hit), with an already-covered sibling pin as the positive control (1 hit).

No changeset. The gate's own criterion says none is owed — scripts/ is not published source of a released package — and objectui#9755, the byte-identical repair on the sibling gate, landed with the same two-file shape and no changeset.

What this pull request deliberately does not do

  • ⛔ Part 2 is not built. No differential emitter gate, no new check:* script, no package.json script registration, no workflow, no hook, no ratchet of any kind. The diff is exactly two files.
  • ⛔ The ${X.issue ? … : ""} truthiness guard is not touched. objectui#9596 is about that shape going silently falsy; there X is a module-level anchor constant with its own pin, here it is a per-entry field on a ledger row. Different question, different card, no assertions added about it.
  • ⛔ No sibling gate was edited. One thing worth the reviewer's eye, recorded rather than acted on: the banner comment beside the DEBT ratchet in scripts/check-lint-coverage.mjs states in the present tense that the same shape still stands in check-type-check-coverage.mjs and check-action-forward-parity.mjs. objectui#9755 already falsified half of that sentence and this branch falsifies the other half. It is readable as a historical note about that pull request, so it is left for the dispatching seat to judge rather than reshaped here.

Acceptance notes

  • Noted, not filed — rule B's residual hit, the noun fix before a bare objectstack-prefixed anchor in the TEST_DEBT table comment. Non-resolvable reference form, source comment, no rendered diagnostic. Successor who would meet it: whoever next edits that ledger's prose.
  • Noted, not filed — the stale present-tense cross-file claim in check-lint-coverage.mjs described above. Successor: the next reader of that gate's banner, or whoever lands the fifth repair in this class.
  • The dispatch order quotes site 2's source line with two spaces before the ?; the tree has one. Transcription only, no bearing on the repair.

🤖 Generated with Claude Code

https://claude.ai/code/session_012EpHzwH4wTy5sd7ibkD2yq


Generated by Claude Code

…ending keyword

`scripts/check-type-check-coverage.mjs` emitted a GitHub closing keyword
immediately before an interpolated issue anchor at BOTH of its stale-entry
ratchets — rule 2 (`DEBT`) and rule 6 (`TEST_DEBT`) — inside messages a
contributor is told to quote into a pull-request body. Quoting one ends the
anchor card silently, from a body whose author was being careful: GitHub's
parser does no sentence parsing, so hedging the surrounding sentence buys
nothing. The `DEBT` tail was a byte-identical twin of the one already replaced
in `scripts/check-lint-coverage.mjs`.

Repaired onto the form already landed on the sibling gates
(`check-lint-coverage.mjs`, `check-action-forward-parity.mjs`): the keyword
becomes "can be ended", and the anchor is spelled `objectui#` rather than a bare
`#`, so the reference cannot match the closing grammar at all. The instruction
survives in full. A banner at each ratchet states the rule for whoever words the
next entry.

Both ledgers are empty, so neither message is reachable in this tree — which is
why the shape survived, not a reason to leave it: each is one ledger entry away
from rendering, and the entry that reopens it is written by whoever will need to
quote the message.

`scripts/__tests__/check-type-check-coverage-closing-keyword.test.ts` is the
pin, one rendered leg per site. It drives the exported `collect()` +
`auditPackages()` over throwaway package trees with a seeded ledger row and
asserts on the text the gate really produced — this gate takes its tables as a
parameter, so no copy-the-gate-into-a-workspace harness is needed. Every leg
carries a control that must fire: that the seeded ratchet is the one that
reported, and that the regex catches the pre-repair wording.

Anchors in the source are written unresolved, as `${debt[name].issue}` and
`${spec.issue}`, exactly as the file carries them.

Part of objectui#9598 — Part 1 only. The card's Part 2 (a differential emitter
gate over everything `scripts/` prints) is NOT built here: the maintainer ruled
a new required gate is the human floor and stands by no further gate
development, so this branch adds no `check:*` entry point, no package.json
script, no workflow and no ratchet.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EpHzwH4wTy5sd7ibkD2yq
@github-actions github-actions Bot added the tests label Sep 18, 2026
@os-justin
os-justin marked this pull request as ready for review September 18, 2026 14:29
@os-justin
os-justin added this pull request to the merge queue Sep 18, 2026
Merged via the queue into main with commit fb7dfed Sep 18, 2026
35 checks passed
@os-justin
os-justin deleted the claude/issue-9598-type-check-coverage-closing-keyword branch September 18, 2026 15:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

2 participants