Skip to content

Hibernate idle agents before critical memory pressure panics - #9090

Merged
austinywang merged 24 commits into
mainfrom
issue-8997-memory-growth-panics
Jul 29, 2026
Merged

austinywang merged 24 commits into
mainfrom
issue-8997-memory-growth-panics

Conversation

@austinywang

@austinywang austinywang commented Jul 28, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Add critical-memory-pressure safety hibernation after hidden renderer/browser reclamation, selecting at most two hidden, idle, process-safe resumable agent panes. Routine scheduled hibernation remains opt-in and never terminates a live process.
  • Reuse AgentHibernationController as the single MainActor lifecycle owner, with explicit live → terminating → recovering → terminationFailed/hibernated phases and one stable committed request identity across exit observation, native teardown, recovery, retry, and panel-close cleanup.
  • Fail closed before signaling unless exact PID generation, process group, captured TTY, and uncached cmux workspace/surface scope all match. Authorities are capped at 32 processes, multi-TTY scopes are rejected, TERM/KILL escalation is bounded, and late generations are observed without broadening which groups may be signaled.
  • Tear down the native Ghostty surface through two independently admitted hibernation lanes, so one stuck ghostty_surface_free cannot strand the second pressure candidate or ordinary panel close. Callback/tee/manual-I/O userdata remains alive until native free returns.
  • Preserve transcript restoration, panel transfer, Dock alias, and current main font-size-transfer ownership invariants. No bonsplit or Ghostty submodule change is part of this PR.

This targets the failure mode in #8997: renderer-only reclamation cannot release memory held by long-lived agent process trees, while a confirmed idle resumable agent can be snapshotted, terminated within an exact process authority, and restored on demand before system pressure reaches WindowServer/watchdog failure.

Regression coverage

The regression commits precede the implementation commits so the PR history shows the failures before the fix. Behavioral coverage includes:

  • critical pressure selection while routine hibernation is disabled;
  • visible/running/needs-input/unconfirmed/unprotectable candidate exclusion;
  • exact PID-generation, process-group, TTY, and cmux-scope validation;
  • 32-process, multi-TTY, refreshed fan-out, and eight-refresh fail-closed bounds;
  • partial signal commit and exact-exit observation without blocking later work;
  • stable committed ownership before any post-signal suspension;
  • close-during-native-teardown bounded cleanup with no late recovery re-registration;
  • independent native-free lanes and callback userdata lifetime;
  • Dock reconcile preserving panels still owned by live aliases.

Tests inject signal/exit providers and never signal arbitrary live processes.

Validation

  • Canonical local autoreview: clean, no actionable findings (0.88 confidence) before the origin/main merge.
  • Post-merge: all changed Swift parses, git diff --check, check-pbxproj, test wiring (630 files), workspace package grouping, Package.resolved policy, JSON localization parsing, and canonical cmux policy checks pass.
  • Focused package suites before the merge: TerminalSurfaceRuntimeTeardownCoordinatorTests 5/5 and TerminalSurfaceTeardownCallbackLifetimeTests 8/8.
  • The focused SwiftPM command still exits nonzero because the checked-in generated GhosttyKit archive is named ghostty-internal.a instead of lib…; after main's Ghostty API bump, the local generated artifact also lacks the new font-size callback declarations. This PR does not modify the generated XCFramework; GitHub CI/cloud build supplies the matching artifact.
  • Every new Swift file is below 500 lines. The requested .github/swift-file-length-budget.tsv, swift-warning-budget.tsv, and scripts/swift_file_length_budget.py are absent on current origin/main; no budget TSV was generated or modified.
  • Tagged runtime verification will run only after CI and review are green.

Localization audit: the new finishing/failure/retry UI copy uses localized keys with English and Japanese entries, matching the existing agent-hibernation catalog coverage. Changed localization JSON parses cleanly and the changed Swift files contain no new bare user-facing English.

Closes #8997

Summary by CodeRabbit

  • New Features
    • Added trigger-aware “Routine Agent Hibernation” behavior, separate from critical memory pressure safety hibernation.
    • Improved agent hibernation eligibility and process-exit handling to better coordinate commit/resume.
    • Updated Terminal panel hibernation lifecycle UI to reflect terminating/recovering/failed phases with clearer retry/resume actions.
  • Bug Fixes
    • Refined confirmation/teardown validation and tracking during panel close, detach, move, and restore to prevent incorrect state transitions.
  • Documentation
    • Updated CLI/UI/settings copy and localization/schema text to distinguish routine vs critical memory pressure behavior.

@coderabbitai

coderabbitai Bot commented Jul 28, 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

This PR adds critical-memory-pressure safety hibernation alongside scheduled Agent Hibernation. It introduces trigger-aware planning, process-identity validation, bounded runtime teardown, panel lifecycle tracking, synchronous input recording, memory-pressure handling, UI phase transitions, tests, documentation, localization, and build wiring.

Changes

Critical Memory Pressure Hibernation

Layer / File(s) Summary
Trigger-aware planning and controller evaluation
Sources/App/AgentHibernation*.swift, Sources/RestorableAgentSession.swift, Sources/App/AgentHibernationPlanner.swift
Adds trigger-specific selection, confirmation, process-identity tracking, pressure evaluation, and teardown validation.
Scoped termination and bounded runtime teardown
Sources/App/AgentHibernationController+Process*.swift, Sources/App/AgentHibernationController+Teardown*.swift, Packages/macOS/CmuxTerminal/...
Validates process scope, coordinates exact-generation exit observation, and adds ticketed isolated hibernation teardown lanes.
Panel phases and lifecycle tracking
Sources/AgentHibernation/*, Sources/Panels/*, Sources/Workspace*.swift, Sources/DockSplitStore*.swift
Tracks live, terminating, recovering, failed, and hibernated phases while preserving or discarding tracking across lifecycle transitions.
Input recording, tests, documentation, localization, and wiring
Sources/GhosttyTerminalView.swift, cmuxTests/*, cmuxUITests/*, docs/*, web/*, Resources/*, cmux.xcodeproj/*
Moves input recording to a synchronous main-actor path, adds coverage, and updates user-facing descriptions and project entries.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MemoryPressureMonitor
  participant AgentHibernationMemoryPressureResponder
  participant AgentHibernationController
  participant AgentHibernationPlanner
  participant TerminalSurfaceRuntimeTeardownCoordinator
  participant ProcessExitObservation
  MemoryPressureMonitor->>AgentHibernationMemoryPressureResponder: shedMemory(for: snapshot)
  AgentHibernationMemoryPressureResponder->>AgentHibernationController: reclaimIdleAgentsForSystemMemoryPressure(...)
  AgentHibernationController->>AgentHibernationPlanner: selectedPanelKeys(trigger: .systemMemoryPressure)
  AgentHibernationPlanner-->>AgentHibernationController: bounded eligible panels
  AgentHibernationController->>TerminalSurfaceRuntimeTeardownCoordinator: reserve and enqueue isolated teardown
  AgentHibernationController->>ProcessExitObservation: observeCommittedTermination(...)
  ProcessExitObservation-->>AgentHibernationController: exact-generation exit result
Loading

Possibly related issues

  • manaflow-ai/cmux-dev-artifacts#6868: Shares process-snapshot and RestorableAgentSessionIndex logic used by live-agent and fork-availability checks.

Possibly related PRs

Suggested reviewers: lawrencecchen


Important

Pre-merge checks failed

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

❌ Failed checks (8 errors, 1 warning)

Check name Status Explanation Resolution
Cmux Swift Blocking Runtime ❌ Error Production hibernation/runtime code adds new sleeps and polling (ContinuousClock.sleep, Task.sleep, kill(pid,0) loops, timeout waits) in teardown/restore paths. Replace these waits with event/callback-driven completions or actor state transitions; keep timing waits confined to tests or explicitly justified UI delays.
Cmux Algorithmic Complexity ❌ Error TerminalSurfaceRuntimeTeardownCoordinator.swift:229-234 uses Array.removeFirst() for the teardown FIFO, making a batch of N surface frees O(N²). Use an O(1) queue (head index/deque/ring buffer) for queuedRequests so repeated teardown dequeues don't shift the whole array.
Cmux Swift Concurrency ❌ Error Adds internal callback-driven teardown APIs and unstructured Tasks in core hibernation flow; these cmux-owned async paths should be async/await or structured task handles. Replace the new completion-handler style controller/coordinator APIs with async-returning operations or stored/cancellable task handles; keep only OS/AppKit callback bridges.
Cmux Swift @Concurrent ❌ Error waitForCommittedTerminationRecovery is nonisolated async but lacks @concurrent; it’s awaited from a @MainActor task and coordinates long-running exit/recovery waits. Annotate that helper with conditional @concurrent (or move the wait into a detached helper) so the recovery work leaves MainActor before waiting on processes.
Cmux Swift Package Boundaries ❌ Error The diff adds reusable, testable hibernation/session logic in app-target Sources/ (AgentHibernationPlanner, RestorableAgentSession, CmuxTopSnapshot) instead of a package. Extract the reusable core into a small SwiftPM target (e.g. CmuxAgentHibernationCore) and keep only AppKit/UI/Ghostty wiring in Sources/.
Cmux Full Internationalization ❌ Error The PR adds user-facing strings in xcstrings and web messages only for en/ja, but both catalogs support 20 locales, so localization is incomplete. Add translated entries for every locale in Resources/Localizable.xcstrings and all 20 web/messages/*.json files, keeping keys aligned with web/i18n/routing.ts.
Cmux No Test Or Debug Seam In Production Source ❌ Error PR adds #if DEBUG test-observation members in Sources/DockSplitStore.swift and Sources/Workspace.swift (debug… counters) used only by tests. Remove these seams from production source; widen the underlying state to internal and inspect it from Tests/ via @testable import, or move any genuine debug-only code to a dedicated debug file/folder.
Cmux No Ambient Global State ❌ Error AppDelegate.swift adds app-delegate runtime state workspaceTerminalFontSizeArbiter at line 516, which is ambient state per the rule. Move the arbiter into a dedicated constructable composition-root type and inject it at the app seam instead of storing it on AppDelegate.
Docstring Coverage ⚠️ Warning Docstring coverage is 10.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (16 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes implement critical-pressure agent hibernation, process-scope validation, exact-exit observation, and cleanup as required by #8997.
Out of Scope Changes check ✅ Passed The diffs stay focused on agent-hibernation behavior, supporting tests, docs, localization, and build wiring without obvious unrelated changes.
Cmux Swift Actor Isolation ✅ Passed Explicit MainActor boundaries or actors wrap the new UI and teardown state; detached work hops back safely and no new isolation leak is evident.
Cmux Browser Automation Off-Main ✅ Passed Only browser-adjacent change is TerminalController help text; no browser routing, waits, or policy tests changed, so the rule isn’t implicated.
Cmux Expensive Synchronous Load ✅ Passed The new memory-pressure/teardown paths use await RestorableAgentSessionIndex.loadIncludingProcessDetectedSnapshots() inside Task.detached, while UI close paths still prefer `SharedLiveAgentInde...
Cmux Cache Substitution Correctness ✅ Passed Changed history/restore paths use SharedLiveAgentIndex with cold-cache fallback, and the cache is TTL/event-driven, so no blind stale substitution.
Cmux No Hacky Sleeps ✅ Passed PASS: The PR diff only changes Swift, docs, and JSON resources; no TypeScript/JavaScript/shell or build/runtime script files were changed, so the rule isn’t triggered.
Cmux Swiftpm Lockfiles ✅ Passed PASS: The Package.swift pin bump has a matching package-local Package.resolved, and the Xcode/workspace lockfiles were updated; no .gitignore changes touched Package.resolved.
Cmux Swift Logging ✅ Passed Full Swift diff has no added/changed print/debugPrint/dump/NSLog/Logger/log calls, and no file-scoped Logger constants or sensitive-data logging.
Cmux User-Facing Error Privacy ✅ Passed Changed user-facing text is generic (“Reload queued…”, “Agent shutdown needs attention”, “Retry shutdown”) and exposes no vendor/internal implementation details.
Cmux Swiftui State Layout ✅ Passed PASS: Changes only add one @Published field on existing TerminalPanel/ObservedObject model, plus a DEBUG background GeometryReader; no lazy-row store refs or render-time state writes.
Cmux Architecture Rethink ✅ Passed The diff adds bounded, documented bridge logic (pressure confirmation, process-exit observation) with clear single owners and phase/ticket invariants; no split lifecycle bug is introduced.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR only changes terminal-panel views/settings text and hibernation internals; no new/changed NSWindow, NSPanel, WindowGroup, or cmux.* auxiliary-window identifiers appear in the diff.
Cmux Source Artifacts ✅ Passed Changed paths are source/config/docs/tests/localization or a submodule gitlink; no logs, temp dirs, build output, caches, or copied artifacts were added.
Title check ✅ Passed The title is concise and accurately reflects the main change: critical-memory-pressure hibernation for idle agents.
Description check ✅ Passed The description is substantial and covers summary, rationale, testing, and validation, though the template sections are not fully followed.
✨ 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-8997-memory-growth-panics

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.

@austinywang

Copy link
Copy Markdown
Contributor Author

@codex review

@coderabbitai review

@greptile-apps review

@coderabbitai

coderabbitai Bot commented Jul 28, 2026 •

Copy link
Copy Markdown

@austinywang: I’ll review the changes, with particular attention to lifecycle eligibility, teardown/revalidation safety, pressure coalescing, and preservation of the scheduled hibernation behavior.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@cursor

cursor Bot commented Jul 28, 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.

@austinywang

Copy link
Copy Markdown
Contributor Author

Latest HEAD 4cfff09:

@codex review

@coderabbitai review

@greptile-apps review

@coderabbitai

coderabbitai Bot commented Jul 28, 2026 •

Copy link
Copy Markdown

@austinywang: I’ll review the latest changes at 4cfff09d8d, focusing on critical-pressure eligibility, teardown safety, coalescing, and preservation of scheduled hibernation behavior.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@austinywang

Copy link
Copy Markdown
Contributor Author

Latest HEAD 102e733:

@codex review

@coderabbitai review

@greptile-apps review

@coderabbitai

coderabbitai Bot commented Jul 28, 2026 •

Copy link
Copy Markdown

@austinywang: I’ll review the latest changes at 102e733026, focusing on critical-pressure eligibility, teardown/revalidation safety, coalescing, and preservation of scheduled hibernation behavior.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@austinywang

Copy link
Copy Markdown
Contributor Author

Latest HEAD 5839b0e:

@codex review

@coderabbitai review

@greptile-apps review

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@coderabbitai

coderabbitai Bot commented Jul 28, 2026 •

Copy link
Copy Markdown

@austinywang: I’ll review the latest changes at 5839b0e9c9, focusing on critical-pressure eligibility, teardown safety, process-scope revalidation, and preservation of scheduled hibernation behavior.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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 (1)
Sources/App/AgentHibernationController.swift (1)

265-340: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Clear expired .systemMemoryPressure confirmations so scheduled hibernation can proceed.

A stale .systemMemoryPressure confirmation survives pruneTrackingState because that only removes .scheduled entries, and later .scheduled calls block on any existing .systemMemoryPressure confirmation before creation. The memory-pressure task also leaves them behind on the initial isPressureStillCritical() return, sleep catch, and subsequent isPressureStillCritical() return before teardown completion. Treat an expired non-in-flight .systemMemoryPressure confirmation as stale/clearable during .scheduled evaluation, or clear it on every early-exit path of the memory-pressure task.

🤖 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/App/AgentHibernationController.swift` around lines 265 - 340, Update
evaluateConfirmation so a non-in-flight .systemMemoryPressure confirmation whose
dueAt has expired is removed before the existing guard blocks .scheduled
evaluation, allowing a new scheduled confirmation to be created. Preserve active
confirmations and any teardown-in-flight state, and retain the current behavior
for unexpired memory-pressure confirmations.
🤖 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/AgentHibernationProcessTerminationTests.swift`:
- Around line 101-126: Add a test alongside rejectsProcessOutsidePaneScope named
rejectsScopeWithUnrecordedProcessIdentity that supplies a
ProcessTerminationScope whose processIDs includes a PID absent from
processIdentities, then invokes validatedScopedProcessTerminations with valid
providers and asserts the result is nil.

In `@Sources/App/AgentHibernationController`+ProcessTermination.swift:
- Around line 176-220: Move the post-termination validity checks in
commitConfirmedTeardown, especially AgentHibernationTrackingGate.isEnabled(),
ownership, protection, generation, and panel-state checks, to before
terminateScopedProcessesForHibernation sends SIGTERM. Preserve the
post-termination process/index and terminal-input validation, and ensure any
checks that can change during termination are revalidated without leaving a
terminated agent in a non-hibernated state; if post-termination validation still
fails, explicitly reconcile the panel state rather than silently returning
false.

---

Outside diff comments:
In `@Sources/App/AgentHibernationController.swift`:
- Around line 265-340: Update evaluateConfirmation so a non-in-flight
.systemMemoryPressure confirmation whose dueAt has expired is removed before the
existing guard blocks .scheduled evaluation, allowing a new scheduled
confirmation to be created. Preserve active confirmations and any
teardown-in-flight state, and retain the current behavior for unexpired
memory-pressure confirmations.
🪄 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 Plus

Run ID: 27da2b23-ab5d-491c-b5bc-6950ca43c819

📥 Commits

Reviewing files that changed from the base of the PR and between 72a457c and ca7ca8f.

📒 Files selected for processing (38)
  • CLI/cmux.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/TerminalSection.swift
  • Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Runtime/AgentHibernationRecording.swift
  • Packages/macOS/CmuxTerminal/Tests/CmuxTerminalTests/FakeHibernationRecorder.swift
  • Resources/Localizable.xcstrings
  • Sources/App/AgentHibernationController+Confirmation.swift
  • Sources/App/AgentHibernationController+InFlightTeardown.swift
  • Sources/App/AgentHibernationController+MemoryPressure.swift
  • Sources/App/AgentHibernationController+PanelLifecycle.swift
  • Sources/App/AgentHibernationController+ProcessTermination.swift
  • Sources/App/AgentHibernationController+Records.swift
  • Sources/App/AgentHibernationController+Teardown.swift
  • Sources/App/AgentHibernationController.swift
  • Sources/App/AgentHibernationMemoryPressureResponder.swift
  • Sources/App/AgentHibernationPlanner.swift
  • Sources/App/WorkspaceRuntimeSettings.swift
  • Sources/AppDelegate+PaneMemoryGuardrail.swift
  • Sources/DockSplitStore+SurfaceTransfer.swift
  • Sources/GhosttyTerminalView.swift
  • Sources/RestorableAgentSession.swift
  • Sources/TerminalController.swift
  • Sources/TerminalSurfaceRuntimeWiring.swift
  • Sources/Workspace+PanelLifecycle.swift
  • Sources/Workspace.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/AgentHibernationPlannerSwiftTests.swift
  • cmuxTests/AgentHibernationProcessTerminationTests.swift
  • cmuxTests/AgentHibernationTrackingLifecycleTests.swift
  • cmuxTests/AgentResumeLivenessTests.swift
  • cmuxTests/CompletedRestoredAgentGenerationTests.swift
  • cmuxTests/SharedLiveAgentIndexAgentLivenessTests.swift
  • cmuxUITests/SettingsTerminalBehaviorUITests.swift
  • docs/agent-hooks.md
  • docs/cli-contract.md
  • docs/configuration.md
  • web/data/cmux.schema.json
  • web/messages/en.json
  • web/messages/ja.json

Comment thread cmuxTests/AgentHibernationProcessTerminationTests.swift
Comment thread Sources/App/AgentHibernationController+ProcessTermination.swift Outdated

@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

Caution

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

⚠️ Outside diff range comments (4)
Sources/TerminalController.swift (2)

12712-12719: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Reset snapshots using the same key used when storing them.

panelSnapshot stores entries under terminalPanel.id, but panelSnapshotReset removes target.surfaceID. These are distinct identifiers, so reset leaves the previous snapshot behind and the next capture reports stale pixel changes.

Proposed fix
-            guard let panelId = resolveSurfaceId(from: panelArg, tab: tab),
-                  let snapshotSurfaceID = tab.terminalInputTarget(forPanelID: panelId)?.surfaceID else {
+            guard let panelId = resolveSurfaceId(from: panelArg, tab: tab),
+                  let terminalPanel = tab.terminalInputTarget(forPanelID: panelId)?.panel else {
                 result = "ERROR: Surface not found"
                 return
             }
             Self.panelSnapshotLock.lock()
-            Self.panelSnapshots.removeValue(forKey: snapshotSurfaceID)
+            Self.panelSnapshots.removeValue(forKey: terminalPanel.id)

Also applies to: 12847-12851

🤖 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/TerminalController.swift` around lines 12712 - 12719, Update the
snapshot reset logic in panelSnapshotReset to remove the entry using the
terminal panel identifier used by panelSnapshot when storing snapshots, rather
than snapshotSurfaceID. Apply the same key correction to the corresponding reset
path around the additional affected location, while preserving the existing
panel-resolution validation and locking.

12717-12719: 🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

Give panelSnapshots one synchronization owner.

The changed code adds manual locking around process-global mutable state while both call paths already execute through v2MainSync; no rationale explains why an actor or MainActor-owned store cannot own this dictionary. Centralize access behind one actor/MainActor owner, or document and enforce a single lock-protected access path if off-main callers are genuinely required.

As per coding guidelines, new manual locks around shared mutable state require a documented reason an actor or MainActor-isolated model cannot provide synchronization.

Also applies to: 12846-12851

🤖 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/TerminalController.swift` around lines 12717 - 12719, Give
panelSnapshots a single synchronization owner instead of adding ad hoc locking
in the removal and related access paths. Prefer centralizing the dictionary
behind the existing v2MainSync/MainActor-isolated flow; if off-main access is
required, route every read and mutation through one lock-protected abstraction
and document why actor isolation is insufficient. Update both the shown removal
path and the corresponding access path around panelSnapshots.

Source: Coding guidelines

Sources/GhosttyTerminalView.swift (2)

6307-6329: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

New #if DEBUG "debug…" accessors are test-only production seams.

debugWordPathSnapshotTerminalPanelID() and debugCanApplyMountedSearchFieldFocusRequest() are new, #if DEBUG-guarded, debug…-named wrapper accessors added solely to expose private state (wordPathSnapshotTerminalPanel, canApplyMountedSearchFieldFocusRequest) for tests, with no production caller. This matches the pattern the repo's custom lint rule calls out for production Sources/ files.

As per path instructions: "flag added test-only or debug-only seams: #if DEBUG (or other test-build-guarded) extensions/members that expose internal state for tests or a debugger with no production caller, members named like debug…... Prefer reaching internal state from the test target via @testable import after widening private to internal; isolate genuinely debug-only facilities in a dedicated debug file or folder."

Also applies to: 9749-9752

🤖 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/GhosttyTerminalView.swift` around lines 6307 - 6329, Remove the `#if`
DEBUG wrapper accessors debugWordPathSnapshotTerminalPanelID and
debugCanApplyMountedSearchFieldFocusRequest. Widen the underlying members
wordPathSnapshotTerminalPanel and canApplyMountedSearchFieldFocusRequest from
private to internal so tests can access them through `@testable` import,
preserving their existing behavior without production debug seams.

Source: Path instructions


7735-7735: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Wire or remove onExplicitTerminalInput.

TerminalPanel.configureTerminalPanel(...) assigns the closure, and terminalSurfaceDidReceiveExplicitInput() invokes it, but GhosttyTerminalView.swift never wires the assignment into any explicit-input path. Add a setExplicitTerminalInputHandler(_:)/propagation step and the relevant terminalSurfaceDidReceiveExplicitInput() call; otherwise this closure is dead code.

🤖 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/GhosttyTerminalView.swift` at line 7735, Wire the
onExplicitTerminalInput closure through GhosttyTerminalView: add a
setExplicitTerminalInputHandler(_:) propagation method and invoke the handler
from terminalSurfaceDidReceiveExplicitInput(). Ensure
TerminalPanel.configureTerminalPanel(...) reaches this handler so explicit
terminal input triggers the assigned closure; otherwise remove the unused
property.
🤖 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 `@Sources/App/AgentHibernationController`+ProcessTermination.swift:
- Around line 292-306: Update the teardown signaling flow around
signalErrorProvider and waitForExactProcessGenerationsToExitWithoutTimeout to
track targets that return non-ESRCH errors after teardownIsCommitted. Exclude
those unsignalable targets from scopedProcessTerminations, or otherwise
transition the panel to a resumable failure state, so the panel cannot remain
permanently .terminating; preserve the existing first-target failure rejection
behavior.

---

Outside diff comments:
In `@Sources/GhosttyTerminalView.swift`:
- Around line 6307-6329: Remove the `#if` DEBUG wrapper accessors
debugWordPathSnapshotTerminalPanelID and
debugCanApplyMountedSearchFieldFocusRequest. Widen the underlying members
wordPathSnapshotTerminalPanel and canApplyMountedSearchFieldFocusRequest from
private to internal so tests can access them through `@testable` import,
preserving their existing behavior without production debug seams.
- Line 7735: Wire the onExplicitTerminalInput closure through
GhosttyTerminalView: add a setExplicitTerminalInputHandler(_:) propagation
method and invoke the handler from terminalSurfaceDidReceiveExplicitInput().
Ensure TerminalPanel.configureTerminalPanel(...) reaches this handler so
explicit terminal input triggers the assigned closure; otherwise remove the
unused property.

In `@Sources/TerminalController.swift`:
- Around line 12712-12719: Update the snapshot reset logic in panelSnapshotReset
to remove the entry using the terminal panel identifier used by panelSnapshot
when storing snapshots, rather than snapshotSurfaceID. Apply the same key
correction to the corresponding reset path around the additional affected
location, while preserving the existing panel-resolution validation and locking.
- Around line 12717-12719: Give panelSnapshots a single synchronization owner
instead of adding ad hoc locking in the removal and related access paths. Prefer
centralizing the dictionary behind the existing v2MainSync/MainActor-isolated
flow; if off-main access is required, route every read and mutation through one
lock-protected abstraction and document why actor isolation is insufficient.
Update both the shown removal path and the corresponding access path around
panelSnapshots.
🪄 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 Plus

Run ID: a4b8a2a7-c8b4-44a5-9e0f-fad65a9892f0

📥 Commits

Reviewing files that changed from the base of the PR and between ca7ca8f and 53914ad.

📒 Files selected for processing (27)
  • CLI/cmux.swift
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/TerminalSection.swift
  • Resources/Localizable.xcstrings
  • Sources/AgentHibernation/AgentHibernationPanelPhase.swift
  • Sources/App/AgentHibernationController+InFlightTeardown.swift
  • Sources/App/AgentHibernationController+PanelLifecycle.swift
  • Sources/App/AgentHibernationController+ProcessTermination.swift
  • Sources/App/AgentHibernationController+Teardown.swift
  • Sources/App/AgentHibernationController+TeardownValidation.swift
  • Sources/App/AgentHibernationController.swift
  • Sources/DockSplitStore+PanelDestruction.swift
  • Sources/DockSplitStore+Reset.swift
  • Sources/DockSplitStore+SessionRestore.swift
  • Sources/DockSplitStore+SurfaceTransfer.swift
  • Sources/DockSplitStore.swift
  • Sources/GhosttyTerminalView.swift
  • Sources/Panels/TerminalPanel+AgentHibernation.swift
  • Sources/Panels/TerminalPanel.swift
  • Sources/Panels/TerminalPanelView.swift
  • Sources/TerminalController.swift
  • Sources/Workspace.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/AgentHibernationProcessTerminationTests.swift
  • cmuxTests/AgentHibernationTrackingLifecycleTests.swift
  • web/data/cmux.schema.json
  • web/messages/en.json
  • web/messages/ja.json

Comment thread Sources/App/AgentHibernationController+ProcessTermination.swift Outdated

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

Caution

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

⚠️ Outside diff range comments (2)
Sources/App/AgentHibernationController+ProcessTermination.swift (2)

40-80: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Preserve rejected scopes in the teardown result dictionary.

scopedProcessTerminations pre-populates entries for empty scopes, but omitted validatedScopedProcessTerminations(...) tasks are left absent from the returned dictionary. Since callers use guard scopedProcessTerminationsByPanel[record.key] else { continue }, using a fallback such as result[key] ?? [] would bypass identity/scope validation and allow an empty process set to proceed to commitConfirmedTeardown.

🤖 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/App/AgentHibernationController`+ProcessTermination.swift around lines
40 - 80, Ensure scopedProcessTerminations includes a dictionary entry for every
input scope, including scopes whose validatedScopedProcessTerminations task is
rejected or produces no result. Preserve the distinction between a present empty
array and a missing key so callers’ guarded lookup continues to skip rejected
scopes rather than treating them as valid empty terminations; update the
task/result aggregation around validatedScopedProcessTerminations accordingly.

137-192: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Reclaim ownership on late aborts after the monitor is armed.

In commitConfirmedTeardown, .rejected at line 229 and the pre-SIGTERM safety-check failure after line 177 return early without cleanup. Add a cleanup/transfer path here so the monitor/cancellation state is relinquished and the snapshot is retained as recovery (or disposed when it is no longer guarded) rather than leaving tracking state/snapshot ownership behind.

🤖 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/App/AgentHibernationController`+ProcessTermination.swift around lines
137 - 192, Update commitConfirmedTeardown so late aborts—both the .rejected
branch and the pre-SIGTERM teardownIsStillSafe failure—reclaim all monitor and
cancellation state. Reuse the existing snapshot cleanup/transfer helpers to
retain the snapshot for recovery while it remains guarded, or dispose it once
protection is no longer active, and ensure restoreOwnedSnapshotPaths and
tracking state are not left behind.
🤖 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.

Outside diff comments:
In `@Sources/App/AgentHibernationController`+ProcessTermination.swift:
- Around line 40-80: Ensure scopedProcessTerminations includes a dictionary
entry for every input scope, including scopes whose
validatedScopedProcessTerminations task is rejected or produces no result.
Preserve the distinction between a present empty array and a missing key so
callers’ guarded lookup continues to skip rejected scopes rather than treating
them as valid empty terminations; update the task/result aggregation around
validatedScopedProcessTerminations accordingly.
- Around line 137-192: Update commitConfirmedTeardown so late aborts—both the
.rejected branch and the pre-SIGTERM teardownIsStillSafe failure—reclaim all
monitor and cancellation state. Reuse the existing snapshot cleanup/transfer
helpers to retain the snapshot for recovery while it remains guarded, or dispose
it once protection is no longer active, and ensure restoreOwnedSnapshotPaths and
tracking state are not left behind.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4711a97c-db8b-40ac-b291-0fbbd40de8a3

📥 Commits

Reviewing files that changed from the base of the PR and between 53914ad and 4f6d229.

📒 Files selected for processing (1)
  • Sources/App/AgentHibernationController+ProcessTermination.swift

@cursor

cursor Bot commented Jul 29, 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.

@austinywang

Copy link
Copy Markdown
Contributor Author

Latest HEAD a751a4b:

@codex review

@coderabbitai review

@greptile-apps review

@coderabbitai

coderabbitai Bot commented Jul 29, 2026 •

Copy link
Copy Markdown

@austinywang I’ll review the latest changes at a751a4b2a9, focusing on the critical-pressure lifecycle, process-scope revalidation, teardown completion, and Dock cleanup paths.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@austinywang

Copy link
Copy Markdown
Contributor Author

CodeRabbit review 4803792901 follow-up:

  • Rejected-scope dictionary entries intentionally remain absent. A missing key is the fail-closed rejection sentinel consumed by the guarded lookup in beginConfirmedTeardowns; an empty present array means a successfully validated scope with no processes. Populating rejected scopes with [] would erase that distinction and is exactly what the current code avoids. No caller uses a fallback.
  • The late-abort restore-monitor ownership finding was valid and is fixed in 120713c6e0. A pre-signal revalidation failure or first-signal rejection now cancels and awaits the armed monitor, removes its ownership marker, deletes an unchanged snapshot, or moves drifted protected bytes into the session's single bounded retained-recovery slot. lateAbortReleasesArmedMonitorAndDisposesItsSnapshot covers the monitor, ownership, snapshot, and unchanged-live-transcript behavior.

@austinywang

Copy link
Copy Markdown
Contributor Author

Latest HEAD 120713c:

@codex review

@coderabbitai review

@greptile-apps review

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026 •

Copy link
Copy Markdown

@austinywang I’ll review the latest changes at 120713c6e0, focusing on the late-abort snapshot/restore-monitor cleanup alongside the critical-pressure teardown lifecycle and process-scope safety.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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 `@Sources/DockSplitStore.swift`:
- Around line 605-608: Update the reconciliation logic around staleTabIds and
discardPanelStateAndClose so it removes only mappings whose surface IDs are
stale, rather than filtering by stale panel IDs. After removal, close each
affected panel only if no remaining surface-to-panel mapping references it,
preserving ownership for panels still referenced by live tabs.
🪄 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 Plus

Run ID: 9e8a3a9d-d824-4d62-9c2a-4a1acc9a42e5

📥 Commits

Reviewing files that changed from the base of the PR and between 4f6d229 and 120713c.

📒 Files selected for processing (7)
  • Sources/App/AgentHibernationController+ProcessTermination.swift
  • Sources/App/AgentHibernationController+Teardown.swift
  • Sources/DockSplitStore+PanelDestruction.swift
  • Sources/DockSplitStore+Reset.swift
  • Sources/DockSplitStore.swift
  • cmuxTests/AgentHibernationProcessTerminationTests.swift
  • cmuxTests/AgentHibernationRestoreMonitorTests.swift

Comment thread Sources/DockSplitStore.swift
…wth-panics

# Conflicts:
#	Sources/DockSplitStore+Reset.swift
#	Sources/DockSplitStore.swift
#	Sources/Workspace+PanelLifecycle.swift
#	Sources/Workspace.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: 9

Caution

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

⚠️ Outside diff range comments (2)
Sources/App/AgentHibernationController+Records.swift (1)

61-80: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Rename the local panelProcessIDs — it means something different from the record field of the same name.

The local is processEntry?.processIDs (used only for hasLiveProcess), while AgentHibernationRecord.panelProcessIDs is assigned processEntry?.hibernationPanelProcessIDs. Same identifier, two different PID sets, three lines apart, in a gate that decides which processes get SIGTERM'd.

♻️ Suggested rename
-                    let panelProcessIDs = processEntry?.processIDs ?? []
+                    let livenessProcessIDs = processEntry?.processIDs ?? []
@@
-                            hasLiveProcess: !panelProcessIDs.isEmpty,
+                            hasLiveProcess: !livenessProcessIDs.isEmpty,
🤖 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/App/AgentHibernationController`+Records.swift around lines 61 - 80,
Rename the local derived from processEntry?.processIDs in the record-building
code to clearly distinguish it from AgentHibernationRecord.panelProcessIDs, and
update the hasLiveProcess check to use the renamed local. Leave the
panelProcessIDs record field assignment sourced from hibernationPanelProcessIDs
unchanged.
Sources/DockSplitStore+SurfaceTransfer.swift (1)

281-286: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Attach-failure rollbacks don't undo updateWorkspaceId, so hibernation tracking can be orphaned.

Both overloads retarget the panel to the Dock (terminal.updateWorkspaceId(workspaceId) at Line 255 / Line 344) before the Bonsplit mutation, but the failure branches only roll back panels, surfaceIdToPanelId, and the cached transfer. The hibernation tracking added in this PR still lives under detached.sourceWorkspaceId, while the panel now reports the Dock workspace — so a subsequent panel.close() discards the wrong key and leaves the source-keyed tracking (and its committed-termination observation) behind.

Restore the previous workspace id in both rollbacks.

🐛 Suggested rollback fix (split variant shown)
         guard let newPane else {
             surfaceIdToPanelId.removeValue(forKey: tab.id)
             detachedSurfaceTransfersByPanelId.removeValue(forKey: detached.panelId)
             panels.removeValue(forKey: detached.panelId)
             clearSessionRestoreState(panelId: detached.panelId)
+            if let terminal = panel as? TerminalPanel {
+                terminal.updateWorkspaceId(detached.sourceWorkspaceId)
+            } else if let browser = panel as? BrowserPanel {
+                browser.updateWorkspaceId(detached.sourceWorkspaceId)
+            }
             return nil
         }

Also applies to: 374-380

🤖 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/DockSplitStore`+SurfaceTransfer.swift around lines 281 - 286, Update
both attach-failure rollback branches in the split and non-split transfer paths
to restore the panel’s previous workspace ID after the earlier updateWorkspaceId
call. Use detached.sourceWorkspaceId when reverting the affected panel,
alongside the existing panels, surface mapping, cached transfer, and session
restore cleanup.
🤖 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/AgentHibernationProcessSnapshotCoordinatorTests.swift`:
- Around line 34-47: Replace the non-deterministic await Task.yield() in the
nextSnapshot coalescing test with a real registration signal: await a second
beforeCapture/waiter-registered event, or use a deadline-bounded poll of the
coordinator’s queued-waiter state. Release allowCapture only after the second
waiter is confirmed queued, preserving the captureCount == 1 assertion.

In `@cmuxTests/AgentHibernationProcessTerminationTests.swift`:
- Line 12: Mark the AgentHibernationProcessTerminationTests suite with the
serialized suite trait, matching AgentHibernationRestoreMonitorTests and
AgentHibernationTerminationFailureTests, so tests that observe
AgentHibernationController.shared cannot run concurrently.
- Around line 243-247: Remove the redundant contains assertions on
escalatedTargets in the test, keeping the exact equality assertion to [-101] as
the sole validation of the escalated targets before finishing
postKillDeadline.continuation.

In
`@Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Lifecycle/TerminalSurfaceRuntimeTeardownCoordinator.swift`:
- Around line 182-190: Replace the preconditionFailure guard in the isolated
hibernation teardown case with an if-let validation of the reservation,
execution slot, and queue index; run the isolated teardown body only when all
resolve successfully, otherwise fall back to the serialized teardown lane.
Ensure the switch case is not skipped and the surface is freed exactly once.

In
`@Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface`+RuntimeLifecycle.swift:
- Around line 394-415: Release any pending agent hibernation runtime teardown
reservation from the surface teardown lifecycle so it cannot outlive the
surface. Update teardownSurface() to invoke the existing cancellation path
cancelAgentHibernationRuntimeTeardownReservation(), and ensure deinit or the
shared teardown path covers all destruction cases without affecting committed
teardown tickets.

In
`@Packages/macOS/CmuxTerminal/Tests/CmuxTerminalTests/TerminalSurfaceRuntimeTeardownCoordinatorTests.swift`:
- Around line 169-183: Reorder the exhaustion assertion in the test so it runs
immediately after acquiring secondReservation and before enqueueRuntimeTeardown
consumes it. Move the reserveIsolatedHibernationTeardown() == nil expectation
ahead of the second ticket enqueue, preserving the existing reservation and
teardown setup otherwise.

In `@Sources/App/AgentHibernationController`+PanelLifecycle.swift:
- Around line 74-95: Update the cleanup Task created in the panel lifecycle flow
so every exit path, including cancellation and failed identity checks, removes
committedTerminationCleanupByPanelID[panelID] when its requestID still matches
cleanupID. Preserve the existing success-path observation removal and completion
handling, and verify no other cleanup path is responsible for pruning this
entry.

In `@Sources/App/AgentHibernationController`+ProcessExitObservation.swift:
- Around line 57-89: Extract the repeated committed-observation identity check
into a private helper named
isCurrentCommittedTerminationObservation(panelID:requestID:) on the relevant
controller. Replace the repeated committedTerminationObservationsByPanelID
requestID comparisons in all three task bodies, including the additional
locations noted, while preserving each existing !Task.isCancelled guard and
return behavior.

In `@Sources/CmuxTopSnapshot.swift`:
- Around line 310-336: Review the `hasCompleteProcessGroups` validation in
`agentHibernationProcessScope` and its downstream `containsUnrelatedProcess`
handling to confirm whether missing process-group leaders should remain a hard
fail-closed veto. If orphaned leaders are valid for otherwise verified
descendant groups, relax this check so live members can pass without requiring
the leader PID to resolve; otherwise preserve the strict behavior and add or
update coverage documenting the intentional tradeoff.

---

Outside diff comments:
In `@Sources/App/AgentHibernationController`+Records.swift:
- Around line 61-80: Rename the local derived from processEntry?.processIDs in
the record-building code to clearly distinguish it from
AgentHibernationRecord.panelProcessIDs, and update the hasLiveProcess check to
use the renamed local. Leave the panelProcessIDs record field assignment sourced
from hibernationPanelProcessIDs unchanged.

In `@Sources/DockSplitStore`+SurfaceTransfer.swift:
- Around line 281-286: Update both attach-failure rollback branches in the split
and non-split transfer paths to restore the panel’s previous workspace ID after
the earlier updateWorkspaceId call. Use detached.sourceWorkspaceId when
reverting the affected panel, alongside the existing panels, surface mapping,
cached transfer, and session restore cleanup.
🪄 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 Plus

Run ID: 64fc3d1a-7382-4a38-add5-c12958808b85

📥 Commits

Reviewing files that changed from the base of the PR and between 120713c and 387fc94.

📒 Files selected for processing (57)
  • Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Lifecycle/TerminalSurfaceRuntimeTeardownAdmission.swift
  • Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Lifecycle/TerminalSurfaceRuntimeTeardownCompletion.swift
  • Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Lifecycle/TerminalSurfaceRuntimeTeardownCoordinator.swift
  • Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Lifecycle/TerminalSurfaceRuntimeTeardownExecutionLane.swift
  • Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Lifecycle/TerminalSurfaceRuntimeTeardownRequest.swift
  • Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Lifecycle/TerminalSurfaceRuntimeTeardownReservation.swift
  • Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Lifecycle/TerminalSurfaceRuntimeTeardownTicket.swift
  • Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface+RuntimeLifecycle.swift
  • Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface.swift
  • Packages/macOS/CmuxTerminal/Tests/CmuxTerminalTests/TerminalSurfaceRuntimeTeardownCoordinatorTests.swift
  • Packages/macOS/CmuxTerminal/Tests/CmuxTerminalTests/TerminalSurfaceTeardownCallbackLifetimeTests.swift
  • Resources/Localizable.xcstrings
  • Sources/AgentHibernation/AgentHibernationPanelPhase.swift
  • Sources/App/AgentHibernationController+CommittedTerminationCleanup.swift
  • Sources/App/AgentHibernationController+CommittedTerminationObservation.swift
  • Sources/App/AgentHibernationController+InFlightTeardown.swift
  • Sources/App/AgentHibernationController+PanelLifecycle.swift
  • Sources/App/AgentHibernationController+ProcessExitObservation.swift
  • Sources/App/AgentHibernationController+ProcessExitWaiting.swift
  • Sources/App/AgentHibernationController+ProcessSignaling.swift
  • Sources/App/AgentHibernationController+ProcessTermination.swift
  • Sources/App/AgentHibernationController+Records.swift
  • Sources/App/AgentHibernationController+ScopedProcessTerminationResult.swift
  • Sources/App/AgentHibernationController+Teardown.swift
  • Sources/App/AgentHibernationController+TeardownValidation.swift
  • Sources/App/AgentHibernationController.swift
  • Sources/App/AgentHibernationPlanner.swift
  • Sources/App/AgentHibernationProcessExitCompletion.swift
  • Sources/App/AgentHibernationProcessExitEpoch.swift
  • Sources/App/AgentHibernationProcessSnapshotCoordinator.swift
  • Sources/App/AgentHibernationTranscriptGuard+PostTeardownRestore.swift
  • Sources/CmuxTopSnapshot.swift
  • Sources/DockSplitStore+PanelDestruction.swift
  • Sources/DockSplitStore+SessionRestore.swift
  • Sources/DockSplitStore+SurfaceTransfer.swift
  • Sources/DockSplitStore.swift
  • Sources/GhosttyTerminalView.swift
  • Sources/Panels/AgentHibernationPlaceholderMode.swift
  • Sources/Panels/TerminalPanel+AgentHibernation.swift
  • Sources/Panels/TerminalPanel.swift
  • Sources/Panels/TerminalPanelView.swift
  • Sources/RestorableAgentSession.swift
  • Sources/TerminalController.swift
  • Sources/TerminalSurfaceRuntimeWiring.swift
  • Sources/Workspace+PanelLifecycle.swift
  • Sources/Workspace.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/AgentHibernationPlannerSwiftTests.swift
  • cmuxTests/AgentHibernationProcessSignalBoundaryTests.swift
  • cmuxTests/AgentHibernationProcessSnapshotCoordinatorTests.swift
  • cmuxTests/AgentHibernationProcessTerminationTests.swift
  • cmuxTests/AgentHibernationRestoreMonitorTests.swift
  • cmuxTests/AgentHibernationTerminationFailureTests.swift
  • cmuxTests/AgentHibernationTrackingLifecycleTests.swift
  • cmuxTests/AgentResumeLivenessTests.swift
  • cmuxTests/CompletedRestoredAgentGenerationTests.swift
  • cmuxTests/DockRuntimeParityTests.swift
💤 Files with no reviewable changes (1)
  • Sources/App/AgentHibernationController+InFlightTeardown.swift

Comment thread cmuxTests/AgentHibernationProcessSnapshotCoordinatorTests.swift
Comment thread cmuxTests/AgentHibernationProcessTerminationTests.swift
Comment thread cmuxTests/AgentHibernationProcessTerminationTests.swift
Comment thread Sources/App/AgentHibernationController+PanelLifecycle.swift
Comment thread Sources/App/AgentHibernationController+ProcessExitObservation.swift
Comment thread Sources/CmuxTopSnapshot.swift
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.

v0.64.20 memory grows to 30-50 GB, causes repeated WindowServer watchdog kernel panics (4 reboots in one day, 16 GB M4 Mac mini)

1 participant