Found while landing #12107 (the resolveCheckToFiles extension fix). ⛔ Not fixed there — that
card's declared surface is resolveCheckToFiles and the discoverFamilies package-filter branch,
and scripts/pm/dispatch-gates.mjs is the head of a four-card serial queue (#12074 option 1,
#11556, #11199). Filed unassigned, not graded.
This is only visible because of #12107: before it, all 23 TypeScript-authored gates resolved to
zero files, so their sources were never opened and none of their literals reached the residue. With
those sources opened, the unreachable listing goes from 2 families to 12, and two independent
defects come with it.
1. collapseHint turns a mid-segment * into a double slash
collapseHint('skills/*/references/_index.md')// → 'skills//references/_index.md'hintCovers('skills/*/references/_index.md','skills/objectstack-ai/references/_index.md')// → falseskills//references/_index.md is not a path any tree can hold, so the literal matches nothing by
construction. Measured on this tree: 9 tracked files match that glob as a shell would —
$ git ls-files 'skills/*/references/_index.md' | wc -l
9
— and the derivation reaches none of them. This is not a declaration the gate got wrong; it is a
real population spelled in a glob shape the covering rule cannot expand. The trailing-** shape
(content/docs/references/**) works, so the gap is specifically a * in a middle segment.
check:skill-refs is the live specimen: packages/spec/scripts/build-skill-references.ts
generates those nine _index.md files, and after #12107 the family resolves its source, reads the
declaration, and still matches nothing in the tree.
2. unreachableClass files that family under "THE LAYOUT MOVED"
1 where THE LAYOUT MOVED under a gate that still spells the old path — a real miss, worth triaging:
- pnpm --filter @objectstack/spec run check:skill-refs [lint.yml] dead: 'lib/generated-output' —
no tracked path under its first segment; never was a repo path · '@objectstack/spec' — … · 'data/field.zod.ts' — …
The layout did not move. unreachableClass returns 'layout moved' when any dead hint has a
deepest that differs from its collapsed form, and the double-slash collapse above is what makes
that true. The heading then promotes the row above the "BY CONSTRUCTION" block as "a real miss,
worth triaging" — and the three reasons it prints are not the glob at all, they are TypeScript
module specifiers (defect 3), so a reader who follows the lead is sent to look for a moved
lib/generated-output that never existed.
Both halves of the output are wrong in the same row: the classification, and the evidence shown
for it.
3. TypeScript module specifiers are admitted as watch hints
extractWatchHints was written against .mjs gates, whose relative imports carry a leading ./.
The packages/spec TypeScript gates use paths-mapped bare specifiers that look pathy:
lib/dist-freshness · lib/generated-output · lib/schema-name · src/kernel/protocol-version
data/field.zod.ts · ui/view.zod.ts · @objectstack/spec · typescript/bin/tsc
Measured across the 19 families #12107 gives coverage to: 19 hints are live (they cover at
least one tracked file) and 128 are inert (they cover zero).
⭐ The inert 128 fabricate no MATCHED pair — that was measured for #12107 and is why it landed:
a hint covering zero files cannot put a gate in any card's matched column. The cost is confined to
the residue, and it is real there: they are what unreachableReason prints, so a family's genuine
reason (defect 1) is displaced by three specifiers that were never repo paths.
⚠️ Inert today is not inert by construction. data/field.zod.ts and src/kernel/protocol-version
are one top-level data/ or src/ directory away from covering real files, and at that point they
would fabricate in the matched column rather than the residue.
Not asserted
No claim about which remedy is right, or whether the three are one fix or three. Some shapes:
- teach
collapseHint/hintCovers a mid-segment * (widest, and it is the one that recovers the
9 files); - have
unreachableClass not read a collapsed form that contains // as evidence of a move
(narrowest, and it removes the false lead without recovering anything); - give
extractWatchHints a way to tell a paths-mapped TS specifier from a repo path — note the
hint set is fleet-wide, so this one is priced the way firstPartyImportTargets' docblock prices
a widening.
Reproduce
At any commit carrying #12107's fix:
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
# → Unreachable — the 12 famil(ies) …
# 1 where THE LAYOUT MOVED …: check:skill-refs
Refs: #12107 (the fix that surfaces this) · #11556 · #12074 · #11199 (the rest of the serial queue
on this file) · #12064 (adjacent worklist-output defect, different mechanism)
Found while landing #12107 (the
resolveCheckToFilesextension fix). ⛔ Not fixed there — thatcard's declared surface is
resolveCheckToFilesand thediscoverFamiliespackage-filter branch,and
scripts/pm/dispatch-gates.mjsis the head of a four-card serial queue (#12074 option 1,#11556, #11199). Filed unassigned, not graded.
This is only visible because of #12107: before it, all 23 TypeScript-authored gates resolved to
zero files, so their sources were never opened and none of their literals reached the residue. With
those sources opened, the unreachable listing goes from 2 families to 12, and two independent
defects come with it.
1.
collapseHintturns a mid-segment*into a double slashskills//references/_index.mdis not a path any tree can hold, so the literal matches nothing byconstruction. Measured on this tree: 9 tracked files match that glob as a shell would —
— and the derivation reaches none of them. This is not a declaration the gate got wrong; it is a
real population spelled in a glob shape the covering rule cannot expand. The trailing-
**shape(
content/docs/references/**) works, so the gap is specifically a*in a middle segment.check:skill-refsis the live specimen:packages/spec/scripts/build-skill-references.tsgenerates those nine
_index.mdfiles, and after #12107 the family resolves its source, reads thedeclaration, and still matches nothing in the tree.
2.
unreachableClassfiles that family under "THE LAYOUT MOVED"The layout did not move.
unreachableClassreturns'layout moved'when any dead hint has adeepestthat differs from its collapsed form, and the double-slash collapse above is what makesthat true. The heading then promotes the row above the "BY CONSTRUCTION" block as "a real miss,
worth triaging" — and the three reasons it prints are not the glob at all, they are TypeScript
module specifiers (defect 3), so a reader who follows the lead is sent to look for a moved
lib/generated-outputthat never existed.Both halves of the output are wrong in the same row: the classification, and the evidence shown
for it.
3. TypeScript module specifiers are admitted as watch hints
extractWatchHintswas written against.mjsgates, whose relative imports carry a leading./.The
packages/specTypeScript gates usepaths-mapped bare specifiers that look pathy:Measured across the 19 families #12107 gives coverage to: 19 hints are live (they cover at
least one tracked file) and 128 are inert (they cover zero).
⭐ The inert 128 fabricate no MATCHED pair — that was measured for #12107 and is why it landed:
a hint covering zero files cannot put a gate in any card's matched column. The cost is confined to
the residue, and it is real there: they are what
unreachableReasonprints, so a family's genuinereason (defect 1) is displaced by three specifiers that were never repo paths.
data/field.zod.tsandsrc/kernel/protocol-versionare one top-level
data/orsrc/directory away from covering real files, and at that point theywould fabricate in the matched column rather than the residue.
Not asserted
No claim about which remedy is right, or whether the three are one fix or three. Some shapes:
collapseHint/hintCoversa mid-segment*(widest, and it is the one that recovers the9 files);
unreachableClassnot read a collapsed form that contains//as evidence of a move(narrowest, and it removes the false lead without recovering anything);
extractWatchHintsa way to tell apaths-mapped TS specifier from a repo path — note thehint set is fleet-wide, so this one is priced the way
firstPartyImportTargets' docblock pricesa widening.
Reproduce
At any commit carrying #12107's fix:
Refs: #12107 (the fix that surfaces this) · #11556 · #12074 · #11199 (the rest of the serial queue
on this file) · #12064 (adjacent worklist-output defect, different mechanism)