Skip to content

[finding] dispatch-gates derives the SCHEDULED live half-state board sweep into the per-PR gate family for any diff with a changeset #14899

Description

@claude

Recording only, no severity asserted — routing and ranking are triage's. Found while running the derived gate family for the card #13961 on branch claude/issue-13961-explain-zero-rows-sentinels; unrelated to that card's diff, so deliberately not repaired there.

Measured

node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack on a diff whose only PM-ish path is one .changeset/*.md file prints, among 67 matched families:

- node scripts/pm/check-half-states.mjs   [half-state-patrol.yml]   matched via .changeset/EXAMPLE.md  =>  gate source '.changeset'

That command is the live board sweep, not a gate:

  • Its standing caller is .github/workflows/half-state-patrol.yml — a scheduled workflow, whose own header says the patrol exists because "a lane that has to REMEMBER to run a patrol does not run it". It is not triggered by a PR.
  • lint.yml deliberately runs only the offline self-test, pnpm check:pm-half-states, and says why in a comment beside the step: "The gate runs the SELF-TEST only. The live sweep (node scripts/pm/check-half-states.mjs) reads a shared board over the GitHub API, is report-only by design (a completed sweep exits 0 whether it found 0 or 40 half-states), and its non-zero exits classify the ENVIRONMENT … which is not a verdict about the PR running it."
  • pnpm check:pm-half-states is ALSO in the derived list and passes in ~seconds, so the offline half is already covered. The bare node spelling is a second, different command.

So the derived family names a command CI never runs on a PR, and the dispatch protocol tells a dev to run the printed commands.

Cost, measured on one dev container

Running the derived list top to bottom, node scripts/pm/check-half-states.mjs sat for 3m09s with no output before it was stopped by PID; the remaining ~52 commands were blocked behind it for that whole window. It reads a shared board over the GitHub API, so a dev seat that lets it finish also spends API quota on a sweep that says nothing about its own diff — and every dev whose PR carries a changeset (which is most of them) gets this.

Why it is small

The command cannot redden anything: it is report-only by construction. The damage is a dev's wall clock, some shared API quota, and a NOT-MEASURED-looking non-zero exit (143 when stopped, or an environment classification) landing in a verification record next to real gate results, where it reads like a finding.

Scope NOT established

  • ⛔ Whether the repair is (a) an exclusion in dispatch-gates.mjs for commands whose only source workflow is schedule-triggered, (b) a narrower exclusion naming this script, or (c) leaving the derivation and teaching the dispatch protocol to skip report-only live sweeps, is not decided here. (a) is the general shape and would need its own measurement — how many derived commands come only from scheduled workflows, and whether any of them is one a dev SHOULD run.
  • ⛔ Whether half-state-patrol.yml's path list should carry .changeset at all is a separate question about that workflow, not about the deriver.
  • Not measured: whether other scheduled-only workflows contribute commands the same way.

Related

Filed from the #13961 run (branch claude/issue-13961-explain-zero-rows-sentinels). Neighbouring dispatch-gates findings, none of them this one: #14880 (a gate CI DOES run that is not derived — the opposite direction), #14753 and #14294 (silent flag drops), #14290 (an untraversed edge), #14688 (a selfTest() binding bug).


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions