Found while working #10533, whose entire diff is one file under scripts/.
node scripts/pm/dispatch-gates.mjs did not name check:parse-guard in the local gate list, even
though that gate's population is exactly the directory the card edits. It appears instead under
Unreachable BY CONSTRUCTION:
3 unreachable BY CONSTRUCTION — the literal is not a path this derivation can reach,
and no change to the gate or the tree makes it one:
- pnpm check:parse-guard [lint.yml] dead: 'scripts' — the tree HAS it;
the covering rule refuses the literal as too generic (no path separator)
The gate is real and it read my file: run directly it reports
✓ check:parse-guard: 125 scripts/ file(s) — every TypeScript parse goes through ts-parse.mjs.
EXIT=0
The mechanism
hintCovers refuses a bare single-segment literal as too generic by design — that refusal is
measured, and scripts/check-role-word.mjs carries the measurement in its own header (teaching the
extractor to accept bare top-level directory words was priced at +139084 fabricated (gate, file)
pairs). So the refusal is correct; what is missing is the escape hatch.
scripts/check-parse-guard.mjs spells its population as scripts/** in prose throughout its
header, but the only string literal the extractor can reach is the bare 'scripts' on line 267:
returnn==='*'||n.startsWith('**')||n==='scripts'||n.startsWith('scripts/');Why this is the same class the repo has already solved once
check-role-word.mjs hit exactly this for its skills root, paid for it as a repair round on
PR #10038 (a skills-only docs fix that derived a green local union and met the gate as red CI),
and closed it with a declaration rather than a wider extractor:
constROOT_DIR_WATCH_HINTS=['skills/**'];
with a self-test pinning both halves (every separator-less ROOT is declared; nothing declared is
itself a ROOTS entry). The same three lines would make check:parse-guard reachable for every
scripts/ card. Note the tension worth resolving in the same pass: the derivation prints
"no change to the gate or the tree makes it one", while its own residue text documents the escape
("a gate whose population really is a root file reaches it by declaring the subtree spelling").
One of those two sentences is wrong for this case.
Impact
Every card whose diff is scripts/** — a large share of gate/tooling work — gets a brief with this
gate missing, and CI enforces it anyway (lint.yml carries no path filter). The cost is a repair
round, paid by whoever happens to trip it.
Related, not duplicate
#10784 reports the same symptom for check:entry-guard and the same directory, but a different
mechanism (its population is an enumeration of the files that already exist, so a NEW file can never
appear in it). This one is a bare too-generic literal. Merge them if triage prefers one card for
"dispatch-gates blind spots over scripts/".
Not fixed in #10533's PR: different gate, different family, and it would widen a gate-semantics diff
past what its own card can be reviewed against.
Generated by Claude Code
Generated by Claude Code
Found while working #10533, whose entire diff is one file under
scripts/.node scripts/pm/dispatch-gates.mjsdid not namecheck:parse-guardin the local gate list, eventhough that gate's population is exactly the directory the card edits. It appears instead under
Unreachable BY CONSTRUCTION:
The gate is real and it read my file: run directly it reports
The mechanism
hintCoversrefuses a bare single-segment literal as too generic by design — that refusal ismeasured, and
scripts/check-role-word.mjscarries the measurement in its own header (teaching theextractor to accept bare top-level directory words was priced at +139084 fabricated (gate, file)
pairs). So the refusal is correct; what is missing is the escape hatch.
scripts/check-parse-guard.mjsspells its population asscripts/**in prose throughout itsheader, but the only string literal the extractor can reach is the bare
'scripts'on line 267:Why this is the same class the repo has already solved once
check-role-word.mjshit exactly this for itsskillsroot, paid for it as a repair round onPR #10038 (a skills-only docs fix that derived a green local union and met the gate as red CI),
and closed it with a declaration rather than a wider extractor:
with a self-test pinning both halves (every separator-less ROOT is declared; nothing declared is
itself a ROOTS entry). The same three lines would make
check:parse-guardreachable for everyscripts/card. Note the tension worth resolving in the same pass: the derivation prints"no change to the gate or the tree makes it one", while its own residue text documents the escape
("a gate whose population really is a root file reaches it by declaring the subtree spelling").
One of those two sentences is wrong for this case.
Impact
Every card whose diff is
scripts/**— a large share of gate/tooling work — gets a brief with thisgate missing, and CI enforces it anyway (
lint.ymlcarries no path filter). The cost is a repairround, paid by whoever happens to trip it.
Related, not duplicate
#10784 reports the same symptom for
check:entry-guardand the same directory, but a differentmechanism (its population is an enumeration of the files that already exist, so a NEW file can never
appear in it). This one is a bare too-generic literal. Merge them if triage prefers one card for
"dispatch-gates blind spots over
scripts/".Not fixed in #10533's PR: different gate, different family, and it would widen a gate-semantics diff
past what its own card can be reviewed against.
Generated by Claude Code
Generated by Claude Code