Skip to content

[finding] The shared transport verdicts speak check-half-states' vocabulary ("the sweep", "the board read"), and #9966 just routed them to a second caller that does neither #10156

Description

@os-zhuang

Filed unassigned by the #9966 dev seat (session session_01DdCnBGcHeufjrq7drTD3wt), out of that card's scope: #9966's declared file surface is scripts/pm/ci-failure.mjs, and this wording lives in scripts/pm/check-half-states.mjs. Duplicate search first: swept all 231 open issues for the transport / verdict / wording shapes plus a semantic search — no hit. Adjacent but distinct: #10155 (the walk's missing transport net), #9898 (this file's --self-test runs nowhere in CI).

Observed, 2026-08-20, as real output

With #9966's repo-scoped stage adopted, ci-failure.mjs now prints the shared repo-scope-refused verdict verbatim:

$ PM_SWEEP_REPO=objectstack-ai/objectui node scripts/pm/ci-failure.mjs --sha 2d3860df9aad...
ci-failure: PREREQUISITE NOT MET — the transport authenticates but repo-scoped reads are
refused — the sweep cannot list one page
...
fix: run the sweep from a container whose egress allows repo-scoped reads (CI, or
fix: the Routine seat class); in a proxy-mediated seat the board read stays on the
fix: `mcp__github__*` tools, which take a different path and do work here.
EXIT=3

ci-failure.mjs runs no sweep and reads no board — it walks check-runs, jobs and annotations for one sha. A seat that pointed it at a CI failure is told the remedy for a half-state board read.

Why it is a finding and not a defect in #9966

The classification is exactly right, the exit code is right, and ci-failure.mjsdeliberately imports the classifier rather than copying it — its header states the trade in as many words:

Classified by check-half-states.mjs's probe, which is imported rather than re-implemented: same numbers, same wording, one instrument.

So "same wording" was chosen with eyes open when there was one caller whose vocabulary it matched. What changed is only that a second caller now reaches these two strings, and its nouns are different. Nothing is wrong; one sentence is now addressed to the wrong reader.

The shape of a fix, if it is judged worth one

Only the caller knows what it is about to do, so the noun has to come from the caller — e.g. classifyTransportProbe({ ..., subject: 'the walk' }) defaulting to today's 'the sweep', touching the two verdicts that name it (repo-scope-refused, and rate-limited's how clause already parameterises this way, which is the precedent). That is a change to check-half-states.mjs and its self-test, which is why it is filed rather than ridden along.

Cheaper alternative worth weighing first: decide the verdicts should be caller-neutral prose ("this container cannot make one repo-scoped request") and drop the subject noun entirely — one edit, no parameter, no per-caller state.

Generated by Claude Code

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions