Found while implementing #8509 (the identity-key derivation), measured rather than reasoned. Out of that card's scope — a different function, and a different key.
The observation
hintCovers in scripts/pm/dispatch-gates.mjs decides coverage with raw string prefixes in both directions:
returninputPath.startsWith(plain)||plain.startsWith(inputPath);
A path prefix is not a string prefix. packages/client is a string prefix of packages/client-react/src/index.ts, so a gate whose source names the first would be printed in the MATCHED column for a card that only touches the second:
hintCovers('packages/client', 'packages/client-react/src/x.ts') -> true
hintCovers('packages/spec', 'packages/spec-extra/x.ts') -> true
Both sibling pairs are real directory names in this tree (packages/client / packages/client-react). The MATCHED column is what a dispatch prompt pastes, and a fabricated lead there is indistinguishable from a real one to the dev who runs it — the same cost argument #8478 was decided on, one function further down the chain.
The neighbouring predicate already draws the boundary correctly and has a pinned case for exactly this: isInI18nBundlePackage tests path === dir || path.startsWith(dir + '/'), with the self-test case a sibling sharing a name prefix does not. hintCovers is the one place in the file that does not.
Measured — the rule is live, its exercise today is not
Probed across the full live hint population on a6231c7: 324 distinct hints against 73 package directories, asking "does this hint cover a package it does not name, other than as a genuine parent directory?"
live sibling-prefix false coverages: 0
So this is dormant, not firing. What saves it today is incidental: nearly every package-scoped hint carries a subdirectory (packages/client/src/** collapses to packages/client/src, which does not prefix packages/client-react/…). A hint that happens to stop at the package boundary — one new URL('../../packages/client', …), one glob written packages/client* — starts fabricating leads with nothing else changing, and nothing would report it.
Filing it while it is cheap and provable, since the failure mode is silent by construction.
Direction (not a recommendation)
Compare on segment boundaries in both directions — a === b || a.startsWith(b + '/') || b.startsWith(a + '/') — which preserves every case the current self-test pins (hint covers deeper path, collapsed glob prefix covers, input dir covers hint below it) while dropping the sibling case. Worth pinning in both directions, since the glob collapsing means packages/client* legitimately should reach the sibling and the trailing-slash rule would stop it; that trade needs deciding, not assuming.
Related, same neighbourhood, smaller
extractWatchHints accepts a trailing . as part of a hint. scripts/check-skill-compatibility-version.mjs carries a backticked span ending a sentence at line 295, and it becomes the hint scripts/check-skill-compatibility-version.mjs. — visible in the tool's own output before #8509 landed, where the provenance column read ...-version.mjs. with the period. It is currently harmless (the bidirectional prefix still reaches the real file), so it is noted here as a second specimen of "the hint is not quite the path", not as a separate card.
Related
Generated by Claude Code
Found while implementing #8509 (the identity-key derivation), measured rather than reasoned. Out of that card's scope — a different function, and a different key.
The observation
hintCoversinscripts/pm/dispatch-gates.mjsdecides coverage with raw string prefixes in both directions:A path prefix is not a string prefix.
packages/clientis a string prefix ofpackages/client-react/src/index.ts, so a gate whose source names the first would be printed in the MATCHED column for a card that only touches the second:Both sibling pairs are real directory names in this tree (
packages/client/packages/client-react). The MATCHED column is what a dispatch prompt pastes, and a fabricated lead there is indistinguishable from a real one to the dev who runs it — the same cost argument #8478 was decided on, one function further down the chain.The neighbouring predicate already draws the boundary correctly and has a pinned case for exactly this:
isInI18nBundlePackagetestspath === dir || path.startsWith(dir + '/'), with the self-test casea sibling sharing a name prefix does not.hintCoversis the one place in the file that does not.Measured — the rule is live, its exercise today is not
Probed across the full live hint population on
a6231c7: 324 distinct hints against 73 package directories, asking "does this hint cover a package it does not name, other than as a genuine parent directory?"So this is dormant, not firing. What saves it today is incidental: nearly every package-scoped hint carries a subdirectory (
packages/client/src/**collapses topackages/client/src, which does not prefixpackages/client-react/…). A hint that happens to stop at the package boundary — onenew URL('../../packages/client', …), one glob writtenpackages/client*— starts fabricating leads with nothing else changing, and nothing would report it.Filing it while it is cheap and provable, since the failure mode is silent by construction.
Direction (not a recommendation)
Compare on segment boundaries in both directions —
a === b || a.startsWith(b + '/') || b.startsWith(a + '/')— which preserves every case the current self-test pins (hint covers deeper path,collapsed glob prefix covers,input dir covers hint below it) while dropping the sibling case. Worth pinning in both directions, since the glob collapsing meanspackages/client*legitimately should reach the sibling and the trailing-slash rule would stop it; that trade needs deciding, not assuming.Related, same neighbourhood, smaller
extractWatchHintsaccepts a trailing.as part of a hint.scripts/check-skill-compatibility-version.mjscarries a backticked span ending a sentence at line 295, and it becomes the hintscripts/check-skill-compatibility-version.mjs.— visible in the tool's own output before #8509 landed, where the provenance column read...-version.mjs.with the period. It is currently harmless (the bidirectional prefix still reaches the real file), so it is noted here as a second specimen of "the hint is not quite the path", not as a separate card.Related
entry.filesas match keys routed through this samehintCovers; it inherits this rule rather than changing it.Generated by Claude Code