Skip to content

Commit 9fd9370

Browse files
committed
fix(devx): enumerate and triage the invisible half of the bare-root species
A gate whose population literal carries no separator builds no watch hint at all -- `looksPathy` drops it before `hintCovers` is consulted -- so it is unnameable by any dispatch brief and leaves no residue saying so. That half is invisible to the derivation AND to ESCAPABLE_LITERAL_LEDGER, which #10890's comment says in the source and names #10840 for. Adds scripts/pm/bare-root-worklist.mjs: the sweep, derived at runtime from the derivation's own exported predicates, plus one recorded verdict per row. Its self-test pins the triage to the tree in both directions -- a verdict cannot outlive its row, and a new row cannot land unjudged -- and proves the recogniser both speaks and discriminates. Lands three per-gate declarations, the only rows clearing precision >= 85% and blast radius <= 300 files: check:driver-conformance packages/drivers/** 259/291 (89%) check:skill-frame-sync skills/** 48/50 (96%) check:skill-compatibility skills/** 49/50 (98%) Each pins the coupling in its own self-test, derived from the population constant rather than re-spelled, and pins its REFUSALS by name too. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DdCnBGcHeufjrq7drTD3wt
1 parent 2695a8c commit 9fd9370

5 files changed

Lines changed: 783 additions & 3 deletions

File tree

‎.github/workflows/lint.yml‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,28 @@ jobs:
343343
- name: PM dispatch-gates self-test
344344
run: pnpm check:pm-dispatch-gates
345345

346+
# PM bare-root worklist self-test (#10840). The step above proves the
347+
# dispatch derivation still WORKS; this one proves the recorded triage of
348+
# the gates that derivation structurally cannot see is still true of the
349+
# tree. A gate whose population is spelled as a bare single-segment word
350+
# builds no watch hint at all — not a dead hint, not a silent verdict,
351+
# nothing — so it is unnameable by any dispatch brief and leaves no residue
352+
# saying so. The worklist enumerates that species and carries one recorded
353+
# verdict per row; this step fails when a verdict outlives its row (the
354+
# shrink) or when a new gate joins the species unjudged.
355+
#
356+
# ⛔ It runs the SELF-TEST only, never the sweep as a verdict: recognising
357+
# this species needs a heuristic over constant NAMES, and #10705 refused to
358+
# put one on the path that derives every PR's gate list. Nothing in
359+
# `dispatch-gates.mjs` reads the worklist, and no verdict in it reaches a
360+
# dispatch prompt.
361+
#
362+
# Unconditional, for the same reason as the step above: a self-test that
363+
# can be skipped is the gap moving rather than closing. Reads the workflow
364+
# tree and every gate source once; ~0.5s.
365+
- name: PM bare-root worklist self-test
366+
run: node scripts/pm/bare-root-worklist.mjs --self-test
367+
346368
# Part-of/closing-keyword guard self-test (#8476). The guard itself is a
347369
# PR-scoped blocking check in its own workflow — it needs a pull request
348370
# body to judge, which this job does not have — so what runs HERE is its

‎scripts/check-driver-conformance.mjs‎

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,65 @@ const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
119119
const DRIVERS_DIR = join(ROOT, 'packages', 'drivers');
120120
const CASE_SETS_DIR = join(ROOT, 'packages', 'spec', 'src', 'data');
121121

122+
/**
123+
* The half of this gate's two scan roots that `scripts/pm/dispatch-gates.mjs`
124+
* cannot see, written in the syntax that derivation CAN read. Provenance ONLY:
125+
* nothing in this gate reads this array, and both walks behave exactly as they
126+
* did without it.
127+
*
128+
* ## The defect this repairs (#10840's worklist, the #10114 / #10314 idiom)
129+
*
130+
* The dispatch derivation scans a gate's module body for the path literals it
131+
* operates on, and "looks like a path" there means "carries a separator". Both
132+
* roots above are assembled by `join()` from separate single-segment arguments,
133+
* so the only literals this file offers the extractor are the bare words
134+
* `packages`, `drivers`, `spec`, `src` and `data` — every one of which
135+
* `extractWatchHints` drops BEFORE `hintCovers` is ever consulted. They are not
136+
* dead hints; they are nothing at all, which is why no residue line ever named
137+
* them. Measured on this tree, a derivation for
138+
* `packages/drivers/postgres/src/index.ts` named six gates and this was not one
139+
* of them — a driver card, and the driver-conformance matrix is invisible to it.
140+
*
141+
* ## Why `packages/drivers/**` and NOT `packages/**`
142+
*
143+
* `hintCovers` refuses a bare single-segment literal as too generic BY DESIGN,
144+
* and the refusal is measured: accepting bare top-level directory words was
145+
* priced at +139084 fabricated (gate, file) pairs, precisely because `packages`
146+
* is a path COMPONENT in dozens of gates that never read that root — this gate
147+
* among them. The literal `'packages'` here is such a component and nothing
148+
* more. Declaring the top-level root would be the fabrication one level up:
149+
*
150+
* packages/** 259 files this gate reads, of 4903 tracked — 5.3%,
151+
* pasted into every packages/** prompt in the repo.
152+
* packages/drivers/** 259 of 291 — 89%, over a subtree 17x smaller.
153+
*
154+
* The remaining 32 files under `packages/drivers/` are the per-package
155+
* manifests, licences and changelogs; adding or removing a driver package moves
156+
* `discoverDrivers` through exactly those, so 89% is a floor rather than an
157+
* estimate.
158+
*
159+
* ## Why CASE_SETS_DIR is deliberately NOT declared
160+
*
161+
* The instrument can only express a SUBTREE — `collapseHint` strips globs, so
162+
* `packages/spec/src/data/*-conformance.ts` collapses to a path that names
163+
* nothing, and the only spellable claim is the whole directory. That directory
164+
* holds 143 tracked files of which this gate reads 7 (4.9%): a subtree
165+
* declaration there would name this gate for every Zod schema and unit test
166+
* beside the case sets. A missing lead costs one card one CI round; a
167+
* fabricated one is pasted into every prompt whose surface brushes it. So the
168+
* case-set side stays undeclared, and the refusal is pinned in the self-test
169+
* rather than left in this paragraph.
170+
*
171+
* ## Provenance, never a lookup key
172+
*
173+
* `assertRootsResolvable([DRIVERS_DIR, CASE_SETS_DIR])` stats both roots and
174+
* throws DeadRootError when one is missing, so the glob form appearing in either
175+
* constant would turn this gate red on a directory that never existed. The
176+
* self-test pins that apart, and derives both halves of the coupling from
177+
* DRIVERS_DIR rather than re-spelling it.
178+
*/
179+
const ROOT_DIR_WATCH_HINTS = ['packages/drivers/**'];
180+
122181
// ── The case-sets ───────────────────────────────────────────────────────────
123182
//
124183
// `marker` is the export a suite cannot run the case-set without naming, so its
@@ -1074,6 +1133,39 @@ function selfTest() {
10741133
}
10751134
}
10761135

1136+
// -- The dispatch-gates declaration (#10840) --------------------------------
1137+
//
1138+
// Enforcement cannot hold any of these: the declaration is read by another
1139+
// tool entirely, so a wrong or stale one runs green here forever and pays
1140+
// itself out as a dev dispatched on a driver card with this gate missing from
1141+
// the brief. Both halves are DERIVED from DRIVERS_DIR rather than re-spelled,
1142+
// so moving the driver tree cannot leave the declaration describing the old
1143+
// location -- the failure mode a hand-kept copy has.
1144+
const driversRel = DRIVERS_DIR.slice(ROOT.length + 1);
1145+
expect('the declaration names the driver subtree this gate actually walks, derived from '
1146+
+ 'DRIVERS_DIR rather than re-spelled beside it',
1147+
ROOT_DIR_WATCH_HINTS.includes(`${driversRel}/**`));
1148+
expect('and declares nothing else (a declaration that can drift from the scan is worse than '
1149+
+ 'none -- it replaces a silent gate with a lying one)',
1150+
ROOT_DIR_WATCH_HINTS.every((h) => h.replace(/\/\*+$/, '') === driversRel));
1151+
// The non-vacuity half, and the reason this file needs a declaration at all:
1152+
// every literal it offers the extractor is a bare `join()` argument, so the
1153+
// real population reaches the derivation as nothing whatever.
1154+
expect('the population really is unseeable as spelled -- DRIVERS_DIR is built from bare '
1155+
+ 'single-segment join() arguments, none of which the extractor keeps',
1156+
driversRel.includes('/') && !ROOT_DIR_WATCH_HINTS.includes(driversRel));
1157+
// The REFUSALS, pinned. Neither is an oversight to be tidied up later.
1158+
expect('the bare top-level root is deliberately NOT declared -- `packages` is a path COMPONENT '
1159+
+ 'here, and a subtree hint on it would name this gate for 4903 files to reach 259',
1160+
!ROOT_DIR_WATCH_HINTS.some((h) => h.replace(/\/\*+$/, '') === 'packages'));
1161+
expect('CASE_SETS_DIR is deliberately NOT declared -- its population is a FILENAME pattern '
1162+
+ '(*-conformance.ts, 7 of 143 files) and a subtree hint cannot express one',
1163+
!ROOT_DIR_WATCH_HINTS.some((h) => CASE_SETS_DIR.slice(ROOT.length + 1).startsWith(h.replace(/\/\*+$/, ''))));
1164+
// Provenance, never a lookup key: assertRootsResolvable stats both roots, so
1165+
// the glob form appearing in either constant is a hard red on a dead root.
1166+
expect('the declared form is NOT a scan-root value',
1167+
!ROOT_DIR_WATCH_HINTS.some((h) => h === driversRel || h === DRIVERS_DIR));
1168+
10771169
if (failures.length) {
10781170
for (const f of failures) console.error(` x self-test: ${f}`);
10791171
console.error(`\ncheck-driver-conformance --self-test: ${failures.length} failure(s).\n`);
@@ -1083,7 +1175,8 @@ function selfTest() {
10831175
'OK self-test: detects driven / unused / re-declared fixtures, discovers both axes, accounts for '
10841176
+ 'every entry under DRIVERS_DIR (a dropped or manifestless row is red, not a smaller matrix), '
10851177
+ 'holds the dead-root hard error (red when a scan root is renamed, green when restored), and '
1086-
+ 'keeps CONSUMED\'s ledger offer marked maintainer-only (#8435).',
1178+
+ 'keeps CONSUMED\'s ledger offer marked maintainer-only (#8435). It also declares the driver '
1179+
+ 'subtree dispatch-gates derives from, refusing the bare root and the case-set dir by name.',
10871180
);
10881181
}
10891182

‎scripts/check-skill-compatibility-version.mjs‎

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,54 @@ const SKILLS_DIR = 'skills';
7575
// guarantees that for the next package someone cites.
7676
const PACKAGE_ROOTS = ['packages', 'apps', 'examples'];
7777

78+
/**
79+
* The half of this gate's two populations that `scripts/pm/dispatch-gates.mjs`
80+
* cannot see, written in the syntax that derivation CAN read. Provenance ONLY:
81+
* nothing in this gate reads this array, and both walks behave exactly as they
82+
* did without it.
83+
*
84+
* ## The defect this repairs (#10840's worklist, the #10114 / #10314 idiom)
85+
*
86+
* The dispatch derivation scans a gate's module body for path-ish string
87+
* literals, and "path-ish" there means "carries a separator". Both `SKILLS_DIR`
88+
* and every entry of `PACKAGE_ROOTS` are bare single-segment words, so
89+
* `extractWatchHints` drops all four BEFORE `hintCovers` is ever consulted —
90+
* they are not dead hints, they are nothing at all, which is why no residue line
91+
* ever named them. Measured on this tree, a derivation for
92+
* `skills/objectstack-platform/SKILL.md` named four gates and this was not one
93+
* of them, though a `compatibility:` pin in that file is the whole subject here.
94+
*
95+
* ## Why `skills/**` is declared and the three PACKAGE_ROOTS are NOT
96+
*
97+
* The instrument can only express a SUBTREE: `hintCovers` collapses globs, so a
98+
* declared hint names every tracked file beneath it and there is no way to spell
99+
* "the package manifests under this root". That makes the two sides of this gate
100+
* completely different trades, and both were measured on this tree:
101+
*
102+
* skills/** 49 of 50 tracked files are skill directories this gate
103+
* reads — 98% precision over a 50-file subtree.
104+
* packages/** 73 package.json files out of 4903 tracked files — 1.5%,
105+
* pasted into every packages/** dispatch prompt in the repo.
106+
* apps/** 1 of 35 (2.9%) · examples/** 4 of 238 (1.7%).
107+
*
108+
* The three package roots are therefore the +139084 fabrication one level up —
109+
* the very measurement in `hintCovers`' docblock, which prices accepting bare
110+
* top-level directory words at that many fabricated (gate, file) pairs because
111+
* `packages`, `apps` and `examples` are path COMPONENTS in dozens of gates that
112+
* never read those roots. A missing lead costs one card one CI round; a
113+
* fabricated one is pasted into every prompt whose surface brushes it and the
114+
* dev cannot tell it from a real one. So the manifest side stays undeclared,
115+
* deliberately, and the refusal is pinned in the self-test rather than left in
116+
* this paragraph — a later author who adds `packages/**` meets an assertion.
117+
*
118+
* ## Provenance, never a lookup key
119+
*
120+
* `readSkillFiles` joins SKILLS_DIR and then `statSync`s each entry, so the glob
121+
* form appearing in that constant would throw on a directory that does not
122+
* exist. The self-test pins that apart too.
123+
*/
124+
const ROOT_DIR_WATCH_HINTS = ['skills/**'];
125+
78126
/**
79127
* A `compatibility:` pin, e.g. `@objectstack/spec 17.x`.
80128
*
@@ -658,11 +706,53 @@ function selfTest() {
658706
console.log(` ✓ real-tree discovery: ${disc.files.length} SKILL.md file(s), ${disc.problems.length} layout problem(s)`);
659707
}
660708

709+
// ── The dispatch-gates declaration (#10840) ───────────────────────────────
710+
//
711+
// Enforcement cannot hold any of these: the declaration is read by another
712+
// tool entirely, so a wrong or stale one runs green here forever and pays
713+
// itself out as a dev dispatched on a skills card with this gate missing from
714+
// the brief. Both halves are DERIVED from the population constants rather than
715+
// re-spelled, so renaming or re-scoping a root cannot leave the declaration
716+
// describing the old population.
717+
//
718+
// The predicate is `hintCovers`' own refusal (dispatch-gates.mjs: a hint with
719+
// no `/` and no leading `.` is rejected as too generic), spelled here rather
720+
// than imported because this gate must not take a dependency on the PM tool to
721+
// state what it reads. If that refusal ever changes, this line moves with it.
722+
const unseeable = (r) => !r.includes('/') && !r.startsWith('.');
723+
const declFailures = [];
724+
const decl = (label, ok) => { if (!ok) declFailures.push(label); };
725+
decl('SKILLS_DIR is invisible to the derivation, which is why it needs a declaration at all',
726+
unseeable(SKILLS_DIR));
727+
decl('and it declares exactly that root, in the subtree spelling',
728+
ROOT_DIR_WATCH_HINTS.includes(`${SKILLS_DIR}/**`));
729+
decl('and declares no root this gate does not read (a declaration that can drift from the scan '
730+
+ 'is worse than none — it replaces a silent gate with a lying one)',
731+
ROOT_DIR_WATCH_HINTS.every((h) => h.replace(/\/\*+$/, '') === SKILLS_DIR));
732+
// The REFUSAL, pinned. The manifest walk really does read all three roots, so
733+
// this is not an oversight to be tidied up later — it is a priced decision:
734+
// 73 of 4903 files under packages/ (1.5%), 1 of 35 under apps/, 4 of 238 under
735+
// examples/. A subtree hint cannot say "the manifests"; it can only say "all
736+
// of it", and all of it is false here.
737+
decl('the three PACKAGE_ROOTS are deliberately NOT declared — a subtree hint would name this '
738+
+ 'gate for every file under them to reach the package.json files, which is the fabricated '
739+
+ 'lead hintCovers is measured against',
740+
PACKAGE_ROOTS.every((r) => !ROOT_DIR_WATCH_HINTS.includes(`${r}/**`)));
741+
decl('the non-vacuity half of that refusal: those roots really are invisible, so the refusal is '
742+
+ 'a live choice rather than a description of something the extractor already handles',
743+
PACKAGE_ROOTS.every(unseeable));
744+
// Provenance, never a lookup key: readSkillFiles joins SKILLS_DIR and statSyncs
745+
// each entry, so the glob form appearing there would throw on a missing dir.
746+
decl('the declared form is NOT the SKILLS_DIR value itself',
747+
!ROOT_DIR_WATCH_HINTS.includes(SKILLS_DIR));
748+
for (const f of declFailures) console.error(` ✗ dispatch-gates declaration: ${f}`);
749+
failed += declFailures.length;
750+
661751
if (failed > 0) {
662752
console.error(`\n✗ check-skill-compatibility-version self-test failed (${failed} case(s)).`);
663753
process.exit(1);
664754
}
665-
console.log(`\n✓ check-skill-compatibility-version self-test: ${cases.length} cases pass.`);
755+
console.log(`\n✓ check-skill-compatibility-version self-test: ${cases.length} cases pass, plus 7 dispatch-gates declaration cases.`);
666756
}
667757

668758
// ---------------------------------------------------------------------------

0 commit comments

Comments
 (0)