Skip to content

Notify on fatal Codex turn errors - #8170

Merged
lawrencecchen merged 4 commits into
mainfrom
task-codex-fatal-error-notifications
Jul 15, 2026
Merged

lawrencecchen merged 4 commits into
mainfrom
task-codex-fatal-error-notifications

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Jul 15, 2026 •

Copy link
Copy Markdown
Contributor

Fixes missing cmux notifications when Codex ends a turn with a fatal error, including model capacity failures.

The transcript parser now treats task_complete.error as authoritative even when Codex emitted partial assistant output. The regression test uses the current Codex rollout schema and verifies both the notification and high-priority error status.

Testing:

  • Swift parser checks passed
  • Xcode project test wiring lint passed
  • Focused local test build was interrupted before execution because concurrent machine-wide Xcode jobs blocked the runner; tagged cloud build and CI provide build coverage

View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.


Summary by cubic

Ensure cmux sends a notification and sets a high-priority error when a Codex turn ends with a terminal error, even if partial assistant output was emitted. Fixes missed alerts for capacity and other fatal failures.

  • Bug Fixes
    • Treat task_complete.error as authoritative; accept structured objects and plain strings.
    • Prevent pre-terminal publishes when a terminal error is present.
    • Harden CodexTerminalErrorNotificationTests with a socket-backed server; assert notify_target content and set_status (priority 100, red icon, color #FF453A).

Written for commit 2f87150. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes

    • Improved Codex terminal error handling by prioritizing the terminal error payload, ensuring overload/capacity messages are preserved and incomplete assistant output no longer overrides the failure details.
  • Tests

    • Added CodexTerminalErrorNotificationTests to verify that persisted terminal error notifications win over partial assistant output, including validation of the expected notification command and terminal error status indicators.

@cursor

cursor Bot commented Jul 15, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@coderabbitai

coderabbitai Bot commented Jul 15, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The Codex stop hook now treats terminal error payloads as authoritative failure candidates. A new integration test runs the hook against a temporary transcript and UNIX socket server, while Xcode project settings include the test in the build.

Changes

Codex terminal error handling

Layer / File(s) Summary
Terminal error candidate selection
CLI/cmux.swift
Dictionary and string values in task_complete.error create failure candidates and prevent publication before the terminal event; the existing assistant-message fallback remains.
Terminal error integration coverage
cmuxTests/CodexTerminalErrorNotificationTests.swift, cmux.xcodeproj/project.pbxproj
The serialized test launches the bundled stop hook, captures UNIX socket commands, verifies terminal error notification and status updates, and adds the test file to the Xcode target.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Transcript
  participant CodexStopHook
  participant UnixSocketServer
  CodexStopHook->>Transcript: Read task_complete payload
  Transcript-->>CodexStopHook: Return terminal error
  CodexStopHook->>UnixSocketServer: Send error notification and status
  UnixSocketServer-->>CodexStopHook: Return focused-surface response
Loading

Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (3 errors, 1 warning)

Check name Status Explanation Resolution
Cmux Swift Package Boundaries ❌ Error The diff adds pure Codex transcript/error parsing in CLI/cmux.swift, a testable domain concern; the boundary rule says that belongs in a SwiftPM package, not the app target. Extract the Codex failure parsing/summarization helpers into a small package target (e.g. CmuxCore) exposing a CodexTranscriptParser or CodexHookFailureCandidate; keep CLI wiring in cmux.swift.
Cmux User-Facing Error Privacy ❌ Error publishCodexMonitorFailure sends summary.body from candidate.message, so the new task_complete.error path can surface raw upstream text like the model-capacity message in a user alert. Map terminal errors to generic user-facing copy and keep upstream/vendor details only in internal logs or telemetry; do not use raw error.message in notifications.
Cmux Full Internationalization ❌ Error A new localized error key was added in CLI/cmux.swift, but Resources/Localizable.xcstrings only has en/ja entries for it while the catalog supports 20 locales. Add translated entries for every existing locale in Resources/Localizable.xcstrings for agent.codex.error.noFinalResponse (or avoid introducing the new user-facing key).
Description check ⚠️ Warning The description covers summary and testing, but it omits required Demo Video, Review Trigger, and Checklist sections. Add the missing template sections: Demo Video, Review Trigger block, and the checklist items, or note why they don't apply.
✅ Passed checks (21 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed PASS: production diff is pure synchronous parser logic; no new MainActor/Sendable/service-protocol isolation issues. The only @unchecked Sendable is a locked test helper.
Cmux Swift Blocking Runtime ✅ Passed Blocking primitives appear only in the new test-only socket/process scaffolding; no shipped Swift path adds waits, sleeps, or locks.
Cmux Browser Automation Off-Main ✅ Passed PR only touches the Codex error-notification test; it does not modify the browser routing files or any browser.* socket-worker/mainActor command paths.
Cmux Expensive Synchronous Load ✅ Passed The patch only changes error precedence inside existing readCodexTranscriptFailure; it adds no new disk/JSON load or RestorableAgentSessionIndex.load() on an interactive path.
Cmux Cache Substitution Correctness ✅ Passed The diff prioritizes authoritative task_complete.error over fallback assistant output; it does not replace a fresh read with a cached/opportunistic value in a persistence path.
Cmux No Hacky Sleeps ✅ Passed Only a new Swift test file changed; no TS/JS/shell/build/runtime files or hacky sleeps were added, so the runtime no-sleeps rule isn’t applicable.
Cmux Algorithmic Complexity ✅ Passed The only current diff is a test file, and the terminal-error parsing path uses single-pass line iteration with O(1) payload lookups—no nested rescans or sorting/filtering.
Cmux Swift Concurrency ✅ Passed PASS: The only new DispatchQueue.async usage is in test-only socket/process helpers, which the rule allows; cmux.swift change is synchronous parsing only.
Cmux Swift @Concurrent ✅ Passed No new @concurrent issues: the PR adds only synchronous Swift logic/tests, and the background queue work in the test isn’t UI-isolated or missing an actor hop.
Cmux Swiftpm Lockfiles ✅ Passed Diff only adds a test; no Package.swift, Package.resolved, .gitignore, workflow, or Xcode package-reference changes are present.
Cmux Swift Logging ✅ Passed The Codex parser diff adds only branching/comments; grep found no new print/debugPrint/dump/NSLog/Logger in production changes, and the new test file adds no logging.
Cmux Swiftui State Layout ✅ Passed Diff only adds a non-UI test file; no new ObservableObject, GeometryReader, lazy-row store refs, or render-time state writes were introduced.
Cmux Architecture Rethink ✅ Passed Production fix is a small parser invariant change; the only locks/dispatch/semaphores are confined to test-only synchronization, which the rule allows.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed HEAD only changes a test file; no user-visible NSWindow/NSPanel/WindowGroup code or cmuxAuxiliaryWindowIdentifiers changes, so the rule doesn’t apply.
Cmux Source Artifacts ✅ Passed The only changed path is a hand-written Swift test in cmuxTests; no artifact, cache, build, or temp directory is added to source control.
Cmux No Test Or Debug Seam In Production Source ✅ Passed No Sources/** production file changed; the PR only updates CLI/cmux.swift, project wiring, and a test file, so the rule doesn’t trigger.
Cmux No Ambient Global State ✅ Passed No new ambient-global-state surface: the production change stays inside an existing private method, and test helpers are scoped types, not globals.
Title check ✅ Passed The title clearly summarizes the main change: notifying on fatal Codex turn errors.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch task-codex-fatal-error-notifications

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 15, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes missed cmux notifications when a Codex turn ends with a fatal error (e.g., model capacity exceeded) that is embedded in task_complete.error alongside partial last_agent_message output. Previously, the last_agent_message branch ran first and cleared the error candidate, so the user received no notification.

  • Production fix (CLI/cmux.swift): Inserts two new branches before the last_agent_message check in the task_complete/turn_complete handler — one for structured dict errors (via codexHookFailureCandidate) and one for plain string errors (via codexHookStringValue) — and sets candidateCanPublishBeforeTerminal = false in both to ensure the error is surfaced after the terminal event.
  • Regression test (cmuxTests/CodexTerminalErrorNotificationTests.swift): Launches the real CLI binary against a mock socket and a crafted JSONL transcript, asserting notify_target and set_status --priority=100 --color=#FF453A commands are emitted; covers only the structured-dict error path.
  • Xcode project (cmux.xcodeproj/project.pbxproj): Wires the new test file into the test target build phases.

Confidence Score: 5/5

Safe to merge — the production change is a targeted fix that correctly adds error extraction before the assistant-message branch, and the regression test validates the primary failure scenario end-to-end.

The core logic change is small and well-scoped: two new else-if branches in the task_complete handler that fire only when payload error is present, with the existing last_agent_message path preserved as a fall-through. The return-value logic is unaffected for all pre-existing cases. The test spawns the real CLI binary and confirms the notification and status commands, making the regression coverage meaningful.

The string-error branch in CLI/cmux.swift (the else-if codexHookStringValue path) has no corresponding test in cmuxTests/CodexTerminalErrorNotificationTests.swift.

Important Files Changed

Filename Overview
CLI/cmux.swift Adds three-branch error extraction to the task_complete/turn_complete handler: structured dict, plain string, then existing last_agent_message fallback. Logic is correct — the terminal error is authoritative and properly blocks pre-terminal publishing.
cmuxTests/CodexTerminalErrorNotificationTests.swift New regression test verifying dict-form task_complete.error generates a notify_target and set_status --priority=100 command; the string-error branch (second else-if) has no coverage, leaving that path unvalidated.
cmux.xcodeproj/project.pbxproj Registers CodexTerminalErrorNotificationTests.swift in the test target build-file and file-reference lists — straightforward Xcode project wiring with no structural issues.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["Transcript line: task_complete / turn_complete"] --> B{"payload.error\nis a dict?"}
    B -->|Yes| C["codexHookFailureCandidate\nrequireFailureSignal=false"]
    C --> D["candidate = structured failure\ncandidateCanPublishBeforeTerminal = false"]
    B -->|No| E{"payload.error\nis a string?"}
    E -->|Yes| F["candidate = string failure\ncandidateCanPublishBeforeTerminal = false"]
    E -->|No| G{"last_agent_message\nnon-empty?"}
    G -->|Yes| H["sawAssistantMessage = true\ncandidate = nil"]
    G -->|No| I{"candidate==nil AND\nnot sawAssistantMessage?"}
    I -->|Yes| J["candidate = no-final-response error"]
    I -->|No| K["no change"]
    D --> L["return .failure(candidate)"]
    F --> L
    H --> M["return .healthy"]
    J --> L
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A["Transcript line: task_complete / turn_complete"] --> B{"payload.error\nis a dict?"}
    B -->|Yes| C["codexHookFailureCandidate\nrequireFailureSignal=false"]
    C --> D["candidate = structured failure\ncandidateCanPublishBeforeTerminal = false"]
    B -->|No| E{"payload.error\nis a string?"}
    E -->|Yes| F["candidate = string failure\ncandidateCanPublishBeforeTerminal = false"]
    E -->|No| G{"last_agent_message\nnon-empty?"}
    G -->|Yes| H["sawAssistantMessage = true\ncandidate = nil"]
    G -->|No| I{"candidate==nil AND\nnot sawAssistantMessage?"}
    I -->|Yes| J["candidate = no-final-response error"]
    I -->|No| K["no change"]
    D --> L["return .failure(candidate)"]
    F --> L
    H --> M["return .healthy"]
    J --> L
Loading

Reviews (2): Last reviewed commit: "Harden Codex error notification test" | Re-trigger Greptile

Comment thread CLI/cmux.swift

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmuxTests/CodexTerminalErrorNotificationTests.swift`:
- Around line 11-13: Update the temporary socket setup around root and
socketPath to use a deliberately short directory and socket filename, then
validate the socketPath’s UTF-8 byte length against sockaddr_un.sun_path before
binding. Reject oversized paths explicitly before bind, and ensure the exact
validated path is passed to both the server and hook.
- Around line 244-252: The timeout handling around process.terminate() must
remain bounded and avoid reading pipes from a still-running process. After the
initial one-second wait, escalate termination if needed, confirm completion
before accessing terminationStatus or performing readDataToEndOfFile(), and
return a safe timeout result when completion cannot be confirmed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8028de85-a43f-483c-a75f-a1a0d12084ad

📥 Commits

Reviewing files that changed from the base of the PR and between ace9cc8 and cb1cae5.

📒 Files selected for processing (3)
  • CLI/cmux.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/CodexTerminalErrorNotificationTests.swift

Comment thread cmuxTests/CodexTerminalErrorNotificationTests.swift Outdated
Comment thread cmuxTests/CodexTerminalErrorNotificationTests.swift
@lawrencecchen
lawrencecchen merged commit e3cba0e into main Jul 15, 2026
16 checks passed
@lawrencecchen
lawrencecchen deleted the task-codex-fatal-error-notifications branch July 15, 2026 22:18
hhsw2015 pushed a commit to hhsw2015/cmux that referenced this pull request Jul 16, 2026
* Add regression test for Codex terminal errors

* Notify on Codex terminal errors

* Harden Codex error notification test

(cherry picked from commit e3cba0e)
@lawrencecchen
lawrencecchen restored the task-codex-fatal-error-notifications branch July 18, 2026 10:19
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.

1 participant