Skip to content

[finding] ** in a hint does not match ZERO segments — scripts/**/*.d.mts names 3 tracked files and reaches 0, a dead hint by construction that #12300's new branch introduced #12329

Description

@yinlianghui

Measured while fixing #12289. ⛔ Not fixed there — that card's declared surface is scripts/pm/bare-root-worklist.mjs, and this lives in scripts/pm/dispatch-gates.mjs. Filed unassigned, not graded.

Measured on a6b6e54a26, driving the real hintCovers.

The shape

#12300 routed a glob in a non-final segment through triggerCovers instead of the collapse. In that matcher, ** matches one or more path segments, never zero:

hintCovers('scripts/**/*.d.mts', 'scripts/pm/x.d.mts') -> true (one segment)
hintCovers('scripts/**/*.d.mts', 'scripts/invoked-as.d.mts') -> false (zero segments)
hintCovers('packages/**/*.ts', 'packages/x.ts') -> false (zero segments)

Conventional glob semantics — and the reading a hint author will assume — is that a/**/b matches a/b. The three tracked files scripts/**/*.d.mts is the natural spelling for sit at the top level of the root:

scripts/check-regen-pending.d.mts
scripts/invoked-as.d.mts
scripts/js-comment-mask.d.mts

So the hint names three files and reaches none of them. That is the same failure mode #12246 was filed for — a hint that matches nothing BY CONSTRUCTION while looking like an ordinary literal — arriving through the branch that fixed it, for a different reason.

The other spelling is dead too, by the older route: scripts/*.d.mts is a final-segment glob, so it still goes through collapseHint, which yields scripts/.d.mts and matches 0.

Why it is worth a row

The hintCovers docblock prices a fabricated lead above a missing one, and a dead hint is worse than both: unreachableClass classifies a dead hint whose deepest differs from its collapsed form as "THE LAYOUT MOVED … a real miss, worth triaging" — the wrong-classification-plus-wrong-evidence row #12300's commit body calls "the worst row this output can print". A zero-segment ** reproduces the conditions for it.

⭐ It also silently props up a recorded verdict. scripts/pm/bare-root-worklist.mjs's scripts/check-declaration-mirrors.mjs SCRIPTS_DIR scripts row refuses on the grounds that "what cannot be spelled here is the EXTENSION filter" — and today that is true only because of this gap. Both spellings of its population are dead: one on the zero-segment rule, one on the collapse. Fix this and that row's reason becomes stale in the same way #12328 describes for four of its siblings. Worth handling together, or at least knowing about.

Not asserted

Whether **should match zero segments is a real decision, not an obvious bug fix — #12300's self-test deliberately pins a large set of "what this must NOT disturb" cases, including the ROOT_DIR_WATCH_HINTS idiom it measured at −7404 pairs on three gates if widened wrongly. Any change here needs the same measurement. The alternative remedy is to leave the matcher alone and treat scripts/**/*.d.mts as a spelling authors must not use, which argues for a check that refuses a hint reaching zero tracked files at its declaration site.

Repro

node -e "import('./scripts/pm/dispatch-gates.mjs').then(({hintCovers, trackedFiles}) => { const real = trackedFiles().filter(f => f.startsWith('scripts/') && f.endsWith('.d.mts')); console.log('tracked:', real); console.log('reached by scripts/**/*.d.mts:', real.filter(f => hintCovers('scripts/**/*.d.mts', f)).length); console.log('reached by scripts/*.d.mts: ', real.filter(f => hintCovers('scripts/*.d.mts', f)).length);});"

Refs: #12300 (added the branch) · #12246 (the dead-hint species) · #12328 (the sibling rows this one is deliberately NOT among) · #12289


Generated by Claude Code

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions