Skip to content

[finding] dispatch-gates offers the bare check-partof-closing-keyword command as runnable — it takes PR_BODY through env:, not argv, so the NOT-MEASURED bucket never sees it #15761

Description

@claude

Measured 2026-09-05 06:0xZ while deriving the gate family for a scripts/pm/check-half-states.mjs card (PR #15755).

What was measured

node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 31 runnable commands for a one-path changeset. Two of them are the same guard:

node scripts/check-partof-closing-keyword.mjs          -> exit 2
pnpm check:partof-closing-keyword                      -> exit 0 (28 cases pass)

The bare form cannot pass anywhere outside a workflow run. Its own refusal says so, in the file's own words:

check:partof-closing-keyword: NOT WIRED — neither PR_BODY nor PR_NUMBER is set, so this run
was handed no pull request and judged nothing. This is a wiring or usage failure, NOT a
verdict: it says nothing about whether any PR body contradicts itself, and no author caused it.

So a dev handed this family runs a command that can only ever be non-zero, and the honest readings of it are "a red gate I must fix" (wrong) or "NOT MEASURED, skip it" (right, but only if the reader knows the difference).

Why the existing safety net does not catch it

dispatch-gates already has the bucket for exactly this class, and on the same run it used it correctly for four other families:

+ 4 famil(ies) matched by path take a VALUE FROM THE WORKFLOW and are NOT above — their argv
  carries a variable with no value outside a CI run.
    NOT MEASURED — scripts/check-cross-package-test-inputs.mjs --union-into "$RUNNER_TEMP/..."
    NOT MEASURED — scripts/check-shard-attestation.mjs --emit --job test --shard ...
    NOT MEASURED — scripts/check-test-completeness.mjs "$RUNNER_TEMP/test-core.log" ...
    NOT MEASURED — scripts/pm/check-half-states.mjs --format=markdown --provenance="$PROVENANCE"

Each of those is detected because its argv carries a variable. check-partof-closing-keyword.mjs takes its whole input through env: (PR_BODY / PR_NUMBER) and its argv is bare, so the argv-shaped detector cannot see the dependency and files the command as plainly runnable.

The class is not new — #14004 carded the same shape for check-governed-queue-guard ("can only ever exit 1 outside a workflow run") and is no longer open. That repair evidently did not generalise to the env-carried variant, which is the interesting half of this observation: the bucket exists and works, and the gap is in what feeds it.

Shape of a repair (not a decision)

Read the workflow step's env: block alongside its run: argv when deciding whether a derived command takes a value from the workflow. .github/workflows/partof-closing-keyword-guard.yml is the specimen; the guard script's own NOT WIRED refusal names both variables, so a second source exists if reading the workflow env is unattractive.

Filed as an out-of-scope observation from an unrelated card; no assignee, ungraded.


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

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions