Skip to content

feat(review-leg): put the build in front of the reviewer (#613) - #614

Merged
BaseInfinity merged 5 commits into
mainfrom
fix/613-ci-status-precondition
Aug 15, 2026
Merged

feat(review-leg): put the build in front of the reviewer (#613)#614
BaseInfinity merged 5 commits into
mainfrom
fix/613-ci-status-precondition

Conversation

@BaseInfinity

Copy link
Copy Markdown
Owner

Closes #613.

The failure this closes

PR #610 ran eight review rounds with two independent reviewers while CI validate was red the entire time. Both ran the suites directly and correctly reported them green — the failing guard was one nobody was asked about. scripts/merge-pr.sh caught it at the merge.

That is "a gate step discovered mid-merge", which #593 Rung 1's stop condition names in so many words. Both reviewers prescribed the same fix independently:

Seven rounds audited the diff; zero audited the build — that is the whole fix.

Both priority rulings then made this Rung 1 item 3, ahead of #521, as closing an observed stop-condition failure rather than discretionary re-planning.

What it does

The launcher writes a ## CI STATUS block into the leg's output file before exec'ing codex, so the build is stated where the reviewer reads and ahead of the model's own output. The block carries the contract sentence: a certification verdict issued over a build that is not green, or not determinable, is only valid if it says so and says why.

Preflight, never a gate

A red build is reported and the leg proceeds. Deliberate, and the harder half of the design: a leg must stay launchable against known-red CI when that is the point, and a preflight that can refuse to launch is a second way for a review not to happen — the failure #590 exists to prevent. Every probe failure mode (no gh, no auth, no network, no PR for the branch) records UNKNOWN and the review runs. The probe gets < /dev/null for the same reason the exec line does.

What the suite caught that review would not have

The first version wrapped the probe in timeout 30. This machine has neither timeout nor gtimeout — GNU coreutils, not stock macOS. Every probe would have reported UNKNOWN, forever, silently, on the maintainer's own laptop: this issue's exact failure mode reintroduced by its own fix. Found by a test written RED before the code.

No new guard

tests/test-workflow-triggers.sh already catches the drift that broke #610 and always did. The gap was invocation, not coverage — so this adds no guard, and modifies two existing surfaces (the launcher, its suite). That keeps it inside #593's "no new guard or tooling surface" standing ruling.

Verification

  • tests/test-run-review-leg.sh 16/0 (12 → 16 rows), RED first on all four new assertions
  • shellcheck clean on both files

PR #610 ran EIGHT review rounds with two independent reviewers while CI
validate was red the entire time. Both reviewers ran the test suites directly
and correctly reported them green — the guard that was failing was one nobody
was asked about, and the merge gate is what finally caught it.

That is "a gate step discovered mid-merge", which #593 Rung 1's stop condition
names as a failure in so many words. Both reviewers then prescribed the same
fix independently, and it is not more diff scrutiny:

    Seven rounds audited the diff; zero audited the build.

So the launcher states the build where the reviewer reads, ahead of the model's
own output, with the sentence that makes it binding: a certification verdict
issued over a build that is not green, or not determinable, is only valid if it
says so and says why.

PREFLIGHT, NEVER A GATE

A red build is REPORTED and the leg proceeds. That is deliberate and it is the
harder half of the design: a leg must stay launchable against known-red CI when
that is the point, and a preflight that can refuse to launch is a second way for
a review not to happen — the exact failure #590 exists to prevent. Every probe
failure mode is absorbed the same way: no gh, no auth, no network, no PR for
this branch each record UNKNOWN, and the review runs.

The probe gets `< /dev/null` for the same reason the exec line does. A preflight
that can hang would have reintroduced #590 in the one place nobody would think
to look.

WHAT THE SUITE CAUGHT THAT REVIEW WOULD NOT HAVE

The first version wrapped the probe in `timeout 30`. This machine has neither
`timeout` nor `gtimeout` — they are GNU coreutils, not stock macOS. Every probe
would have reported UNKNOWN, forever, silently, on the maintainer's own laptop:
this issue's exact failure mode, reintroduced by its own fix. It is now used
when present and skipped when not.

Found by a test written RED before the code, not by a reviewer. That is the
whole argument for the four assertions.

test-run-review-leg 12 -> 16 rows, RED first on all four. shellcheck clean.
Round 1 returned NOT CERTIFIED 6/10 with one blocker, and it was a real
reintroduction of the failure this launcher exists to prevent.

THE CLAIM WAS MINE AND IT WAS WRONG

The probe fell back to running `gh` bare when neither `timeout` nor `gtimeout`
was present — stock macOS, this machine included — and a comment justified it:
"gh carries its own network timeouts."

I never checked. The reviewer did, and cited the source: gh 2.92 configures no
overall HTTP timeout (cli/cli api/http_client.go, go-gh
pkg/api/client_options.go). A stalled request blocks before `exec codex` ever
runs. That is #590 — a review leg waited on instead of owned — reintroduced by
the preflight added to prevent a different failure. The suite missed it because
its stub always exited.

So the deadline is now this script's own and depends on nothing. The probe runs
in the background writing its exit status to a marker file; a bounded poll
abandons it and records UNKNOWN. A marker rather than `kill -0` on the pid,
because a background job of this shell stays a zombie until waited on and
`kill -0` would report it alive after it finished; `wait -n` would do it but
needs bash 4 and macOS ships 3.2.

A SECOND DEFECT, FOUND WHILE FIXING THE FIRST

The probe subshell inherits `set -e`. A non-zero `gh` — which is precisely what
a RED BUILD is — killed it before it wrote its marker. Every red build would
have looked stalled, burned the full deadline, and reported "abandoned": the
one case this feature exists to report, reported wrong.

Found by the red-build row regressing, not by reading the code back. `set +e`
inside the subshell, and a comment saying why it is load-bearing.

THE RED WAS THE LOUDEST KIND

Running the new stalled-probe row against the unfixed launcher hung the test
suite itself for 120 seconds. The defect reproduced rather than argued.

The reviewer also answered the question the prompt asked it: the CI STATUS
block is "useful, not noise... prominent, concise, includes the failing check's
raw output, and correctly precedes the review verdict."

test-run-review-leg 16 -> 20 rows, all green. shellcheck clean.
Round 2 returned NOT CERTIFIED 6/10 with one blocker, and it falsified a second
unverified claim of mine in as many rounds.

The timeout path killed CI_PROBE_PID. That is the SUBSHELL, not `gh`. Killing
it left `gh` running, reparented to PID 1. My own known_limits had said the
orphan "exits on its own" — I never checked, and a genuinely stalled request
never does. The reviewer ran the real 120-second fixture and watched both the
probe and its child survive the leg that started them. Repeated timeouts would
leak processes, descriptors and connections until a later leg could not launch:
the failure this launcher exists to prevent, arriving by a third route.

THE FIX IS `set -m`, AND IT IS LOAD-BEARING

Without job control a backgrounded subshell shares this shell's process group,
so the only thing addressable by pid is the subshell itself. With `set -m` it
leads its own group, and the timeout path can TERM then KILL the NEGATIVE pid —
subshell, `gh`, and anything `gh` spawned — then `wait` to reap.

If a future edit drops `set -m`, the negative-pid kill silently degrades to
killing the subshell alone and the leak returns. That is now in known_limits,
and the suite's new row is what would catch it.

THE ROW PROVES DEATH, NOT ABSENCE

The stub records its own pid; the test asserts that pid is gone afterwards. Run
against the unfixed launcher it names the survivor by number. Asserting the leg
finished quickly would have passed on the broken version — the leg did finish,
that was never the defect.

THREE ROUNDS, THREE CLAIMS I DID NOT CHECK

Round 1: "gh carries its own network timeouts" — false, gh sets none.
Round 2: the red-build path, where `set -e` killed the probe before it could
report — caught by my own suite.
Round 3: "the orphan exits on its own" — false.

Each was a sentence written to justify a shortcut. Filed as #617.

test-run-review-leg 20 -> 21 rows, all green. shellcheck clean.
Round 3 split 10/10 and 9/10-at-90%. The second reviewer ran its own stall
repro rather than reading the diff, and found two things neither the first
reviewer nor the suite had. Neither meets the blocking bar; both are defects in
the feature this PR exists to deliver, and 90% is below the merge gate's 95%.

THE NOTICE LANDED IN THE BLOCK IT WAS MAKING READABLE

On the abandoned-probe path, bash announces the kill:

    ./scripts/run-review-leg.sh: line 193: 34945 Terminated: 15  ( set +e; gh …

That goes to the reviewer's own output file, inside the CI STATUS block,
exposing this script's internal command line. The whole point of the block is
that a reviewer reads it first; shipping shell noise into it undercuts that.

`disown` after `set +m`. The group kill still works — it addresses the process
group, not the job table — and the existing `wait ... || true` absorbs the
disowned-job error.

THE SUITE WAS NOT HERMETIC, AND SAID NOTHING ABOUT IT

The `gh` stub was installed beside the tests that drive it, in section 7. Every
test before that ran the launcher against the REAL `gh`: live API calls from a
unit suite, with behaviour depending on the network and on whether the current
branch happens to have a PR. Tests 1-6 were measuring something other than what
they claimed, and passed anyway.

Stub hoisted above test 1.

Worth naming the pattern: this is the third defect on this PR found by running
the thing rather than reading it, and the second found only because a reviewer
built its own repro instead of trusting the suite. The suite is the artifact
that says whether the code works, and it was itself wrong about its own
isolation.

test-run-review-leg 21/0, hermetic throughout. shellcheck clean.
Round 4 cleared at 96%, above the gate bar, with one note the reviewer chose to
defer: the `disown` fix it had just verified carried no regression assertion.
Delete `disown` and the suite stayed 21/21 green, because nothing asserted on
the reviewer-facing output. The fix was guarded by a human running a repro.

Taken rather than deferred. A fix with no test is the pattern this repo's own
rules exist to stop, and the other reviewer's clearance was already stranded by
round 4's commit, so the round was owed whatever else changed — the assertion
costs one row on a leg that had to run anyway.

PROVEN BY MUTATION, not by reading:

    with `disown`        22 passed, 0 failed
    `disown` removed     21 passed, 1 failed  <- exactly the new row
    restored             22 passed, 0 failed

That is the difference between a test and a comment. The row greps the leg's
own output file for a shell job notice, which is what leaked: bash announcing
"Terminated: 15  ( set +e; gh pr checks …" inside the CI STATUS block, exposing
the launcher's internals in the one block this PR exists to make readable.

Also fixes the reviewer's cosmetic note: a comment introducing the gh stub as
though it were defined below it, 130 lines after the stub moved to the top of
the file to make the earlier tests hermetic.

test-run-review-leg 21 -> 22 rows. shellcheck clean.
@BaseInfinity

Copy link
Copy Markdown
Owner Author

CROSS-MODEL-CLEARANCE

{"confidence": 99, "reviewer": "sol", "sha": "7ed0aa7f2df851b0a0079898ddf2fb361166b65d", "verdict": "YES"}

Round 5. CERTIFIED — 10/10 — confidence 99%. No findings.

  • Delta contains only the disown fix, the hermetic gh stub hoist, the regression assertion, and the comment correction.
  • Targeted suite 22/0; shellcheck clean under macOS Bash 3.2.
  • Mutation reproduced independently: without disown, exactly 21/1 on the shell-notice assertion.
  • Instrumented process-group test 23/0 — probe and descendant killed, no hang, no survivors.
  • Stub active before test 1; no live gh calls.
  • Codex exit status unchanged. Head confirmed 7ed0aa7, validate passed, merge state CLEAN.

@BaseInfinity

Copy link
Copy Markdown
Owner Author

CROSS-MODEL-CLEARANCE

{"confidence": 97, "reviewer": "fable", "sha": "7ed0aa7f2df851b0a0079898ddf2fb361166b65d", "verdict": "YES"}

Round 5, independent leg. CERTIFIED — 9/10 — confidence 97%.

Delta touches exactly one file (tests/test-run-review-leg.sh, +17/−3). scripts/run-review-leg.sh is byte-identical to the previously certified commit, so none of the four blocking criteria can have moved — they all live in a file with zero delta.

Mutation reproduced by hand, not taken from the submitter's numbers: HEAD 22/0 → disown neutralized 21/1, the sole red row being the new assertion → restored 22/0. The assertion discriminates on exactly the behaviour it claims to guard. The round-4 deferred note is closed.

CI validate pass on headRefOid = 7ed0aa7 — green on the exact SHA certified, not a stale one. Shellcheck clean. Working tree clean after the mutation round-trip.

No new findings. The delta strictly strengthens the guarded surface — it converts a manual-repro-only guard into a suite assertion at the cost of one test row. Five rounds is enough and this PR is done.

@BaseInfinity
BaseInfinity merged commit cdb8d4d into main Aug 15, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Review legs certify over a red build: make CI status a precondition, not more diff scrutiny

1 participant