{{ message }}
Stop blaming the recipe for a turn that never came back - #9266
Merged
Conversation
`connection (codex)` fails on main and on unrelated branches, and the two
lines it prints contradict each other:
##[warning] ... judging the turn on its assertions instead of calling it guide drift.
##[error] [guide drift] agent=codex: the documented launch command exited
non-zero (rc=124) ... so the documented flow in start.py drifted.
Neither is right.
run_timed printed the warning unconditionally, but three callers
(connection, resume, attribution-ab) have no assertion that can rescue a
partial turn and treat a cap as fatal on purpose. So it promised the
opposite of what was about to happen, for exactly the callers most likely
to hit it. It now states the fact and leaves the verdict to the caller.
The error is worse, because it sends the reader to the one file that is
not implicated. The transcript shows codex launching perfectly -- correct
provider, correct model, correct profile -- and then sitting on
ERROR: Reconnecting... 1/5
for the full 600s. Nothing about the documented flow had drifted; the
model server never answered. A cap means the launch command was fine and
the turn never came back, which is a different failure with a different
owner.
Still fatal. Waiving a cap here would report "connection OK" for a recipe
that printed a banner and then blocked on a headless prompt, which is the
failure this job exists to catch, and assert_reply cannot tell a finished
reply from a startup banner. Only the attribution changes.
A non-zero exit from the launch command is still reported as drift, which
is the case guide_fail is right about.
Four static guards, since the script needs five agent CLIs and a live
model server to run. All four mutants (run_timed speaking for its callers
again, the timeout routed back through guide_fail, the timeout waived
instead of fatal, a non-zero exit no longer reporting drift) were
reintroduced and confirmed red. Wired into workflow-trigger-lint, the only
job with no paths filter.
for more information, see https://pre-commit.ci
danielhanchen
force-pushed
the
fix-agent-drive-verdict
branch
from
August 19, 2026 07:20
3981357 to
8a6edb2
Compare
The shell suite went red on this branch: 'exactly the expected TIMED_OUT
sites (got 4, want 3)'. Worth deciding which of the two was wrong rather
than moving the number.
The heading is 'only file-edit turn 1 rescues a soft timeout', and that
is the invariant worth having. The assertion under it counted every
consultation of TIMED_OUT and pinned the total at 3 -- so it conflated the
single waiver with the fatal checks beside it, and its own comment
admitted as much ('turn 1's guard, PLUS the resume and attribution-ab
fatal checks').
The fourth site this branch adds makes a cap MORE explicitly fatal at
connection. Failing a guard named for waivers because a fatal check was
added is the assertion being over-specified, not the change being wrong.
The neighbouring semantic assertions agree: 'connection guard has no
TIMED_OUT escape' passes.
So the two shapes are counted separately. The waiver is the || form and
is the only one that lets execution continue past a cap; everything else
consults TIMED_OUT to stop. That enforces the sentence rather than a
number, and keeps all the power: a waiver added anywhere still fails.
Mutation-tested against the repaired guard -- a waiver added to the
connection guard, resume's fatal check turned into a waiver, and the
connection check deleted outright are all caught. 44 pass, 0 fail.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

The two lines it prints contradict each other
connection (codex)fails on main and on unrelated branches (fix/amd-aotriton-library-gateamong them), so it is not any one PR. What it says is:Neither is right, and I believed the first one for a while before checking.
The warning.
run_timedprinted it unconditionally, but three callers (connection,resume,attribution-ab) have no assertion that can rescue a partial turn and treat a cap as fatal on purpose, which the script documents a few lines above. So it promised the opposite of what was about to happen, for exactly the callers most likely to hit it, immediately above the error that contradicts it. It now states the fact and leaves the verdict to the caller, which is the only thing it is in a position to know.The error is worse, because it sends the reader to the one file that is not implicated. The transcript shows codex launching perfectly:
Correct provider, correct model, correct profile, and then 600 seconds of reconnecting. Nothing about the documented flow had drifted; the model server never answered. A cap means the launch command was fine and the turn never came back, which is a different failure with a different owner.
What does not change
Still fatal. Waiving a cap here would report "connection OK" for a recipe that printed a banner and then blocked on a headless prompt, which is the failure this job exists to catch, and
assert_replycannot tell a finished reply from a startup banner. Only the attribution changes.A non-zero exit is still drift. That is the case
guide_failis right about, and narrowing must not swallow it.On the underlying stall
I am not claiming to have fixed
Reconnecting... 1/5. It reproduces across unrelated branches, and the script already carries a note about opencode doing the same thing on 2026-08-03 with llama-server serving nothing, described there as intermittent rather than a one-way regression. This makes the red run say what actually happened, so the next person does not spend the time I did instart.py.Verification
Four static guards. The script needs five agent CLIs and a live model server to run, so what can be pinned without them is the shape of what it says. All four mutants reintroduced and confirmed red:
Wired into
workflow-trigger-lint, the only job with no paths filter, since the edit that breaks it is a scripts or workflow edit.tests/studio: 4460 passed, 4 skipped.