🤖 fix: bind a workflow child's terminal failure to its attempt on the task row - #4672
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a23992ed71
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…ilure marker for its attempt
|
@codex review |
|
Codex Review: Didn't find any major issues. Another round soon, please! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
🛡️ Codex Security Review · Automatically triggeredSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
Summary
A workflow child that failed terminally (for example
model_refusalunderonRefusal: "fail") now fails its step after a restart, even when its failure artifact was never written.failAgentTaskTerminallyrecords an attempt-boundtaskTerminalFailuremarker on the task row in the same config write that setsinterrupted, and the attempt classifier reads it.Fixes #4579.
Background
#4577 made a workflow replace a child that ended without a report, and it recognized a terminal failure by the child's failure artifact.
upsertSubagentFailureArtifactonly logs write errors, so when that write failed the settlement receipt still appeared. A restarted process then classified the attempt as a plainterminal-no-reportand replaced a child that should have failed its step.The row's
taskLaunchErrorcan't serve as the evidence:Implementation
taskTerminalFailure?: { attemptId, errorType }on the task row (common/schemas/project.ts). It is kept on metadata writes (config/index.ts).failAgentTaskTerminally, inside the CAS that setsinterruptedandtaskLaunchError, on the attempt that CAS matched.inspectAttemptOutcome):indeterminate.failureonly when itsattemptIdequals the row's current attempt. The message comes fromtaskLaunchError, or a generic message that names theerrorType.classifyPriorAttemptandconsultFailedCheckpointalready propagatefailureinstead of replacing.Validation
failAgentTaskTerminally. Process 2 fails the step with the refusal message, makes no claim, and the original child is the only one.failure. A marker from an earlier attempt stays replaceable.addWorkspacemetadata write.config.test.ts168, Jesttests/ipc/tasks12/12,make static-checkgreen.Risks
Low. The change only moves one outcome, from replacing a terminally failed child to failing its step. Rows written before this change have no marker and behave as before.
Unchanged by this PR: failure artifacts are keyed by child, not by attempt. So an artifact left by an earlier attempt still marks a later attempt's no-report ending as a failure, as it has since #4577. That errs toward failing the step, never toward a duplicate child.
Generated with
xum• Model:anthropic:claude-opus-5-5• Thinking:high• Cost:$248.74