Skip to content

Settle auto-resolved Codex approval notifications - #10019

Closed
austinywang wants to merge 71 commits into
mainfrom
issue-10017-codex-autoapprove-notify-swarm
Closed

austinywang wants to merge 71 commits into
mainfrom
issue-10017-codex-autoapprove-notify-swarm

Conversation

@austinywang

@austinywang austinywang commented Aug 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Stage Codex approval notifications behind a cancellable 100 ms settle window, including journal-owned native hook and Feed notifications.
  • Suppress approvals with validated effective auto_review evidence; correlate tool completion and turn resolution so promptly resolved requests do not produce a banner.
  • Coalesce unresolved requests per pane without allowing stale completions, unrelated notifications, or pane moves to erase a newer approval.
  • Preserve bounded compatibility for ID-less hooks, while sharing trusted native-ID extraction across generic hook and Feed transports.

Fixes #10017 without regressing #9592. The earlier portal-tracker revert is already in main and is not part of this PR's current net diff.

Behavior and trade-offs

  • Older Codex hooks do not expose an authoritative post-review pending signal. The one-shot 100 ms settle is a fallback, not proof of the eventual reviewer outcome: an unknown-policy approval still pending beyond that window can notify. Validated effective auto-review evidence suppresses the request without waiting.
  • Native IDs use journal-owned lifecycle and receipts. ID-less hooks use a bounded canonical tuple and converge on the same coordinator. A completion-only provider ID carries a same-scope tuple fallback in one clear mutation; it cannot clear a different live native request or a replayed request.
  • Repeated same-source derived observations remain ambiguous. Their coalesced prompt intentionally stays visible until scope resolution rather than risking silently clearing a genuine pending approval.
  • Generation changes fence lifecycle disposal/clears, not ordinary request completion, first use, or a stage's newer workspace claim. Admission and generation capture are atomic.
  • Shared hook-state lookups are read-only; only exclusive writers recover/quarantine corrupt state. Tool arguments cannot supply provider identity.
  • Cloud verification disables only the optional development backend because its DNS host is unavailable. This terminal-notification work does not claim web, authentication, or mobile verification.

Verification

Validation results and exact tested SHAs are maintained in the single review-audit comment, including the historical test-only regression replays. Expanded hosted tests exercise the built CLI and captured socket frames, not source-text expectations. Runtime dogfood and visual evidence must be completed on the current full-branch-tagged build before self-merge.

Localization and scope

Audited the modified user-facing text: the existing English/Japanese clear_notifications help entry lists the approval selectors alongside the existing correlation selector. No new UI copy, web message keys, iOS files, or mobile behavior are introduced by this PR's net diff.


Summary by cubic

Codex PermissionRequest events no longer show an approval banner immediately. They now pass through a short, cancellable settle window, so auto-approved or denied requests stay silent while unresolved approvals remain visible; matching completions clear only their request. Fixes #10017 without regressing #9592.

  • Derives opaque approval IDs from session, turn, tool, and input, preserving provider IDs and fencing derived collisions.
  • Coalesces overlapping requests per pane while protecting newer stages from stale completions, dismissals, and retired surfaces.
  • Suppresses matching auto_review banners while retaining feed telemetry; settling also covers journal-owned notifications and hooks without a shared native ID, while non-Codex, legacy, and ambiguous routes keep existing behavior.
  • Adds clear_notifications --approval-id=... and --approval-scope=... without changing existing selectors.
  • Hardens Codex hooks with atomic transcript reads, read-only lookups, corrected shell quoting, and cleanup only during explicit hooks codex install, and makes watchdog cleanup deterministic.
  • Runs Codex hook wire regressions against the built CLI in CI with a SIGPIPE-safe test-runner guard.

Written for commit 054e7bc. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Added correlated approval notifications for permission requests.
    • Approval prompts appear after a brief settling period and combine multiple pending requests into one notification.
    • Completing or canceling an approval resolves only the matching prompt, with support for resolving an entire approval scope.
    • Automatically reviewed approvals no longer generate user-attention notifications.
    • Added targeted approval resolution options while preserving existing notification-clearing behavior.
  • Tests

    • Added comprehensive coverage for approval delivery, resolution, coalescing, ordering, and cancellation.

Note

High Risk
Changes core notification delivery, clearing semantics, and hook I/O for Codex approvals; incorrect correlation or settle logic could silence real prompts or leave stale banners.

Overview
Codex permission notifications no longer fire immediately. The CLI derives stable approval correlation IDs (provider call IDs or hashed session/turn/tool/input tuples) and embeds them in notification meta and clear_notifications (--approval-id, --approval-scope, optional fallback). The app adds AgentApprovalNotificationCoordinator, which stages requests behind a short settle window, skips delivery when auto-review is proven from Codex rollout context, and resolves or scope-clears only the matching prompt so stale completions cannot wipe newer blockers.

Feed and hook paths share the same identity: feed attention commands emit correlated notify/clear lines; generic Codex hooks skip banners for auto_review, use approval meta when identity exists, clear on post-tool-use and Stop (scope), and avoid deduping correlated raises. Journal / notify_target_async routes needs-permission Codex events through the coordinator when meta carries the digest-shaped approval id.

Supporting hardening: bounded Codex hook stdin and transcript tail reads (O_NOFOLLOW, fixed read window), read-only shared lock for hook session lookups, safer fire-and-forget shell watchdog, and conservative Codex hook script GC during explicit install only.

Reviewed by Cursor Bugbot for commit e0c03c7. Bugbot is set up for automated code reviews on this repo. Configure here.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The change adds stable Codex approval identities and routes approval notifications through coordinated delivery and resolution. It suppresses automatic approvals, correlates completion events with prompts, supports ID and scope clearing, and adds deterministic lifecycle and regression tests.

Changes

Correlated approval notification flow

Layer / File(s) Summary
Approval identity and review routing
CLI/AgentHookNotificationPolicy.swift, CLI/FeedEventClassifier.swift, Sources/AgentApprovalCorrelationID.swift, Sources/AgentNotificationGate.swift
Approval metadata now carries validated IDs. Codex payloads derive stable scope and approval identities. Reviewer routing distinguishes user approvals from automatic review.
Codex policy and event integration
CLI/cmux.swift, CLI/FeedEventClassifier.swift, Sources/AgentNotificationDelivery.swift, Sources/TerminalController.swift, cmuxTests/CLICodexHookTimeoutRegressionTests.swift, cmuxTests/FeedEventClassificationTests.swift, tests/test_codex_permission_prompt_notification.py
Automatic approvals no longer produce user-attention notifications. Permission prompts and tool completions use matching approval identities.
Approval coordination and lifecycle
Sources/AgentApprovalNotificationCoordinator.swift, Sources/TerminalNotificationQueue.swift, Sources/TerminalNotificationLiveRetargetDelivery.swift, Sources/TerminalNotificationStore.swift, cmux.xcodeproj/project.pbxproj
The coordinator stages requests, applies a settle window, coalesces pane notifications, resolves IDs or scopes, and cancels pending state. Notification storage and delivery preserve correlation keys.
Lifecycle and metadata validation
cmuxTests/AgentNotificationGateTests.swift
Tests cover metadata parsing, scheduling, resolution, cancellation, ordering, duplicate approvals, and automatic-review suppression.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

Suggested reviewers: lawrencecchen

Sequence Diagram(s)

sequenceDiagram
  participant CodexHook
  participant FeedEventClassifier
  participant AgentApprovalNotificationCoordinator
  participant TerminalNotificationQueue
  participant TerminalNotificationStore
  CodexHook->>FeedEventClassifier: classify permission request
  FeedEventClassifier->>AgentApprovalNotificationCoordinator: stage approval identity
  AgentApprovalNotificationCoordinator->>TerminalNotificationQueue: deliver correlated notification
  TerminalNotificationQueue->>TerminalNotificationStore: store correlation key
  CodexHook->>FeedEventClassifier: process matching tool completion
  FeedEventClassifier->>TerminalNotificationQueue: resolve approval ID
  TerminalNotificationQueue->>TerminalNotificationStore: clear correlated notification
Loading

Important

Pre-merge checks failed

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

❌ Failed checks (5 errors, 1 warning)

Check name Status Explanation Resolution
Cmux Swift Blocking Runtime ❌ Error Production-targeted AgentApprovalNotificationCoordinator adds a default Task.sleep(for:) settle timer (0.1 s), an explicitly disallowed timing primitive in non-test Swift. Replace Task.sleep with a cancellation-aware timer or an explicit approval-resolution/state-transition signal that owns the settle behavior without production sleeping.
Cmux Expensive Synchronous Load ❌ Error The PR adds synchronous transcript-tail FileHandle reads and JSONL parsing in Codex approval hook paths, plus a new session-store JSON decode lookup in runFeedHook, without a cache or background pa... Move rollout/session-store access to a cached or detached background parser and return only the reviewer result/transcript path to the hook path.
Cmux Algorithmic Complexity ❌ Error Sources/AgentApprovalNotificationCoordinator.swift rescans unbounded candidate and tombstone collections on approval events (lines 95, 129-145, 222, 264-287), creating O(N²) notification-path behav... Index candidates by approval ID and scope, maintain earliest/latest ready candidates, and use bounded tombstone storage; add a benchmark for roughly 1000 approval events.
Cmux Swift Package Boundaries ❌ Error The PR adds 347 lines of Foundation-only approval ID and coordinator state logic to app-root Sources; injected scheduling and tests show it is independently testable. Extract AgentApprovalCorrelationID and AgentApprovalNotificationCoordinator into the existing CmuxNotifications SwiftPM target. Expose AgentApprovalCorrelationID first, and keep TerminalNotificationQueue wiring in the app.
Cmux Architecture Rethink ❌ Error Production approval delivery uses Task.sleep for a 100 ms settle window to mask request/reviewer ordering; pane and tombstone caches add a second owner for notification state. Make the agent/notification store the source of truth for pending and resolved approvals. First route request and reviewer outcomes into that state, then derive delivery from it and remove the timer and caches.
Docstring Coverage ⚠️ Warning Docstring coverage is 13.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (19 passed)
Check name Status Explanation
Cmux Swift Actor Isolation ✅ Passed Production changes isolate the approval coordinator and queue drain on MainActor; UI store accesses remain on MainActor, and no new async service protocols or unisolated Sendable reference types ap...
Cmux Browser Automation Off-Main ✅ Passed The PR diff changes notification-policy, coordinator, queue, and tests only; TerminalController.swift and ControlCommandExecutionPolicy.swift are unchanged, so no browser automation routing is intr...
Cmux Cache Substitution Correctness ✅ Passed The diff adds transient approval coordination and correlation metadata; it does not replace a persistence, history, undo, or snapshot read with a cache. Session lookup reloads the state file under...
Cmux No Hacky Sleeps ✅ Passed The diff contains no production TypeScript, JavaScript, shell, or build/runtime script changes. The only non-Swift change is a Python test; Swift timing is out of scope for this check.
Cmux Swift Concurrency ✅ Passed The diff adds no background Dispatch, Combine, or completion-handler API. Its sole new Task uses async sleep and returns cancellation retained by the coordinator for lifecycle control.
Cmux Swift @Concurrent ✅ Passed The PR adds no nonisolated async or @concurrent functions. Its only async work is cancellable Task.sleep inside @MainActor coordination; added nonisolated queue methods are synchronous bridges.
Cmux Swiftpm Lockfiles ✅ Passed The PR adds Swift sources to cmux.xcodeproj but changes no SwiftPM package references, Package.swift, .gitignore, or Package.resolved files; no lockfile rule is triggered.
Cmux Swift Logging ✅ Passed The diff adds only CLI print("{}") output and a #if DEBUG cmux debug event; it adds no production print/log/file diagnostics, unsafe Logger, or unredacted sensitive logging.
Cmux User-Facing Error Privacy ✅ Passed The production diff adds opaque hashed correlation IDs and generic OK/usage responses; alert copy remains localized or sanitized tool-name text, with no new vendor names, raw messages, IDs, or payl...
Cmux Full Internationalization ✅ Passed The production diff adds no new localization keys or catalog/web files; approval notification text still uses existing localized APIs, and added literals are protocol, correlation, or debug tokens.
Cmux Swiftui State Layout ✅ Passed The PR adds no SwiftUI view or layout/state pattern. Its only ObservableObject touch changes notification plumbing; no new state, GeometryReader, lazy/list store row, or render-time mutation appears.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed The PR diff adds no user-visible NSWindow, NSPanel, WindowController, Window, or WindowGroup code. The auxiliary-window lint also passes.
Cmux Source Artifacts ✅ Passed All 16 changed paths are Swift/Python source, tests, or Xcode project configuration; no artifact-like paths, binaries, logs, or scratch directories appear in the diff.
Cmux No Test Or Debug Seam In Production Source ✅ Passed The production Sources diff adds no DEBUG/test guards or test-named seams. Coordinator injection has real production wiring in TerminalNotificationQueue, and tests use its internal behavior without...
Cmux No Ambient Global State ✅ Passed The diff adds an injectable @MainActor coordinator with instance state and closures; new identity/policy types have instance APIs. No new free function, mutable global, static-only namespace, or si...
Linked Issues check ✅ Passed The description links issues 10017 and 9592 and clearly explains how the changes address them without regressing existing behavior.
Out of Scope Changes check ✅ Passed The implementation and tests directly support correlated Codex approval notification settling, resolution, coalescing, and regression coverage.
Title check ✅ Passed The title clearly and concisely describes the primary change: delaying notifications for auto-resolved Codex approvals.
Description check ✅ Passed The description provides a detailed summary, rationale, behavior, trade-offs, verification context, and scope. It does not include the template’s Demo Video, Review Trigger, or Checklist sections, but…
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-10017-codex-autoapprove-notify-swarm

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.

@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: 1

🤖 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/AgentNotificationGateTests.swift`:
- Around line 157-180: Update
pendingApprovalsInOnePaneCoalesceIntoOneNotification to resolve firstApprovalID
after staging and running the approvals, then assert the second approval remains
delivered and fixture.deliveries.clears is empty. Ensure the test specifically
verifies that resolving the stale first approval does not clear the newer
pending approval.
🪄 Autofix

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 Plus

Run ID: 8cc22a98-1886-4bec-91c2-d59244dd3010

📥 Commits

Reviewing files that changed from the base of the PR and between 8952b5e and 46253cc.

📒 Files selected for processing (1)
  • cmuxTests/AgentNotificationGateTests.swift

Comment thread cmuxTests/AgentNotificationGateTests.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: 5

🤖 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 `@CLI/AgentHookNotificationPolicy.swift`:
- Around line 80-89: Update canonicalJSON to return an optional String and
return nil when the value is absent or cannot be deterministically
JSON-serialized; remove the String(describing:) fallback. Propagate this
optional through the approval identity construction in make so it returns nil
when canonicalJSON fails, preserving the caller’s existing uncorrelated
settle-window behavior.

In `@CLI/cmux.swift`:
- Around line 32544-32571: Extract the shared Codex auto-review classification
from the notification-hook site at CLI/cmux.swift:32544-32571 into a helper that
reads the bounded rollout tail, calls
CodexApprovalNotificationPolicy.reviewRoute, and checks .autoReview; update both
sites to use it, including runFeedHook at CLI/cmux.swift:35137-35161 with its
stdinObj source. Also verify or adjust reviewRoute so empty or unavailable
rolloutLines fail closed by returning a non-.autoReview route.

In `@cmuxTests/AgentNotificationGateTests.swift`:
- Around line 254-289: Update reorderedOldResolutionDoesNotCancelNewApproval so
secondApprovalID is staged before the delayed firstApprovalID entries, while
preserving the duplicate old request coverage. Keep the scheduler execution and
assertions focused on delivering only the newer approval notification, ensuring
exact-resolution and scope-level tombstone handling cannot allow the stale
request to replace it.

In `@Sources/AgentApprovalNotificationCoordinator.swift`:
- Around line 124-139: Update resolve(surfaceID:approvalID:) to remove every
candidate in state.candidates whose approvalID matches the supplied approvalID,
rather than selecting only the lowest-sequence candidate. Preserve the existing
tombstone behavior when no candidate matches, then call finishResolution with
the updated state so duplicate candidates cannot keep the pane alive.

In `@Sources/TerminalNotificationQueue.swift`:
- Around line 607-615: Update the .clearNotificationCorrelation case to clear
notifications even when agentNotificationDeliveryTarget returns nil: use
target.tabId when available, otherwise fall back to the enqueued key.tabId,
while preserving the existing correlationKey.
🪄 Autofix

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 Plus

Run ID: 438f03a6-b31c-440e-803e-a8026c3512dd

📥 Commits

Reviewing files that changed from the base of the PR and between 46253cc and 7bf2173.

📒 Files selected for processing (16)
  • CLI/AgentHookNotificationPolicy.swift
  • CLI/FeedEventClassifier.swift
  • CLI/cmux.swift
  • Sources/AgentApprovalCorrelationID.swift
  • Sources/AgentApprovalNotificationCoordinator.swift
  • Sources/AgentNotificationDelivery.swift
  • Sources/AgentNotificationGate.swift
  • Sources/TerminalController.swift
  • Sources/TerminalNotificationLiveRetargetDelivery.swift
  • Sources/TerminalNotificationQueue.swift
  • Sources/TerminalNotificationStore.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/AgentNotificationGateTests.swift
  • cmuxTests/CLICodexHookTimeoutRegressionTests.swift
  • cmuxTests/FeedEventClassificationTests.swift
  • tests/test_codex_permission_prompt_notification.py

Comment thread CLI/AgentHookNotificationPolicy.swift Outdated
Comment thread CLI/cmux.swift
Comment thread cmuxTests/AgentNotificationGateTests.swift
Comment thread Sources/AgentApprovalNotificationCoordinator.swift Outdated
Comment thread Sources/TerminalNotificationQueue.swift
@cursor

cursor Bot commented Aug 12, 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.

1 similar comment
@cursor

cursor Bot commented Aug 12, 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 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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
CLI/AgentHookNotificationPolicy.swift (1)

160-188: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Fail closed when no matching turn ID exists.

When rawObject has no turn ID, Line 175 returns the reviewer route from the newest rollout context. That context can belong to another turn. An unrelated auto_review route then suppresses a blocking approval banner.

Require a matching structured turn ID before using rollout data. Keep direct request fields as the only route source when no turn ID is available.

Proposed fix
         let requestedTurnID = firstString(
             in: rawObject,
             keys: ["turn_id", "turnId"]
         )
-        var latestTurnContext: [String: Any]?
+        guard let requestedTurnID else { return nil }
         for line in rolloutLines.reversed() {
             guard let data = line.data(using: .utf8),
                   let object = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
                   object["type"] as? String == "turn_context",
                   let payload = object["payload"] as? [String: Any] else {
                 continue
             }
-            if latestTurnContext == nil {
-                latestTurnContext = payload
-            }
-            guard let requestedTurnID else {
-                return reviewRoute(in: payload)
-            }
             if firstString(in: payload, keys: ["turn_id", "turnId"]) == requestedTurnID {
                 return reviewRoute(in: payload)
             }
         }
-
-        if let latestTurnContext,
-           firstString(in: latestTurnContext, keys: ["turn_id", "turnId"]) == nil {
-            return reviewRoute(in: latestTurnContext)
-        }
         return nil

As per coding guidelines: “A missing reliable signal must fail closed.” As per path instructions: approval routing must use authoritative structured identifiers and fail closed when rollout data cannot resolve them.

🤖 Prompt for 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.

In `@CLI/AgentHookNotificationPolicy.swift` around lines 160 - 188, Update the
rollout-context resolution around requestedTurnID and latestTurnContext so
rollout data is used only when a structured turn ID is present and matches the
requested turn ID. Remove the fallback that routes from a context without
turn_id, and preserve direct request fields as the sole route source when
requestedTurnID is absent or no matching context exists.

Sources: Coding guidelines, Path instructions

Sources/AgentApprovalNotificationCoordinator.swift (1)

292-309: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Remove fixed-delay approval coordination from the runtime path.

Task.sleep controls whether the coordinator delivers an approval notification. This creates a timing-dependent state window instead of resolving from authoritative approval lifecycle signals.

Use an explicit approval-pending or completion signal to trigger delivery. Keep cancellation in the coordinator.

As per coding guidelines, “flag Task.sleep … used for … delayed coordination.”

🤖 Prompt for 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.

In `@Sources/AgentApprovalNotificationCoordinator.swift` around lines 292 - 309,
Update scheduleOnMainActor so approval notification delivery is triggered by an
explicit approval-pending or completion signal rather than Task.sleep(for:).
Preserve the existing cancellation behavior by retaining the returned task
cancellation mechanism, and keep delivery on MainActor through the action
closure.

Source: Coding guidelines

♻️ Duplicate comments (1)
CLI/cmux.swift (1)

32545-32552: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Auto-review duplication is resolved; residual transcript-path fallback asymmetry remains.

Both call sites now delegate to the shared CodexApprovalNotificationPolicy().isAutoReviewed(rawObject:transcriptPath:readRolloutLines:) method. This addresses the previously flagged duplication of the rollout-read-and-classify logic.

One asymmetry remains between the two call sites:

  • At line 32547, the generic agent hook path falls back to mapped?.transcriptPath when input.transcriptPath is absent.
  • At lines 35144-35147, the runFeedHook path only reads transcript_path/transcriptPath from the raw stdin object, with no session-store fallback.

If a Codex event omits the transcript path key on a given hook delivery, runFeedHook has no way to recover it, while the generic hook path does. This does not create a safety bug (missing transcript data means isAutoReviewed fails closed and still notifies), but it does mean the same underlying approval request can classify differently across the two delivery paths depending on which one is missing the transcript path key.

Unify the transcript-path resolution for both call sites, or confirm that Codex always supplies transcript_path on every hook invocation this path handles.

Also applies to: 35140-35152

🤖 Prompt for 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.

In `@CLI/cmux.swift` around lines 32545 - 32552, Unify transcript-path resolution
between the generic agent hook call and runFeedHook’s
CodexApprovalNotificationPolicy().isAutoReviewed invocation. Update runFeedHook
to use its raw transcript_path/transcriptPath value with the same session-store
fallback used by the generic path, preserving fail-closed behavior when neither
source provides a path.
🤖 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 `@CLI/AgentHookNotificationPolicy.swift`:
- Around line 55-60: Update CodexApprovalNotificationIdentity.make to use the
authoritative per-request tool-call or approval identifier shared by prompt and
completion lifecycle events when constructing approvalID. Do not rely on the
derived session/turn/tool/input hash for exact clearing; if no shared identifier
is available, fail closed rather than returning a potentially colliding
approvalID.

In `@Sources/AgentApprovalNotificationCoordinator.swift`:
- Around line 126-134: In the exact-resolution flow, update the surrounding
resolution method to record exactResolutionTombstones for the approvalID before
checking state.candidates, so every exact resolution suppresses delayed
duplicate PermissionRequest deliveries. Preserve the existing candidate-removal
behavior, and add a regression test that stages an approval, resolves it, then
stages the same approvalID again and verifies no notification is delivered.

---

Outside diff comments:
In `@CLI/AgentHookNotificationPolicy.swift`:
- Around line 160-188: Update the rollout-context resolution around
requestedTurnID and latestTurnContext so rollout data is used only when a
structured turn ID is present and matches the requested turn ID. Remove the
fallback that routes from a context without turn_id, and preserve direct request
fields as the sole route source when requestedTurnID is absent or no matching
context exists.

In `@Sources/AgentApprovalNotificationCoordinator.swift`:
- Around line 292-309: Update scheduleOnMainActor so approval notification
delivery is triggered by an explicit approval-pending or completion signal
rather than Task.sleep(for:). Preserve the existing cancellation behavior by
retaining the returned task cancellation mechanism, and keep delivery on
MainActor through the action closure.

---

Duplicate comments:
In `@CLI/cmux.swift`:
- Around line 32545-32552: Unify transcript-path resolution between the generic
agent hook call and runFeedHook’s
CodexApprovalNotificationPolicy().isAutoReviewed invocation. Update runFeedHook
to use its raw transcript_path/transcriptPath value with the same session-store
fallback used by the generic path, preserving fail-closed behavior when neither
source provides a path.
🪄 Autofix

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 Plus

Run ID: ab99f37b-f06a-48c2-971b-75d64ffaeea3

📥 Commits

Reviewing files that changed from the base of the PR and between 42f9343 and 242bc2a.

📒 Files selected for processing (6)
  • CLI/AgentHookNotificationPolicy.swift
  • CLI/cmux.swift
  • Sources/AgentApprovalNotificationCoordinator.swift
  • Sources/TerminalNotificationQueue.swift
  • cmuxTests/AgentNotificationGateTests.swift
  • cmuxTests/FeedEventClassificationTests.swift

Comment thread CLI/AgentHookNotificationPolicy.swift Outdated
Comment thread Sources/AgentApprovalNotificationCoordinator.swift Outdated
@austinywang

Copy link
Copy Markdown
Contributor Author

Review follow-up on 858de98:

@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: 1

🤖 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/FeedEventClassificationTests.swift`:
- Around line 441-449: Update codexRolloutReviewerRequiresMatchingTurnID so
rawObject includes a requested turn ID distinct from the rollout’s
"another-turn" value, ensuring CodexApprovalNotificationPolicy.reviewRoute
reaches and verifies the turn-ID mismatch while preserving the nil expectation.
🪄 Autofix

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 Plus

Run ID: 7231a56d-105e-4a24-a430-0a00eaa7cc39

📥 Commits

Reviewing files that changed from the base of the PR and between 242bc2a and 858de98.

📒 Files selected for processing (5)
  • CLI/AgentHookNotificationPolicy.swift
  • CLI/cmux.swift
  • Sources/AgentApprovalNotificationCoordinator.swift
  • cmuxTests/AgentNotificationGateTests.swift
  • cmuxTests/FeedEventClassificationTests.swift

Comment thread cmuxTests/FeedEventClassificationTests.swift
@cursor

cursor Bot commented Aug 14, 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.

1 similar comment
@cursor

cursor Bot commented Aug 26, 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.

@vercel

vercel Bot commented Aug 30, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
cmux166 Ready Ready Preview Sep 8, 2026 8:05pm UTC
cmux41 Ready Ready Preview Sep 8, 2026 8:05pm UTC

@cursor

cursor Bot commented Aug 30, 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.

@cursor

cursor Bot commented Aug 30, 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.

1 similar comment
@cursor

cursor Bot commented Aug 30, 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.

@github-actions

github-actions Bot commented Sep 1, 2026 •

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@austinywang
austinywang force-pushed the issue-10017-codex-autoapprove-notify-swarm branch from abe72e5 to 6f23147 Compare September 1, 2026 08:03

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed

Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.

Re-trigger cubic

Comment thread CLI/AgentHookNotificationPolicy.swift Outdated
Comment thread Sources/TerminalNotificationQueue.swift Outdated
Comment thread Sources/TerminalNotificationQueue.swift
Comment thread CLI/cmux.swift
Comment thread CLI/cmux.swift Outdated
Comment thread CLI/CMUXCLI+CodexFireAndForgetHooks.swift Outdated
Comment thread tests/test_codex_permission_prompt_notification.py Outdated
Comment thread cmuxTests/AgentNotificationGateTests.swift Outdated
Comment thread Sources/TerminalController.swift Outdated
Comment thread cmuxTests/FeedEventClassificationTests.swift Outdated
@cursor

cursor Bot commented Sep 1, 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.

1 similar comment
@cursor

cursor Bot commented Sep 1, 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.

@vercel

vercel Bot commented Sep 1, 2026

Copy link
Copy Markdown

Deployment failed for project cmux166 with the following error:

Resource is limited - try again in 60 minutes (more than 450, code: "api-deployments-paid-per-hour").

Learn More: https://vercel.com/manaflow?upgradeToPro=build-rate-limit

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

Cursor Bugbot has reviewed your changes using default effort and found 5 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a4bf746. Configure here.

Comment thread CLI/AgentHookNotificationPolicy.swift
Comment thread CLI/AgentHookNotificationPolicy.swift Outdated
Comment thread CLI/CMUXCLI+SemanticNotifications.swift
Comment thread Sources/TerminalNotificationQueue.swift
Comment thread Sources/TerminalNotificationQueue.swift Outdated
@teamleaderleo teamleaderleo added S2: major A crash, hang, lost state, broken connection, or a regression on a path people use area: notifications Notifications, banners, badges, the bell area: agents Agent integrations (Claude Code, Codex, ACP), agent chat, hooks, status labels Sep 30, 2026
@teamleaderleo

Copy link
Copy Markdown
Collaborator

Closing, superseded by the #10017 fix on main.

This branch was successfully deployed

2 active deployments
Preview – cmux166 — 054e7bc8 Deployed Sep 8, 2026 by vercel[bot]
Preview – cmux41 — 054e7bc8 Deployed Sep 8, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: agents Agent integrations (Claude Code, Codex, ACP), agent chat, hooks, status area: notifications Notifications, banners, badges, the bell S2: major A crash, hang, lost state, broken connection, or a regression on a path people use

Projects

None yet

3 participants