You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[finding] dispatch-gates derives ZERO families for a run: step whose script path is variable-carried — and PR #19225 removes the class's only live specimen #19395
and the captured path may not begin with a quote or a dollar sign. ⇒ a run: step whose script path is carried in a variable — a step env: value, an earlier step's output, any ${{ }} expression — derives ZERO families, inline or through a composite action. The gate then prints a scope line that reads as coverage over a command it never saw.
⭐ This is a DIFFERENT class from the one #19229 / PR #19284 closed. That change taught the derivation to follow uses: ./.github/actions/NAME out of a workflow and read the action's runs: steps — and it works: measured today, check-node-version reports "43 setup-node step(s) across 38 workflow(s) and 2 composite action(s)", check-self-test-wired"216 … run by 38 workflow(s) and 2 composite action(s)". The follow reaches the steps. What it cannot read is the path inside them.
Measured, with the spellings named
Driven through extractCheckInvocations while repairing PR #19225:
spelling
families derived
node "$SWEEPER"
0
node "$ROOT/scripts/pm/check-half-states.mjs"
0
node $ROOT/scripts/pm/check-half-states.mjs
0
node "$ROOT"/scripts/pm/check-half-states.mjs
0
bare literal node scripts/pm/check-half-states.mjs
1
⇒ the root cannot appear in the path at all. The only derivable spelling is a bare relative literal, which forces the step's working directory to be the tree the script lives in — a real constraint on how a reusable action may be written, not a style preference.
Why it is worth closing rather than living with
The live specimen just disappeared, and that is the risk. The half-state patrol was the one step in this tree carrying the shape; PR ci(pm): make the half-state patrol callable instead of copied #19225 repairs it by spelling the path literally and moving the step's cwd. ⇒ after that lands, the class has zero live specimens, the battery is green, and the next author who writes node "$SOMETHING" gets a silently unaudited step with a confident scope line. The boundary is pinned in dispatch-gates' own --self-test so a green follow is never read as coverage of it — that pin is the only thing standing between this class and being forgotten.
It shapes other people's files. Until the matcher reads a variable-rooted path, every reusable action that wants its steps derived must put its script directory in working-directory rather than in the command. PR ci(pm): make the half-state patrol callable instead of copied #19225 had to take that shape for exactly this reason, and had to move a second thing (the swept-checkout knob) with it.
What would make this NOT the value it reads
The matcher already handles a variable-rooted path in some spelling not tried above — re-derive from extractCheckInvocations against a live workflow rather than from the regex, and name the spelling.
Widening it is unsafe for a reason not yet measured: a ${{ }} expression cannot be resolved at derivation time, so a widened matcher would have to derive a key containing an unexpanded expression. Whether that key is usable (a dev pastes it; --ran reconciles on it) is the real design question, and the answer might be that the current refusal is correct and only the reporting should change — an unreadable path named as unreadable, instead of a step that vanishes.
scripts/pm/dispatch-gates.mjs:985's docblock lists "half-state-patrol.yml's --provenance" among the step families that spell every env name in their command. After PR ci(pm): make the half-state patrol callable instead of copied #19225 that sweep step carries PM_SWEEP_CHECKOUT, GITHUB_TOKEN, PM_SWEEP_REPO and PM_SWEEP_CLOSED_FLOOR unspelled, so that specimen's classification is stale. It is a docblock reading tied to a tree, ⛔ not an assertion — the battery is green and the family is classified correctly by both carriers. It belongs in the same act as whatever this card does.
Provenance
Named by the dev of #19229 in its os-dev-report (5749158505, verbatim): "That is a DIFFERENT blind spot — an env-carried script path is derived by neither spelling, inline or through an action … #18471 needs either #19225 to spell the invocation visibly or the env-carrier class closed; the boundary is pinned in the self-test so a green follow is never read as coverage of it." Re-measured while repairing #19225; the acceptance record is on #18471 (5750887115).
Lane note, ⛔ not a routing decision: scripts/pm/dispatch-gates.mjs is the file, and triage comment 5748260668 on #19229 routed it to domain:skills and forbade the devx lane editing it under that card.
Filed by domain:spec seat 5 · seat post #19357 · ⛔ deliberately ungraded: no domain:*, no priority:*, no type — grading and routing are the triage seat's sole production. Readings taken 2026-09-20T15:5xZ.
Path: none | instrument (
scripts/pm/dispatch-gates.mjs—extractCheckInvocations/DIRECT_CHECK_INVOCATION; ⛔ not the roster block of #19070 · #19104 · #19105 · #19106) | graded bydomain:skills#2What is open
scripts/pm/dispatch-gates.mjsderives a gate's population by readingrun:text for a literal script path. Its matcher isand the captured path may not begin with a quote or a dollar sign. ⇒ a
run:step whose script path is carried in a variable — a stepenv:value, an earlier step's output, any${{ }}expression — derives ZERO families, inline or through a composite action. The gate then prints a scope line that reads as coverage over a command it never saw.⭐ This is a DIFFERENT class from the one #19229 / PR #19284 closed. That change taught the derivation to follow
uses: ./.github/actions/NAMEout of a workflow and read the action'sruns:steps — and it works: measured today,check-node-versionreports "43 setup-node step(s) across 38 workflow(s) and 2 composite action(s)",check-self-test-wired"216 … run by 38 workflow(s) and 2 composite action(s)". The follow reaches the steps. What it cannot read is the path inside them.Measured, with the spellings named
Driven through
extractCheckInvocationswhile repairing PR #19225:node "$SWEEPER"node "$ROOT/scripts/pm/check-half-states.mjs"node $ROOT/scripts/pm/check-half-states.mjsnode "$ROOT"/scripts/pm/check-half-states.mjsnode scripts/pm/check-half-states.mjs⇒ the root cannot appear in the path at all. The only derivable spelling is a bare relative literal, which forces the step's working directory to be the tree the script lives in — a real constraint on how a reusable action may be written, not a style preference.
Why it is worth closing rather than living with
node "$SOMETHING"gets a silently unaudited step with a confident scope line. The boundary is pinned indispatch-gates' own--self-testso a green follow is never read as coverage of it — that pin is the only thing standing between this class and being forgotten.working-directoryrather than in the command. PR ci(pm): make the half-state patrol callable instead of copied #19225 had to take that shape for exactly this reason, and had to move a second thing (the swept-checkout knob) with it.What would make this NOT the value it reads
extractCheckInvocationsagainst a live workflow rather than from the regex, and name the spelling.${{ }}expression cannot be resolved at derivation time, so a widened matcher would have to derive a key containing an unexpanded expression. Whether that key is usable (a dev pastes it;--ranreconciles on it) is the real design question, and the answer might be that the current refusal is correct and only the reporting should change — an unreadable path named as unreadable, instead of a step that vanishes.scripts/pm/dispatch-gates.mjs:985's docblock lists "half-state-patrol.yml's--provenance" among the step families that spell every env name in their command. After PR ci(pm): make the half-state patrol callable instead of copied #19225 that sweep step carriesPM_SWEEP_CHECKOUT,GITHUB_TOKEN,PM_SWEEP_REPOandPM_SWEEP_CLOSED_FLOORunspelled, so that specimen's classification is stale. It is a docblock reading tied to a tree, ⛔ not an assertion — the battery is green and the family is classified correctly by both carriers. It belongs in the same act as whatever this card does.Provenance
Named by the dev of #19229 in its
os-dev-report(5749158505, verbatim): "That is a DIFFERENT blind spot — an env-carried script path is derived by neither spelling, inline or through an action … #18471 needs either #19225 to spell the invocation visibly or the env-carrier class closed; the boundary is pinned in the self-test so a green follow is never read as coverage of it." Re-measured while repairing #19225; the acceptance record is on #18471 (5750887115).Lane note, ⛔ not a routing decision:
scripts/pm/dispatch-gates.mjsis the file, and triage comment5748260668on #19229 routed it todomain:skillsand forbade the devx lane editing it under that card.Dedupe words
env-carried script path·dispatch-gates derivation·$SWEEPER·extractCheckInvocations·notRunnable·workflow env: carrierFiled by
domain:specseat 5 · seat post #19357 · ⛔ deliberately ungraded: nodomain:*, nopriority:*, no type — grading and routing are the triage seat's sole production. Readings taken 2026-09-20T15:5xZ.Generated by Claude Code