Measured on PR #11397 (fixing #10907), which shipped a red nobody could have predicted locally.
What happened
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (no paths, merge-base derived) reported 7 local gate families for the diff. Every one was run and every one was green. Lint & Repo Gates then failed on a gate that appeared in none of them:
node scripts/pm/bare-root-worklist.mjs --self-test
x self-test: no gate has NEWLY joined the invisible bare-root species -
FRESH: check:i18n-coverage PACKAGES_DIR packages.
The red was real and the fix was one recorded verdict. What is worth a card is that no local derivation could have named it.
Root cause - the INVOCATION matcher, not the population matcher
This is a different failure from #11199 and #11190, and the difference decides the remedy.
Both of those concern gates that are discovered as families and whose populations are not path-expressible (#11199) or would be lost through a shared import (#11190). Under --residue they at least appear, in the silent / undetermined bucket.
This gate is not a family at all. Measured:
discoverFamilies().byCheck.size -> 139
[...keys].filter(k => k.includes('bare-root')) -> []
[...keys].filter(k => k.includes('--self-test')) -> []
It is absent from the matched list, the convention-triggered list, the unreachable-by-construction list, and from all three residue buckets - because it never enters the universe those buckets partition. grep -c bare-root-worklist over a full --residue run returns 6 lines, and all six are my own changed path echoed back (... bare-root-worklist.mjs -> gate source 'scripts/**'). The file is visible to the derivation only as an INPUT, never as a GATE.
The mechanism is collectInvocations in scripts/pm/dispatch-gates.mjs, which recognises exactly two spellings:
/pnpm\s+(?:--filter\s+(\S+)\s+)?(?:run\s+)?(check:[\w:-]+)/g/node\s+(scripts\/[\w./-]*check-[\w.-]+\.mjs)/g
So a workflow step qualifies only if it is a check:* npm script or its script basename contains check-. scripts/pm/bare-root-worklist.mjs is neither: it has no package.json script, and its filename does not carry the prefix. Verified directly:
"node scripts/pm/bare-root-worklist.mjs --self-test" => []
"node scripts/pm/check-half-states.mjs" => ["scripts/pm/check-half-states.mjs"]
The discovery is keyed on a naming convention, and a real gate that reds the required lane simply does not follow it.
Blast radius, measured
Five steps in lint.yml - the required Lint & Repo Gates job - invoke a scripts/** script whose basename lacks check-, and are therefore invisible to every dispatch brief:
lint.yml:400 node scripts/pm/bare-root-worklist.mjs --self-test
lint.yml:556 node scripts/pm/release-rehearsal-clone.mjs --self-test
lint.yml:785 node scripts/pm/ci-failure.mjs --self-test
lint.yml:1601 node scripts/pr-labels.mjs --self-test
lint.yml:1902 node scripts/partition-test-shards.mjs --self-test
Across all workflows the same sweep finds 13 distinct such scripts. Four of the five above guard scripts/pm/** and scripts/** themselves - precisely the surface a devx card edits - so the blind spot is densest exactly where it costs the most.
bare-root-worklist is also the sharpest specimen for a second reason: its own self-test asserts that it declares no population of its own (this tool declares no population of its own). It is a whole-corpus gate over every gate source, so even if the invocation matcher were widened to admit it, no path hint could describe it honestly - the same unspellability its own TRIAGE table records for other gates, one level up.
Direction (not a decision)
Widening the regex to any scripts/**/*.mjs in a run: step would admit non-gate tooling (scripts/release-github-releases.mjs, scripts/run-with-stall-guard.mjs) and is the fabrication direction hintCovers prices. Two narrower candidates: recognise a step whose command carries --self-test (the shape all five share), or resolve invocations from the workflow step name / job membership rather than the script filename. Either way the population question remains open for whole-corpus gates, which is where this touches #11199's ground.
Refs
#10907 / PR #11397 (where this was measured) - #11199 (a discovered family whose population is not path-expressible) - #11190 (hints lost through a shared import)
Generated by Claude Code
Measured on PR #11397 (fixing #10907), which shipped a red nobody could have predicted locally.
What happened
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(no paths, merge-base derived) reported 7 local gate families for the diff. Every one was run and every one was green.Lint & Repo Gatesthen failed on a gate that appeared in none of them:The red was real and the fix was one recorded verdict. What is worth a card is that no local derivation could have named it.
Root cause - the INVOCATION matcher, not the population matcher
This is a different failure from #11199 and #11190, and the difference decides the remedy.
Both of those concern gates that are discovered as families and whose populations are not path-expressible (#11199) or would be lost through a shared import (#11190). Under
--residuethey at least appear, in thesilent/undeterminedbucket.This gate is not a family at all. Measured:
It is absent from the matched list, the convention-triggered list, the unreachable-by-construction list, and from all three residue buckets - because it never enters the universe those buckets partition.
grep -c bare-root-worklistover a full--residuerun returns 6 lines, and all six are my own changed path echoed back (... bare-root-worklist.mjs -> gate source 'scripts/**'). The file is visible to the derivation only as an INPUT, never as a GATE.The mechanism is
collectInvocationsinscripts/pm/dispatch-gates.mjs, which recognises exactly two spellings:So a workflow step qualifies only if it is a
check:*npm script or its script basename containscheck-.scripts/pm/bare-root-worklist.mjsis neither: it has nopackage.jsonscript, and its filename does not carry the prefix. Verified directly:The discovery is keyed on a naming convention, and a real gate that reds the required lane simply does not follow it.
Blast radius, measured
Five steps in
lint.yml- the requiredLint & Repo Gatesjob - invoke ascripts/**script whose basename lackscheck-, and are therefore invisible to every dispatch brief:Across all workflows the same sweep finds 13 distinct such scripts. Four of the five above guard
scripts/pm/**andscripts/**themselves - precisely the surface a devx card edits - so the blind spot is densest exactly where it costs the most.bare-root-worklistis also the sharpest specimen for a second reason: its own self-test asserts that it declares no population of its own (this tool declares no population of its own). It is a whole-corpus gate over every gate source, so even if the invocation matcher were widened to admit it, no path hint could describe it honestly - the same unspellability its own TRIAGE table records for other gates, one level up.Direction (not a decision)
Widening the regex to any
scripts/**/*.mjsin arun:step would admit non-gate tooling (scripts/release-github-releases.mjs,scripts/run-with-stall-guard.mjs) and is the fabrication directionhintCoversprices. Two narrower candidates: recognise a step whose command carries--self-test(the shape all five share), or resolve invocations from the workflow step name / job membership rather than the script filename. Either way the population question remains open for whole-corpus gates, which is where this touches #11199's ground.Refs
#10907 / PR #11397 (where this was measured) - #11199 (a discovered family whose population is not path-expressible) - #11190 (hints lost through a shared import)
Generated by Claude Code