Skip to content

🤖 fix: bind a workflow child's terminal failure to its attempt on the task row - #4672

Merged
ThomasK33 merged 2 commits into
mainfrom
g2/pr-terminal-failure-marker
Sep 26, 2026
Merged

ThomasK33 merged 2 commits into
mainfrom
g2/pr-terminal-failure-marker

Conversation

@ThomasK33

Copy link
Copy Markdown
Member

Summary

A workflow child that failed terminally (for example model_refusal under onRefusal: "fail") now fails its step after a restart, even when its failure artifact was never written. failAgentTaskTerminally records an attempt-bound taskTerminalFailure marker on the task row in the same config write that sets interrupted, 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. upsertSubagentFailureArtifact only logs write errors, so when that write failed the settlement receipt still appeared. A restarted process then classified the attempt as a plain terminal-no-report and replaced a child that should have failed its step.

The row's taskLaunchError can't serve as the evidence:

  • Nothing clears it when a new attempt starts.
  • Stop-driven reservation cancellations write it as well.

Implementation

  • Schema: taskTerminalFailure?: { attemptId, errorType } on the task row (common/schemas/project.ts). It is kept on metadata writes (config/index.ts).
  • Writer: only failAgentTaskTerminally, inside the CAS that sets interrupted and taskLaunchError, on the attempt that CAS matched.
  • Classifier (inspectAttemptOutcome):
    • A failure artifact found by the existing strict read still wins, and an unreadable artifact is still indeterminate.
    • Otherwise, the marker sets failure only when its attemptId equals the row's current attempt. The message comes from taskLaunchError, or a generic message that names the errorType.
    • A marker left by an earlier attempt is ignored, so no clearing is needed when the attempt rotates.
  • Runner: no change. classifyPriorAttempt and consultFailedCheckpoint already propagate failure instead of replacing.

Validation

  • Bun.spawn restart variant "refused-artifact-lost": process 1 blocks the parent's artifact path so the write fails, then runs the real failAgentTaskTerminally. Process 2 fails the step with the refusal message, makes no claim, and the original child is the only one.
  • Fresh-process classifier: a marker on the current attempt with no artifact gives failure. A marker from an earlier attempt stays replaceable.
  • Config round trip: the marker survives a reload and an addWorkspace metadata write.
  • Mutation checks, each caught: removing the writer, ignoring the marker in the classifier, dropping the attempt binding, and dropping the round-trip copy.
  • Local runs: taskService suites 987, workflow suites 362, config.test.ts 168, Jest tests/ipc/tasks 12/12, make static-check green.

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

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-26T11:21:48.027232Z d2a22cb Manual request
🔒 Security Review ✅ Completed 2026-09-26T11:22:32.668485Z d2a22cb Manual request
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread src/node/services/taskService.ts Outdated
@ThomasK33

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Another round soon, please!

Reviewed commit: d2a22cb8ce

ℹ️ 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".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: d2a22cb8ce

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@ThomasK33
ThomasK33 added this pull request to the merge queue Sep 26, 2026
Merged via the queue into main with commit 670812f Sep 26, 2026
31 checks passed
@ThomasK33
ThomasK33 deleted the g2/pr-terminal-failure-marker branch September 26, 2026 11:36
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.

🤖 fix: bind a workflow child's terminal failure to its attempt on the task row

1 participant