Repository navigation
fix(codex): crash a turn codex ended as failed instead of grading it - #230
Merged
Merged
Conversation
Codex delivers a normal turn/completed when it gives up on the provider, with turn.status == failed and a TurnError (for example rateLimitExceeded after its own stream retries ran out). The harness never read that status, so the turn booked as COMPLETED and the row was graded FAILURE on work the provider had cut off. In adhoc-2026-10-21_16-16-27 (codex, gpt-5.6-luna) 27 rows (11 v1, 16 v2) ended this way, after 0 to 39 commands, and read as skill failures in the v1-vs-v2 comparison. The turn now crashes with the provider's message, the same way Pi and OpenCode already treat a terminal provider error. categorize_error routes the "rate limit exceeded" text to AGENT_RATE_LIMIT and its retry budget; when retries run out the row lands as ERROR. The partial turn keeps its commands and provider_errors. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013fePq8hgqbtNvf2pNvA3WC
tmatup
requested review from
CarlesUIPath,
akshaylive,
bai-uipath and
uipreliga
as code owners
October 21, 2026 20:36
|
Claude finished @tmatup's task in 1m 37s —— View job Code Review in Progress
|
|
Claude finished @tmatup's task in 1m 33s —— View job Code Review in Progress
|
Member
Author
|
CI triage. Short version: neither red check comes from this PR's diff, which only touches
Why local The Claude Code Review run ended with |
Member
Author
bai-uipath
approved these changes
Oct 21, 2026
1 of 2 tasks
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.

Bottom line
When codex gives up on the model provider (for example a rate limit it will not retry), the codex harness now crashes the turn instead of grading it. The row ends as
ERROR(orTIMEOUTif the retry backoff outrunstask_timeout) instead ofFAILURE. Before this, provider outages looked like skill regressions.What was wrong
Codex does not raise when it gives up. It sends a normal
turn/completedwhose turn hasstatus: failedand aTurnError:on_turn_completedaccepted any validTurnCompletedNotification, and_communicate_turnnever readturn.status. So the turn booked asCOMPLETED, the criteria ran on a half-done workspace, and the row wasFAILURE. #203 recorded theerrornotifications inprovider_errors, but nothing acted on them.Evidence: run
adhoc-2026-10-21_16-16-27(codex, gpt-5.6-luna, Maestro case v1 vs v2):rateLimitExceededwithwill_retry=false.FAILURE(8 v1, 13 v2); the other 6 scoredSUCCESSdespite the cut. For example,v2/skill-case-diagnose-formal-arg-slot-idsscored 0.0 with 0 commands.The fix
_communicate_turnchecks the committed Turn. Ifstatus == failedand the pump did not stop on purpose (early stop or turn cap), it calls_finalize_and_raise_crashwithCodex turn failed: <provider message> (codexErrorInfo=<kind>)..claude/notes/agents.md§ Why a clean exit can still be a crash). The note now covers Codex as well.provider_errors[].will_retry. A turn that fails without anerrornotification is caught too.categorize_errormaps therate limit exceededtext toAGENT_RATE_LIMIT, which retries 5 times starting at a 60 s delay. If the retries run out, the row ends asERROR. With a 2400 stask_timeout, the task watchdog may fire first, which givesTIMEOUT. Both are execution-fact statuses, not graded verdicts.commandsandprovider_errors, and post-failure criteria still run on it._codex_error_kindnow parsescodexErrorInfofor bothProviderErrorand the crash message.ProviderErroroutput is unchanged.Reporting is unchanged on purpose.
RunSummary.pass_ratecountsERRORrows as misses and reportserror_shareseparately. That is the existing convention, so this PR leaves it alone.Tests
New
TestFailedTurnIsACrashintests/test_codex_agent.py. It replays the real notification shape from the run above: 5responseStreamDisconnectederrors withwill_retry=true, then onerateLimitExceededwithwill_retry=false, then afailedturn. It covers:AgentCrashError, with 0 commands and with 4 commands;AGENT_RATE_LIMIT;Without the fix, 4 of the 5 new tests fail. The negative control passes either way.
make verifypasses: ruff, pyright with 0 errors, custom lint, and 6392 passed / 3 skipped.🤖 Generated with Claude Code
Co-Authored-By: Claude