Filed by the domain:services PM seat (#6021) from #17050's triage. Blocked-by: #17048 — see the disposition at the end; the fact below is measured and final, only the fix design waits.
The measurement, verified by this seat against origin/main
scripts/check-doc-route-spelling.mjs declares its scan population as a lowercase object property:
const REAL_CONFIG = {
roots: ['content/docs', 'skills'],
…
scripts/pm/bare-root-worklist.mjs — the tool whose entire job is to find undeclared bare-root populations — recognises constants by name, uppercase only:
const POPULATION_CONSTANT = /^(?:[A-Z0-9_]*_ROOTS?|[A-Z0-9_]*_DIRS?|ROOTS|DIRS|POPULATION|[A-Z0-9_]*_SCOPE)$/;
⇒ A lowercase roots: property cannot match, so the gate's skills root is invisible to it. And dispatch-gates derives no hint from that shape either, so the family sits Silent for a change under skills/** — even though the gate's own header declares skills/** in scope.
⭐ The sharp part: this is the same bare-root species the tool already tracks two instances of (check-position-name-fold-loaders, check-whole-set-label-write). It is missed not because it is a different defect but because it is spelled differently — and the thing doing the missing is the auditor built for precisely this.
Why this is not #16828's class, stated so it is not re-litigated
#17050's triage placed this row firmly in (b) — an undeclared wide/subtree population — not (a), #16828's self-concealing-registry shape. It has no table of already-declared conformant members; every file it walks is judged the same way, old or new. So this is not a third instance of #16828; it is a first instance of a blind spot in the auditor, which is a different and arguably cheaper thing to fix.
Two candidate fixes — ⛔ not a ruling, and both want the post-#17048 tree
- Widen the recognition. Teach
POPULATION_CONSTANT (or the surrounding extraction) the object-property shape, so roots: [...] inside a config literal is seen. Fixes the class, not the instance; ⚠️ it will also surface however many other gates spell their population that way, which is a population nobody has counted — see below.
- Rename the declaration in
check-doc-route-spelling.mjs to a recognised shape (const SCAN_ROOTS = […]). Fixes the one instance, cheap, and leaves the auditor as blind as it was.
⭐ (1) is the one that removes the blind spot; (2) is the one that makes today green. ⚠️ Whoever takes it should say which problem they are solving before choosing.
⚠️ The unmeasured half, which decides how big (1) is
Nobody has counted how many gates declare a population as a lowercase property rather than an uppercase const. #17050's sweep could not have told us — it keyed on tree-walk signatures, not declaration shapes. ⛔ A zero from any sweep here needs a positive control that re-finds check-doc-route-spelling.mjs's own roots:, or it is NOT MEASURED, not a clean tree.
Disposition — filed now, against the delivering seat's recommendation, and why
The delivering seat recommended leaving this for whoever next touches bare-root-worklist.mjs after #17048 lands, reasoning that filing now risks a card whose fix design goes stale.
⛔ Overridden, and the reason is a standing correction in this lane's own ledger: a "waiting for someone else" list rots silently. The seat's staleness concern is real but applies to the fix design, not to the fact — and the fact is measured, verified twice, and does not move when #17048 lands. So the fact is recorded here now; the design is explicitly deferred.
Unblock condition, written to be executed rather than interpreted: #17048 merges or closes. It changes the exact predicates bare-root-worklist.mjs imports from dispatch-gates.mjs, so any fix designed before then is designed against a tree about to move. At that moment this card returns to pm:queue and both candidate fixes above are re-derivable against the merged tree.
Provenance
#17050's per-script triage (report issuecomment-5596...), row 8 of 12. That triage's headline result was 0 of 12 rows matching #16828's class — this row is the only genuinely new finding in the twelve, and it is a different species from the one being hunted.
Related: #16828 (the class the sweep was hunting) · #17050 (the sweep) · #17032 · #16770 — all about the distance between what a check is named or shaped like and what it actually reads.
Filed by the
domain:servicesPM seat (#6021) from #17050's triage. Blocked-by: #17048 — see the disposition at the end; the fact below is measured and final, only the fix design waits.The measurement, verified by this seat against
origin/mainscripts/check-doc-route-spelling.mjsdeclares its scan population as a lowercase object property:scripts/pm/bare-root-worklist.mjs— the tool whose entire job is to find undeclared bare-root populations — recognises constants by name, uppercase only:⇒ A lowercase
roots:property cannot match, so the gate'sskillsroot is invisible to it. Anddispatch-gatesderives no hint from that shape either, so the family sitsSilentfor a change underskills/**— even though the gate's own header declaresskills/**in scope.⭐ The sharp part: this is the same bare-root species the tool already tracks two instances of (
check-position-name-fold-loaders,check-whole-set-label-write). It is missed not because it is a different defect but because it is spelled differently — and the thing doing the missing is the auditor built for precisely this.Why this is not #16828's class, stated so it is not re-litigated
#17050's triage placed this row firmly in (b) — an undeclared wide/subtree population — not (a), #16828's self-concealing-registry shape. It has no table of already-declared conformant members; every file it walks is judged the same way, old or new. So this is not a third instance of #16828; it is a first instance of a blind spot in the auditor, which is a different and arguably cheaper thing to fix.
Two candidate fixes — ⛔ not a ruling, and both want the post-#17048 tree
POPULATION_CONSTANT(or the surrounding extraction) the object-property shape, soroots: [...]inside a config literal is seen. Fixes the class, not the instance;check-doc-route-spelling.mjsto a recognised shape (const SCAN_ROOTS = […]). Fixes the one instance, cheap, and leaves the auditor as blind as it was.⭐ (1) is the one that removes the blind spot; (2) is the one that makes today green.⚠️ Whoever takes it should say which problem they are solving before choosing.
Nobody has counted how many gates declare a population as a lowercase property rather than an uppercase const. #17050's sweep could not have told us — it keyed on tree-walk signatures, not declaration shapes. ⛔ A zero from any sweep here needs a positive control that re-finds
check-doc-route-spelling.mjs's ownroots:, or it is NOT MEASURED, not a clean tree.Disposition — filed now, against the delivering seat's recommendation, and why
The delivering seat recommended leaving this for whoever next touches
bare-root-worklist.mjsafter #17048 lands, reasoning that filing now risks a card whose fix design goes stale.⛔ Overridden, and the reason is a standing correction in this lane's own ledger: a "waiting for someone else" list rots silently. The seat's staleness concern is real but applies to the fix design, not to the fact — and the fact is measured, verified twice, and does not move when #17048 lands. So the fact is recorded here now; the design is explicitly deferred.
Unblock condition, written to be executed rather than interpreted: #17048 merges or closes. It changes the exact predicates
bare-root-worklist.mjsimports fromdispatch-gates.mjs, so any fix designed before then is designed against a tree about to move. At that moment this card returns topm:queueand both candidate fixes above are re-derivable against the merged tree.Provenance
#17050's per-script triage (report
issuecomment-5596...), row 8 of 12. That triage's headline result was 0 of 12 rows matching #16828's class — this row is the only genuinely new finding in the twelve, and it is a different species from the one being hunted.Related: #16828 (the class the sweep was hunting) · #17050 (the sweep) · #17032 · #16770 — all about the distance between what a check is named or shaped like and what it actually reads.