Skip to content

Harden memory diagnostics for long-session surface leaks - #6267

Merged
austinywang merged 6 commits into
mainfrom
issue-6266-memory-exhaustion-4day
Jun 16, 2026
Merged

austinywang merged 6 commits into
mainfrom
issue-6266-memory-exhaustion-4day

Conversation

@austinywang

@austinywang austinywang commented Jun 16, 2026 •

Copy link
Copy Markdown
Contributor

Closes #6266

Summary

This PR does not claim a speculative renderer/WebKit/native-heap fix. I first checked the version context from #6266:

Given that, this PR ships the low-risk hardening requested in the issue:

  1. scripts/capture-memory.sh captures ps, footprint, and vmmap -summary by default, with explicit --heavy for leaks and malloc_history only on a fresh profiled instance.
  2. Sentry events carry a refreshed cmux.memory context containing app footprint/RSS/thread count and live terminal surface/runtime-surface counts. Sampling runs off the main actor and refreshes at startup plus activity-driven Sentry breadcrumb/capture points with a 5-minute throttle, with no timer or sleep loop.
  3. TerminalSurfaceRegistry exposes a bounded diagnostic snapshot, with a regression invariant proving unregistered/deallocated surfaces and freed runtime pointers drop out of the counts.

Evidence

Local live production cmux 0.64.16 (96), pid 72227, was sampled read-only with footprint and vmmap -summary:

  • Physical footprint: 1.465 GB, peak 1.485 GB after ~82 minutes.
  • Largest categories: MALLOC_SMALL 483 MB, IOSurface 431 MB, graphics unmapped 264 MB, IOAccelerator 100 MB.
  • This is not the 11 GB 0.64.14 failure shape, but it confirms the useful telemetry categories for the next recurrence.

Sentry lookup was attempted with the provided workflow, but this shell is not authenticated (sentry auth status reports not authenticated) and no Sentry token/org/project environment variables are present, so the pid 708 event could not be fetched from here.

Cloud Mac accelerated repro was attempted through the required skill. GitHub Actions run https://github.com/manaflow-ai/cmux-loader/actions/runs/27648982604 reached the VM hold step, but local discovery timed out waiting for cmux-loader-27648982604; macfleet devices also could not be used because no local token is stored. The held runner was canceled.

Testing

  • Red commit: aae49b5d7 test: add terminal surface registry diagnostics invariant fails because TerminalSurfaceRegistry.diagnosticSnapshot() does not exist.
  • Green focused test: swift test --package-path Packages/CmuxTerminalEngine --filter TerminalSurfaceRegistryTests/diagnosticSnapshotDropsUnregisteredSurfacesAndRuntimePointers
  • Script syntax/smoke: bash -n scripts/capture-memory.sh and scripts/capture-memory.sh --pid $$ --out /tmp/cmux-capture-memory-smoke-event-refresh-$$
  • Script malformed option checks for missing --pid and --out values.
  • Guard checks: ./tests/test_ci_swift_file_length_budget.sh, python3 scripts/swift_file_length_budget.py --budget .github/swift-file-length-budget.tsv, ./tests/test_ci_pbxproj_test_wiring.sh, ./scripts/check-pbxproj.sh.
  • Local policy check: /Users/austinwang/manaflow/cmuxterm-hq/skills/autoreview/scripts/cmux-policy-check --mode branch --base origin/main.

No local app build, reload.sh, bare xcodebuild, or app launch was run.

Demo Video

No demo video is available. The cloud Mac attempt did not become reachable through local Tailscale/MagicDNS, and this PR does not launch a local app build by instruction.

Checklist

Summary by CodeRabbit

  • New Features
    • Added a terminal surface diagnostic snapshot API to expose live registered and placement counts, plus runtime registration metrics.
    • Enabled refresh of Sentry memory/process context as the app launches and exits, and refreshes on relevant capture activity.
    • Introduced a new script to capture memory diagnostics for a target process (with an optional “heavy” mode).
  • Tests
    • Added coverage verifying diagnostic snapshots exclude deallocated/unregistered surfaces and stale runtime pointers.

@vercel

vercel Bot commented Jun 16, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Jun 16, 2026 10:09pm
cmux-staging Building Building Preview, Comment Jun 16, 2026 10:09pm

@coderabbitai

coderabbitai Bot commented Jun 16, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a TerminalSurfaceRegistryDiagnosticSnapshot struct and a diagnosticSnapshot() method to capture live surface counts from the registry. A new sentryRefreshMemoryContext(reason:) function enriches Sentry scope with memory and surface metrics periodically via an AppDelegate-managed task. A standalone Bash script captures macOS memory diagnostics (ps, footprint, vmmap, optionally leaks/malloc_history) for a live process.

Changes

Memory Diagnostics Infrastructure

Layer / File(s) Summary
TerminalSurfaceRegistryDiagnosticSnapshot type and API
Packages/CmuxTerminalEngine/Sources/CmuxTerminalEngine/SurfaceRegistry/TerminalSurfaceRegistryDiagnosticSnapshot.swift, Packages/CmuxTerminalEngine/Sources/CmuxTerminalEngine/SurfaceRegistry/TerminalSurfaceRegistry.swift, Packages/CmuxTerminalEngine/Tests/CmuxTerminalEngineTests/TerminalSurfaceRegistryTests.swift
Defines TerminalSurfaceRegistryDiagnosticSnapshot (Equatable & Sendable) with four integer counters (registeredSurfaceCount, workspaceSurfaceCount, rightSidebarDockSurfaceCount, runtimeSurfaceCount) and a payload() method returning snake_case dictionary keys. TerminalSurfaceRegistry.diagnosticSnapshot() computes these counts under the registry lock and returns the snapshot. Test verifies counts decrease correctly after surface and runtime pointer unregistration.
Sentry memory context refresh and AppDelegate wiring
Sources/SentryHelper.swift, Sources/AppDelegate.swift
Imports Darwin, Foundation, and CmuxTerminalEngine; stores a @MainActor-isolated task handle. sentryStartMemoryContextRefresh() launches a 300-second periodic loop guarded by telemetry settings; sentryStopMemoryContextRefresh() cancels it. sentryRefreshMemoryContext(reason:) captures CmuxTopProcessSnapshot.captureCached(), calls TerminalSurfaceRegistry.diagnosticSnapshot(), and attaches both to Sentry scope under cmux.memory via SentrySDK.configureScope() on the main actor. AppDelegate hooks the start at applicationDidFinishLaunching and the stop at applicationWillTerminate.
capture-memory.sh diagnostic script
scripts/capture-memory.sh
New Bash utility accepting --pid, --out, and --heavy flags. Validates the PID is numeric and live, creates output directory, defines run_capture() wrapper that logs commands and captures stdout/stderr per tool. Runs ps, footprint -summary, and vmmap -summary baselines; in heavy mode also runs leaks and malloc_history, otherwise writes a heavy-tools-skipped.txt note. Writes manifest.json with UTC timestamp, PID, and mode flag.

Sequence Diagram(s)

sequenceDiagram
  rect rgba(173, 216, 230, 0.5)
    Note over AppDelegate,SentrySDK: Startup
    AppDelegate->>sentryStartMemoryContextRefresh: applicationDidFinishLaunching
    sentryStartMemoryContextRefresh->>sentryRefreshMemoryContext: reason: "startup"
  end
  sentryRefreshMemoryContext->>CmuxTopProcessSnapshot: captureCached()
  CmuxTopProcessSnapshot-->>sentryRefreshMemoryContext: PID, memory, threads
  sentryRefreshMemoryContext->>TerminalSurfaceRegistry: diagnosticSnapshot()
  TerminalSurfaceRegistry-->>sentryRefreshMemoryContext: TerminalSurfaceRegistryDiagnosticSnapshot
  sentryRefreshMemoryContext->>SentrySDK: configureScope(cmux.memory)
  rect rgba(144, 238, 144, 0.5)
    Note over sentryStartMemoryContextRefresh,SentrySDK: Periodic (every 300s)
    loop
      sentryRefreshMemoryContext->>SentrySDK: configureScope(cmux.memory)
    end
  end
  rect rgba(255, 182, 193, 0.5)
    Note over AppDelegate,sentryStopMemoryContextRefresh: Teardown
    AppDelegate->>sentryStopMemoryContextRefresh: applicationWillTerminate
    sentryStopMemoryContextRefresh->>sentryStopMemoryContextRefresh: cancel task
  end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~15 minutes

Possibly related PRs

  • manaflow-ai/cmux#5929: Introduces or reshapes TerminalSurfaceRegistry implementation; this PR extends the same registry with a new diagnosticSnapshot() API for diagnostic telemetry.

Suggested reviewers

  • lawrencecchen

Poem

🐰 A snapshot of surfaces, a counter so neat,
Sentry now knows how much memory we eat.
Every five minutes the metrics refresh,
A script captures vmmap — oh how fresh!
No more 11 GB mystery bloat,
The bunny tracks leaks in each terminal boat. 🔍

🚥 Pre-merge checks | ✅ 20 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.38% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (20 passed)
Check name Status Explanation
Title check ✅ Passed The PR title directly and clearly describes the main objective: hardening memory diagnostics for long-session surface leaks, which matches the primary purpose of adding diagnostic tools and telemetry.
Linked Issues check ✅ Passed All three objectives from #6266 are directly addressed: memory capture script with --heavy flag [#6266], Sentry memory/surface context telemetry [#6266], and surface-teardown regression test [#6266].
Out of Scope Changes check ✅ Passed All changes align with the stated objectives: memory capture script, Sentry telemetry integration, registry diagnostics, and supporting app lifecycle wiring—no unrelated or scope-creep changes detected.
Cmux Swift Actor Isolation ✅ Passed Production Swift code properly isolates MainActor state with explicit @MainActor annotations on variables and functions. Boundary crossing from non-MainActor contexts uses correct Task { @MainActor...
Cmux Swift Blocking Runtime ✅ Passed No problematic blocking synchronization introduced. NSLock usage in new TerminalSurfaceRegistry is documented as necessary for nonisolated deinit paths (matching allowed exception). Memory telemetr...
Cmux Expensive Synchronous Load ✅ Passed Memory telemetry runs in Task.detached(.utility) off-main; diagnosticSnapshot() is lightweight (in-memory counting), not expensive disk/syscall work; no violation of expensive-sync-load rule.
Cmux Cache Substitution Correctness ✅ Passed Cache use (CmuxTopProcessSnapshot.captureCached) is transient telemetry only (Sentry events), not persisted to disk; has freshness checking (maximumAge: 2s) and cold-cache fallback; does not replac...
Cmux No Hacky Sleeps ✅ Passed PR adds no problematic sleeps, timers, polling, or wall-clock waits. scripts/capture-memory.sh is pure diagnostics. SentryHelper uses event-driven throttled refresh with Task.detached, not blocking...
Cmux Algorithmic Complexity ✅ Passed diagnosticSnapshot() is a single-pass O(n) scan over terminal surfaces (typically <100) throttled to 300s minimum intervals via Sentry telemetry; no nested scans, unbounded hot loops, or batch resc...
Cmux Swift Concurrency ✅ Passed PR adds no legacy async patterns: no DispatchQueue.global() for ordinary work, no Combine, no completion handlers. Fire-and-forget Task in sentryRequestMemoryContextRefresh is tied to caller-owned...
Cmux Swift @Concurrent ✅ Passed sentryRefreshMemoryContext correctly uses Task.detached for off-MainActor async work and explicit MainActor.run for context updates; no missing @concurrent, invalid @concurrent, or UI-blocking asyn...
Cmux Swift File And Package Boundaries ✅ Passed All Swift changes comply with file and package boundaries: SentryHelper.swift (130 lines, new app-specific Sentry integration glue—allowed); TerminalSurfaceRegistryDiagnosticSnapshot.swift (45 line...
Cmux Swift Logging ✅ Passed PR complies with swift-logging.md rules. No print, debugPrint, dump, or NSLog added in app/runtime Swift code. SentryHelper uses structured Sentry SDK calls (SentrySDK.configureScope, bread...
Cmux User-Facing Error Privacy ✅ Passed PR adds memory diagnostics with no user-facing error messages. New code includes: (1) capture-memory.sh with generic error/help messages, (2) SentryHelper.swift with internal telemetry gated by Tel...
Cmux Full Internationalization ✅ Passed PR adds only developer APIs, operational tooling, and internal telemetry—no user-facing UI text or localized strings requiring i18n compliance per the review rules.
Cmux Swiftui State Layout ✅ Passed No SwiftUI state layout violations detected. Changes are diagnostic snapshots, non-SwiftUI data structures, and app lifecycle integration with @MainActor-protected scheduling, not new SwiftUI state...
Cmux Architecture Rethink ✅ Passed PR does not violate swift-architectural-rethink.md. No timing/blocking repair paths, polling, duplicate ownership, or split lifecycle. Memory context runs on detached utility task with on-demand th...
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR contains no NSWindow, NSPanel, NSWindowController, SwiftUI Window or WindowGroup additions/changes. All changes are diagnostic telemetry (surface registry snapshot), Sentry integration (memory c...
Cmux Source Artifacts ✅ Passed All PR files are hand-written source code, tests, or intentional utility scripts. No local tool output, generated logs, build artifacts, caches, or temporary files detected. scripts/capture-memory....
Description check ✅ Passed The pull request description provides comprehensive context, testing details, and evidence. It addresses the template requirements with detailed sections on summary, testing approach, and checklist items.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-6266-memory-exhaustion-4day

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 and usage tips.

@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 `@scripts/capture-memory.sh`:
- Around line 21-27: The script's option parsing does not validate that required
option values are provided before executing shift 2. If --pid or --out flags are
passed without a following value (or with another flag starting with -- as the
next argument), the shift 2 command will fail with an unhelpful shell error
rather than triggering the intended usage error message. For both the --pid and
--out cases, add a validation check after capturing the second argument (using
the pid="${2:-}" and out_dir="${2:-}" pattern) to verify the captured value is
not empty and does not start with a dash. If the value is invalid or missing,
call your usage error handling function before attempting shift 2. Only execute
shift 2 after confirming a valid value was provided.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: bf56e26f-34ec-4b74-ac7b-4846ad027e2c

📥 Commits

Reviewing files that changed from the base of the PR and between 565a4d6 and 4309917.

📒 Files selected for processing (6)
  • Packages/CmuxTerminalEngine/Sources/CmuxTerminalEngine/SurfaceRegistry/TerminalSurfaceRegistry.swift
  • Packages/CmuxTerminalEngine/Sources/CmuxTerminalEngine/SurfaceRegistry/TerminalSurfaceRegistryDiagnosticSnapshot.swift
  • Packages/CmuxTerminalEngine/Tests/CmuxTerminalEngineTests/TerminalSurfaceRegistryTests.swift
  • Sources/AppDelegate.swift
  • Sources/SentryHelper.swift
  • scripts/capture-memory.sh

Comment thread scripts/capture-memory.sh
@greptile-apps

greptile-apps Bot commented Jun 16, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds three low-risk diagnostic hardening pieces: a TerminalSurfaceRegistry.diagnosticSnapshot() API that captures live surface/runtime-pointer counts under the existing lock, a Sentry memory context refresh wired to app lifecycle and rate-limited to one fire per 5 minutes via detached utility task, and a capture-memory.sh developer script for lightweight footprint/vmmap captures with an explicit --heavy guard around the expensive heap-walk tools.

  • TerminalSurfaceRegistry: diagnosticSnapshot() reads all placement counts inside the lock in one pass, releases the lock, then constructs the value-typed snapshot — the prior out-of-lock race from the original draft was correctly addressed and the regression test covers it.
  • SentryHelper: GhosttyApp.terminalSurfaceRegistry is a plain static let on an unannotated class, so accessing it from the detached task is safe; main-actor state (sentryMemoryContextRefreshTask, sentryLastMemoryContextRefresh) is consistently accessed only from @MainActor-annotated call sites.
  • capture-memory.sh: PID validation and graceful per-capture error handling are solid; one minor shell style nit on variable locality noted below.

Confidence Score: 5/5

Read-only diagnostic addition guarded by a telemetry feature flag; the only mutation is a Sentry scope update on the main actor.

All changes are non-invasive: the registry method is a bounded snapshot behind the existing lock, the Sentry refresh is rate-limited and runs off the main actor, and the shell script is developer-only tooling. No production state machine, persistence, or UI layout was modified.

No files require special attention; the only nit is a missing local declaration in scripts/capture-memory.sh.

Important Files Changed

Filename Overview
Packages/CmuxTerminalEngine/Sources/CmuxTerminalEngine/SurfaceRegistry/TerminalSurfaceRegistry.swift Adds diagnosticSnapshot() that reads all placement counts under the lock in a single pass, then constructs the value type after releasing — consistent with existing patterns and correctly addressed the prior out-of-lock race.
Packages/CmuxTerminalEngine/Sources/CmuxTerminalEngine/SurfaceRegistry/TerminalSurfaceRegistryDiagnosticSnapshot.swift New Equatable, Sendable value type carrying four bounded Int counts and a [String: Any] telemetry payload; no mutable state, no locking concerns.
Packages/CmuxTerminalEngine/Tests/CmuxTerminalEngineTests/TerminalSurfaceRegistryTests.swift Adds a regression test verifying unregistered surfaces and freed runtime pointers drop from all four snapshot fields; straightforward and correctly uses #require for unsafe pointer construction.
Sources/SentryHelper.swift Adds event-driven, rate-limited memory context refresh (300 s minimum interval) via a detached utility task; main-actor state is correctly isolated, GhosttyApp.terminalSurfaceRegistry is a plain static let on an unannotated class so the access from a detached task is safe.
Sources/AppDelegate.swift One-line start/stop hooks for memory context refresh wired to applicationDidFinishLaunching and applicationWillTerminate; guarded against XCTest launches, cancellation on quit is clean.
scripts/capture-memory.sh New developer diagnostic script with PID validation, graceful error capture, and heavy-mode guard; rc variable in run_capture is not declared local but is only read within the same subshell block.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant App as AppDelegate
    participant SH as SentryHelper (MainActor)
    participant DT as Detached Task (utility)
    participant TSR as TerminalSurfaceRegistry
    participant Sentry as SentrySDK

    App->>SH: sentryStartMemoryContextRefresh()
    SH->>SH: sentryScheduleMemoryContextRefresh(minimumInterval: 0)
    SH->>DT: "Task.detached { sentryRefreshMemoryContext() }"

    DT->>DT: CmuxTopProcessSnapshot.captureCached()
    DT->>TSR: diagnosticSnapshot()
    TSR->>TSR: "lock.lock() → count surfaces & placements → lock.unlock()"
    TSR-->>DT: TerminalSurfaceRegistryDiagnosticSnapshot
    DT->>Sentry: "MainActor.run { configureScope(cmux.memory) }"

    Note over SH: On breadcrumb / capture event (rate-limited 300s)
    SH->>DT: "Task.detached { sentryRefreshMemoryContext() }"

    App->>SH: sentryStopMemoryContextRefresh()
    SH->>DT: task.cancel()
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant App as AppDelegate
    participant SH as SentryHelper (MainActor)
    participant DT as Detached Task (utility)
    participant TSR as TerminalSurfaceRegistry
    participant Sentry as SentrySDK

    App->>SH: sentryStartMemoryContextRefresh()
    SH->>SH: sentryScheduleMemoryContextRefresh(minimumInterval: 0)
    SH->>DT: "Task.detached { sentryRefreshMemoryContext() }"

    DT->>DT: CmuxTopProcessSnapshot.captureCached()
    DT->>TSR: diagnosticSnapshot()
    TSR->>TSR: "lock.lock() → count surfaces & placements → lock.unlock()"
    TSR-->>DT: TerminalSurfaceRegistryDiagnosticSnapshot
    DT->>Sentry: "MainActor.run { configureScope(cmux.memory) }"

    Note over SH: On breadcrumb / capture event (rate-limited 300s)
    SH->>DT: "Task.detached { sentryRefreshMemoryContext() }"

    App->>SH: sentryStopMemoryContextRefresh()
    SH->>DT: task.cancel()
Loading

Reviews (2): Last reviewed commit: "fix: make memory telemetry refresh event..." | Re-trigger Greptile

Comment thread Sources/AppDelegate.swift Outdated
Comment on lines +1962 to +1973
sentryMemoryContextTask = Task { @MainActor [weak self] in
while !Task.isCancelled {
// Intended periodic telemetry refresh; cancellation is wired to app termination.
do {
try await Task.sleep(nanoseconds: 300 * 1_000_000_000)
} catch {
break
}
guard self != nil else { break }
sentryRefreshMemoryContext(reason: "periodic")
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Task.sleep polling loop in production code

The cmux-swift-blocking-runtime rule explicitly flags Task.sleep in shipped app code and requires "a real cancellation-aware scheduler, timer abstraction, async sequence, callback, notification, or state transition" instead. The rule does not allow Task.sleep in production code even for periodic work — "polling loops in shipped app/runtime code" are listed as failures by default.

The concrete replacement is a Timer.publish(every: 300, on: .main, in: .common) Combine sequence (or AsyncTimerSequence if Swift Clocks are already in the dependency graph), which drives sentryRefreshMemoryContext(reason: "periodic") without a sleeping poll loop. Cancellation can still be wired to applicationWillTerminate via the same sentryMemoryContextTask?.cancel() pattern.

Rule Used: Flag new blocking or timing-based synchronization ... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The sleep-loop concern was addressed in b263e49 as part of the Sentry helper move: periodic refresh now uses a RunLoop Timer and schedules detached refresh work, with cancellation wired through sentryStopMemoryContextRefresh().

— Claude Code

Comment on lines +119 to +120
let workspaceSurfaceCount = objects.filter { $0.focusPlacement == .workspace }.count
let rightSidebarDockSurfaceCount = objects.filter { $0.focusPlacement == .rightSidebarDock }.count

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Per-placement counts read outside the lock

workspaceSurfaceCount and rightSidebarDockSurfaceCount are derived by calling $0.focusPlacement on each object after lock.unlock(). Every other placement query in this file (isRightSidebarDockSurface) reads from the locked surfaceFocusPlacements dictionary. If any TerminalSurfacing implementation exposes focusPlacement as a mutable stored property on a class, this is an unsynchronized read that could race with register() or unregister() on a background thread.

Capturing surfaceFocusPlacements under the lock (alongside objects) and using placements[$0.id] for the filter would keep the snapshot fully within the lock boundary and consistent with the rest of the registry's access pattern.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in b263e49 by deriving placement counts from the registry's locked surfaceFocusPlacements table in a single pass, instead of reading focusPlacement after unlocking.

— Claude Code

@austinywang
austinywang merged commit 0c8449f into main Jun 16, 2026
24 checks passed
austinywang added a commit that referenced this pull request Jun 17, 2026
Resolve .github/swift-file-length-budget.tsv conflict: keep AppSection.swift
at its actual 933 lines (single entry, no duplicate) and TerminalPanel.swift at
879. Bump AppDelegate.swift ceiling 17610->17612 to reconcile pre-existing main
drift (#6267 grew the file +2 without updating the budget).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview – cmux — 6e1c61a1 Deployed Jun 16, 2026 by vercel[bot]
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.

cmux 0.64.14 reaches 11 GB physical footprint over a 4-day session, then dies (sample: idle, native/GPU/WebKit heap — not scrollback)

1 participant