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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions