Skip to content

[finding] A mid-segment * collapses to a double slash, so skills/*/references/_index.md names 9 real files and reaches none — and the family is filed as "THE LAYOUT MOVED" #12246

Description

@yinlianghui

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')// → false

skills//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)

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions