Found by the #13448 dev seat (PR for hintCovers / unreachableReason) while censusing every dead hint in the fleet. ⛔ Unassigned; no priority or type label — triage's field.
The defect
maskSelfTests does not reach path literals written in a helper function that only the self-test calls, even when that helper sits below the file's own /* self-test */ banner. Measured on scripts/pm/release-rehearsal-clone.mjs at 4301f7846:
node -e "import('./scripts/pm/dispatch-gates.mjs').then(async m => {
const src = require('node:fs').readFileSync('scripts/pm/release-rehearsal-clone.mjs','utf8');
console.log(m.extractWatchHints(m.maskSelfTests(m.maskComments(src)), 'scripts/pm/release-rehearsal-clone.mjs'));
})"
[ 'scripts/pm/release-rehearsal-clone.mjs', '.changeset/*.md', '.changeset',
'.changeset/config.json', '.changeset/README.md',
'.changeset/one.md', <-- fixture
'.changeset/two.md' ] <-- fixture
.changeset/one.md and .changeset/two.md are written by the self-test's temporary-repo builder (writeFile(repo, '.changeset/one.md', ...), around lines 494-505). They are not paths the gate reads in this repo and never were.
Why it is worth a card and not a shrug
They land in the residue as DEAD literals, and the reason printed for them is:
'.changeset/one.md' — the tree stops at .changeset; the layout moved under it
'.changeset/two.md' — the tree stops at .changeset; the layout moved under it
That is the same false-cause register#13448 was filed for — a well-formed sentence naming a directory rename that never happened — arriving one layer up, at EXTRACTION rather than at the covering predicate. A reader triaging those two rows goes looking for a move of a fixture that only ever existed inside a temp dir.
⚠️#13448's repair does not touch this: those two are ordinary literals, judged by the collapse, and the collapse is the right form for them. From the tree alone "never existed" and "moved" are indistinguishable for a literal under a surviving prefix, which is exactly why the extraction is the place to stop it.
Relationship to #8478 — a residual, not a duplicate
#8478 (closed) is this class: "dispatch-gates watch hints are read from self-test fixtures and comments, so gates are printed as MATCHED for paths they never read". maskComments + maskSelfTests closed the two boundaries it named. This is a third boundary the masking does not cover: a fixture literal in a plain helper function that only the self-test calls. Re-opening #8478 or filing under it is fine if triage prefers.
Not folded into #13448's PR
The four-condition in-place exemption fails on the second: the correct fix is not mechanically pinned by existing evidence. At least three shapes are available and each has its own blast radius, so it is a decision:
- widen
maskSelfTests to mask everything below the self-test banner — fleet-wide extraction change, needs its own before/after hint census; - teach it to follow the call graph from the self-test entry — more precise, much larger;
- move the fixtures inside the self-test body, or spell them so the extractor drops them — cheapest, but only fixes this one gate and leaves the mechanism.
Dedup declaration
search_issues (MCP), one targeted query, semantic. ⚠️ The channel is proven live for this session: the same query returned #13448 itself, a known-must-hit control, so the result is a reading and not a false zero. REST GET /search/issues is 403 for this seat, so it could not be used as the second channel. Nearest neighbours examined: #8478 (closed, this class, different boundary — discussed above), #12299 / #12371 / #12470 (module-relative literal depth — a different extraction defect), #13448 (the covering predicate, this card's parent run). ⚠️ One semantic query only; a duplicate worded very differently would not have been seen.
Refs
Generated by Claude Code
Found by the #13448 dev seat (PR for
hintCovers/unreachableReason) while censusing every dead hint in the fleet. ⛔ Unassigned; no priority or type label — triage's field.The defect
maskSelfTestsdoes not reach path literals written in a helper function that only the self-test calls, even when that helper sits below the file's own/* self-test */ banner. Measured onscripts/pm/release-rehearsal-clone.mjsat4301f7846:.changeset/one.mdand.changeset/two.mdare written by the self-test's temporary-repo builder (writeFile(repo, '.changeset/one.md', ...), around lines 494-505). They are not paths the gate reads in this repo and never were.Why it is worth a card and not a shrug
They land in the residue as DEAD literals, and the reason printed for them is:
That is the same false-cause register#13448 was filed for — a well-formed sentence naming a directory rename that never happened — arriving one layer up, at EXTRACTION rather than at the covering predicate. A reader triaging those two rows goes looking for a move of a fixture that only ever existed inside a temp dir.
Relationship to #8478 — a residual, not a duplicate
#8478 (closed) is this class: "dispatch-gates watch hints are read from self-test fixtures and comments, so gates are printed as MATCHED for paths they never read".
maskComments+maskSelfTestsclosed the two boundaries it named. This is a third boundary the masking does not cover: a fixture literal in a plain helper function that only the self-test calls. Re-opening #8478 or filing under it is fine if triage prefers.Not folded into #13448's PR
The four-condition in-place exemption fails on the second: the correct fix is not mechanically pinned by existing evidence. At least three shapes are available and each has its own blast radius, so it is a decision:
maskSelfTeststo mask everything below the self-test banner — fleet-wide extraction change, needs its own before/after hint census;Dedup declaration
search_issues(MCP), one targeted query, semantic.GET /search/issuesis 403 for this seat, so it could not be used as the second channel. Nearest neighbours examined: #8478 (closed, this class, different boundary — discussed above), #12299 / #12371 / #12470 (module-relative literal depth — a different extraction defect), #13448 (the covering predicate, this card's parent run).Refs
scripts/pm/dispatch-gates.mjs—maskSelfTests,extractWatchHints,unreachableReasonscripts/pm/release-rehearsal-clone.mjslines ~494-505 — the live specimenhintCoversdoes not follow a final-segment basename glob, so.changeset/*.mdmeasures DEAD against ~400 tracked changesets — and the residue names a false reason for it #13448 — surfaced during its census; ⛔ not fixed there and ⛔ not blocked by itGenerated by Claude Code