Skip to content

Escape uncreatable socket state directory to /tmp; dedupe listener-failure captures per episode - #11050

Merged
azooz2003-bit merged 2 commits into
mainfrom
fix-sentry-socket-listener
Aug 31, 2026
Merged

azooz2003-bit merged 2 commits into
mainfrom
fix-sentry-socket-listener

Conversation

@azooz2003-bit

@azooz2003-bit azooz2003-bit commented Aug 28, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes the live socket.listener.start.failed loop. Prior-bad: a machine whose ~/.local/state/cmux cannot be created (root-owned after a past sudo install, or an I/O-erroring home volume) never got a listener. The bind fallback moved the shared stable path to the user-scoped sibling inside the same uncreatable directory, and applied no fallback at all when path resolution had already selected the user-scoped path (the wedged machines' breadcrumbs show wake restarts at cmux-<uid>.sock with zero fallback crumbs). Every workspace.didWake restart re-failed at stage create_lock_directory and re-captured after each 60s cooldown window, ~1400 events/day per machine forever.

Now: SocketListenerPolicy.fallbackSocketPathAfterBindFailure accepts both stable paths as the requested path and routes create_directory/create_lock_directory failures to the legacy /tmp/cmux-<uid>.sock, which CLISocketPathResolver already lists as an implicit candidate, so the listener starts and the wake loop ends. ensureSocketParentDirectoryExists unwraps the NSUnderlyingErrorKey chain to report the real POSIX errno instead of collapsing Cocoa-domain mkdir errors to EIO (the events showed a misleading "errno 5"). Listener-failure capture dedup moves from a 60s per-key cooldown to a stateful SocketListenerFailureCaptureGate: one capture per (message|stage|path|errno) key per failure episode, reset on successful listener start, and socket.listener.path.missing stays breadcrumb-only on debug-like bundle ids because dev cleanup scripts routinely delete /tmp dev sockets and the path monitor self-heals.

Commit 1 adds the failing policy and errno tests (CI red), commit 2 the fix (green). Supersedes the policy half of #9228 (same /tmp escape for the stable default) and extends it to the user-scoped path that PR left uncovered.

Sentry issues addressed:

Principled: the fallback targets the one path family the failing mechanism cannot poison, telemetry reports true errnos, and rate limiting is a single stateful reporter keyed to listener lifecycle rather than a timer. Residual risk: a machine where /tmp is also unusable still fails, now captured once per session instead of continuously.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Fixes the infinite socket.listener.start.failed loop on machines whose socket state directory (~/.local/state/cmux) can't be created (root-owned after a past sudo install, or an I/O-erroring home volume): both stable paths now fall back to the legacy /tmp/cmux-<uid>.sock, so the listener starts and the wake loop ends. Listener-failure captures are now deduped per failure episode instead of on a 60-second cooldown, cutting ~1,400 events/day per wedged machine down to one per distinct failure.

Bug Fixes

  • fallbackSocketPathAfterBindFailure now also accepts the user-scoped stable path and routes create_directory/create_lock_directory failures to the legacy /tmp per-user path, which CLISocketPathResolver already lists as a candidate.
  • ensureSocketParentDirectoryExists unwraps NSUnderlyingErrorKey chains so telemetry reports the real POSIX errno instead of collapsing Cocoa-domain mkdir errors to EIO.
  • New SocketListenerFailureCaptureGate captures once per (message|stage|path|errno) key per episode, resets on successful listener start, and keeps socket.listener.path.missing breadcrumb-only on debug-like bundle ids since dev cleanup deletes /tmp dev sockets and the path monitor self-heals.
  • Residual risk: a machine where /tmp is also unusable still fails, now captured once per session instead of continuously.

Written for commit e33c834. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Improved socket listener error reporting by preventing duplicate error captures during the same failure episode.
    • Missing socket paths can now be reported according to the app’s configuration.
  • Bug Fixes

    • Improved socket path fallback behavior when directories cannot be created or accessed.
    • Preserved more specific permission errors instead of reporting generic failures.
    • Clarified listener failure handling and fallback behavior.

azooz2003-bit and others added 2 commits August 27, 2026 21:35
…errno fidelity

Machines whose ~/.local/state/cmux cannot be created (root-owned after a
sudo install, or an I/O-erroring home volume) loop forever at stage
create_lock_directory: the current fallback routes the stable default to
a sibling inside the same uncreatable directory, and applies no fallback
at all when path resolution already selected the user-scoped sibling
(CMUXTERM-MACOS-2MHE/2FVF/25PE breadcrumbs show wake restarts at
cmux-<uid>.sock with zero fallback crumbs). The transport also collapses
Cocoa-domain mkdir errors to EIO, hiding the real errno in telemetry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-failure captures per episode

A machine whose ~/.local/state/cmux cannot be created (root-owned after a
sudo install, or an I/O-erroring home volume) never got a working socket
listener: the bind fallback moved the shared stable path to the
user-scoped sibling inside the same uncreatable directory, and applied no
fallback at all when resolution had already picked the user-scoped path.
Every wake/activation restart re-failed at create_lock_directory and
re-captured to Sentry after each 60s cooldown window (~1400 events/day
per wedged machine).

Now both stable paths escape create_directory/create_lock_directory
failures to the legacy /tmp per-user path, which the CLI already
discovers, so the listener starts and the wake loop ends. mkdir failures
surface the underlying POSIX errno instead of collapsing Cocoa-domain
errors to EIO. Listener-failure captures are deduped by a stateful gate:
once per (message|stage|path|errno) key per failure episode, reset when
the listener starts successfully, and path.missing on debug-like bundle
ids stays breadcrumb-only because dev cleanup scripts delete /tmp dev
sockets and the path monitor self-heals.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 28, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 78eeff6d-0a86-4e41-a211-c461efe48042

📥 Commits

Reviewing files that changed from the base of the PR and between aa7c922 and e33c834.

📒 Files selected for processing (8)
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Policy/SocketListenerPolicy.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Server/SocketControlServerEvents.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Server/SocketListenerFailureCaptureGate.swift
  • Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Transport/SocketTransport+Bind.swift
  • Packages/macOS/CmuxControlSocket/Tests/CmuxControlSocketTests/SocketListenerFailureCaptureGateTests.swift
  • Packages/macOS/CmuxControlSocket/Tests/CmuxControlSocketTests/SocketListenerPolicyTests.swift
  • Packages/macOS/CmuxControlSocket/Tests/CmuxControlSocketTests/SocketTransportPathTests.swift
  • Sources/TerminalController.swift

Included review availability: Your plan provides up to 10 included reviews per hour; 5 remain after this review.


📝 Walkthrough

Walkthrough

The change updates socket fallback rules, preserves underlying POSIX errnos from wrapped directory errors, and replaces cooldown-based listener failure capture with thread-safe per-episode deduplication. Tests cover fallback paths, errno handling, deduplication, suppression, and episode reset.

Changes

Socket listener handling

Layer / File(s) Summary
Socket path fallback and errno preservation
Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Policy/SocketListenerPolicy.swift, Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Transport/SocketTransport+Bind.swift, Packages/macOS/CmuxControlSocket/Tests/CmuxControlSocketTests/SocketListenerPolicyTests.swift, Packages/macOS/CmuxControlSocket/Tests/CmuxControlSocketPathTests.swift
Stable and user-scoped socket paths now apply stage-specific fallbacks. Directory-creation failures use the legacy /tmp path. Wrapped POSIX errors preserve their errno.
Failure capture gate
Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Server/SocketListenerFailureCaptureGate.swift, Packages/macOS/CmuxControlSocket/Tests/CmuxControlSocketTests/SocketListenerFailureCaptureGateTests.swift
The new gate deduplicates failure keys during each listener episode and can suppress socket.listener.path.missing failures.
Failure capture integration
Sources/TerminalController.swift, Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket/Server/SocketControlServerEvents.swift
TerminalController injects the gate, applies debug-like bundle behavior for missing paths, and resets the gate after successful listener startup. Documentation describes the new deduplication behavior.

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

Merge Risk: ⚪ Minimal · up to e33c8

The change adds a bounded socket fallback and episode-based failure reporting to prevent repeated listener failures and telemetry floods. No actionable merge-blocking risk remains after normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant TerminalController
  participant SocketListenerFailureCaptureGate
  participant Sentry
  TerminalController->>SocketListenerFailureCaptureGate: shouldCapture(message, stage, path, errnoCode)
  SocketListenerFailureCaptureGate-->>TerminalController: capture decision
  TerminalController->>Sentry: capture failure when permitted
  TerminalController->>SocketListenerFailureCaptureGate: listenerDidStart()
  SocketListenerFailureCaptureGate->>SocketListenerFailureCaptureGate: clear episode keys
Loading

Suggested reviewers: austinywang


Important

Pre-merge checks failed

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

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
Cmux Swift Blocking Runtime ❌ Error The production diff adds OSAllocatedUnfairLock<Set<String>> in SocketListenerFailureCaptureGate.swift. Its withLock calls protect mutable capture state accessed by the main actor and listener qu… Replace OSAllocatedUnfairLock with actor-owned state. Make the failure-reporting path asynchronous, or enqueue both failure and successful-start events to one actor so the lifecycle order remains correct. Do not block the listener queue o…
Docstring Coverage ⚠️ Warning Docstring coverage is 52.63% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 19 functions across 7 files. (1 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (23 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes both primary changes: the socket fallback to /tmp and per-episode listener-failure deduplication.
Description check ✅ Passed The description is detailed, relevant, and explains the changes, rationale, testing, affected issues, and residual risk. It omits the template headings and does not include the review-trigger block, c…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed No changed production code matches the stated actor-isolation failures. The new SocketListenerFailureCaptureGate is a Sendable shared reference whose mutable Set is protected by `OSAllocatedUnfa…
Cmux Browser Automation Off-Main ✅ Passed The full PR range changes only socket-listener policy, errno handling, failure capture, related tests, and listener wiring in Sources/TerminalController.swift. The TerminalController diff does not…
Cmux Expensive Synchronous Load ✅ Passed The PR does not add or move an expensive synchronous agent-history load. Added production code only changes socket fallback/errno handling, adds an in-memory locked failure gate, and wires that gate i…
Cmux Cache Substitution Correctness ✅ Passed PASS: The PR does not substitute a cache for an authoritative read. The production diff changes socket-path fallback, mkdir errno unwrapping, and Sentry failure deduplication. It does not modify persi…
Cmux No Hacky Sleeps ✅ Passed PASS: The pull request changes only Swift files, including production Swift sources and Swift tests. The custom check applies only to production TypeScript, JavaScript, shell, and build/runtime script…
Cmux Algorithmic Complexity ✅ Passed No algorithmic-complexity failure is introduced. The new SocketListenerFailureCaptureGate uses a hash Set for expected O(1) deduplication and does not scan workspace-sized data. Its only loop, in …
Cmux Swift Concurrency ✅ Passed PASS. The pull-request diff adds no prohibited legacy async pattern. The new SocketListenerFailureCaptureGate uses OSAllocatedUnfairLock for synchronous state protection and contains no `DispatchQ…
Cmux Swift @Concurrent ✅ Passed PASS: The PR diff introduces no async, nonisolated async, or @concurrent declaration. The new SocketListenerFailureCaptureGate and posixErrnoCode(from:) APIs are synchronous. The added gate …
Cmux Swift Package Boundaries ✅ Passed PASS — The pull request keeps the independently testable socket logic behind the existing CmuxControlSocket SwiftPM target. SocketListenerFailureCaptureGate, SocketListenerPolicy changes, and `S…
Cmux Swiftpm Lockfiles ✅ Passed PASS. The PR changes only Swift source and test files. Packages/macOS/CmuxControlSocket/Package.swift, .gitignore, cmux.xcodeproj/project.pbxproj, and the root Xcode Package.resolved are uncha…
Cmux Swift Logging ✅ Passed PASS: The PR adds no print, debugPrint, dump, NSLog, ad hoc file logging, stdout/stderr logging, or Logger declarations. The runtime change only gates existing sentryBreadcrumb/`sentryCapt…
Cmux User-Facing Error Privacy ✅ Passed PASS — The production diff changes socket recovery and internal Sentry telemetry only. The failure callback sends breadcrumbs and captured errors through sentryBreadcrumb/sentryCaptureError; it is…
Cmux Full Internationalization ✅ Passed PASS: The diff adds no user-facing UI, menu, alert, command, web, metadata, or localized app text. The new literals (socket.listener.path.missing, failure stages, and socket.listener.start.failed)…
Cmux Swiftui State Layout ✅ Passed PASS: The pull request does not introduce or materially expand SwiftUI state or layout code. The changed app file, Sources/TerminalController.swift, uses AppKit and changes socket listener event w…
Cmux Architecture Rethink ✅ Passed PASS. The diff does not introduce an architectural-rethink failure. The socket fallback and errno changes are small local correctness fixes. The new capture gate has one construction and one event-sea…
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PASS. The PR changes socket policy, transport error handling, failure capture, and related tests. The diff adds or modifies no user-visible NSWindow, NSPanel, NSWindowController, SwiftUI Window, Windo…
Cmux Source Artifacts ✅ Passed PASS — The PR changes only Swift source, documentation comments, and Swift test files under the expected source and test directories. The complete diff contains no artifact-like paths, binary files, g…
Cmux No Test Or Debug Seam In Production Source ✅ Passed PASS: The production diff adds no test/debug seam. SocketListenerFailureCaptureGate is a production component called by TerminalController for real listener-failure telemetry, not an accessor for …
Cmux No Ambient Global State ✅ Passed PASS: The diff adds no ambient global state that matches the failure conditions. SocketListenerFailureCaptureGate is a constructable instance type with instance-owned state and is injected at the `T…
Full details: Description check

Explanation

The description is detailed, relevant, and explains the changes, rationale, testing, affected issues, and residual risk. It omits the template headings and does not include the review-trigger block, checklist, or behavior-change demo video.

Full details: Docstring Coverage

Explanation

Docstring coverage is 52.63% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 19 functions across 7 files. (1 skipped: 1 too large.)

Full details: Cmux Swift Actor Isolation

Explanation

No changed production code matches the stated actor-isolation failures. The new SocketListenerFailureCaptureGate is a Sendable shared reference whose mutable Set is protected by OSAllocatedUnfairLock; its documentation states that it is shared by the main actor and listener queue and is thread-safe. SocketListenerPolicy and SocketTransport remain value-based Sendable types, and the new posixErrnoCode helper is pure. TerminalController remains explicitly @MainActor; the changed nonisolated event seam captures only the locked gate, while UI callbacks retain their existing actor boundaries. The PR does not add an implicitly MainActor model or service protocol, nor does it add background access to a UI store.

Full details: Cmux Swift Blocking Runtime

Explanation

The production diff adds OSAllocatedUnfairLock&lt;Set&lt;String&gt;&gt; in SocketListenerFailureCaptureGate.swift. Its withLock calls protect mutable capture state accessed by the main actor and listener queue. This is manual locking in a new cross-concurrency gate, and the diff does not document why an actor cannot own the state. The removed NSLock does not remove the new gate's manual-lock implementation. No new sleep, semaphore, delayed dispatch, or polling primitive was found.

Resolution

Replace OSAllocatedUnfairLock with actor-owned state. Make the failure-reporting path asynchronous, or enqueue both failure and successful-start events to one actor so the lifecycle order remains correct. Do not block the listener queue or main actor while obtaining the capture decision.

Full details: Cmux Browser Automation Off-Main

Explanation

The full PR range changes only socket-listener policy, errno handling, failure capture, related tests, and listener wiring in Sources/TerminalController.swift. The TerminalController diff does not change browser command routing. ControlCommandExecutionPolicy.swift is unchanged, and no added line introduces browser.* commands, WebKit waits, main-actor routing, or worker-lane browser code. The custom check is therefore not triggered.

Full details: Cmux Expensive Synchronous Load

Explanation

The PR does not add or move an expensive synchronous agent-history load. Added production code only changes socket fallback/errno handling, adds an in-memory locked failure gate, and wires that gate into existing socket lifecycle callbacks. The added production lines contain no RestorableAgentSessionIndex, agent stores, transcripts, trajectories, JSONL loads, directory scans, Data(contentsOf:), JSON decoding, or per-record history syscalls. The existing Task.detached socket connection task and unrelated file/JSON operations are unchanged.

Full details: Cmux Cache Substitution Correctness

Explanation

PASS: The PR does not substitute a cache for an authoritative read. The production diff changes socket-path fallback, mkdir errno unwrapping, and Sentry failure deduplication. It does not modify persistence, history, undo, or snapshot read paths, and no changed production line introduces a cached value for those consumers. The cache-substitution correctness check is therefore inapplicable.

Full details: Cmux No Hacky Sleeps

Explanation

PASS: The pull request changes only Swift files, including production Swift sources and Swift tests. The custom check applies only to production TypeScript, JavaScript, shell, and build/runtime scripts. The PR introduces no covered non-Swift files or delay constructs.

Full details: Cmux Algorithmic Complexity

Explanation

No algorithmic-complexity failure is introduced. The new SocketListenerFailureCaptureGate uses a hash Set for expected O(1) deduplication and does not scan workspace-sized data. Its only loop, in SocketTransport+Bind.swift, has the explicit fixed bound of eight underlying-error levels. The policy changes use fixed conditionals, and the tests use small fixed fixtures. No nested collection scan, batch rescan, repeated sorting/filtering, or data-store join appears in the changed production code.

Full details: Cmux Swift Concurrency

Explanation

PASS. The pull-request diff adds no prohibited legacy async pattern. The new SocketListenerFailureCaptureGate uses OSAllocatedUnfairLock for synchronous state protection and contains no DispatchQueue, Task, Combine, or completion-handler code. The TerminalController change only injects the gate and calls its synchronous methods. The existing Task { @mainactor in ... } path-missing hop is unchanged from origin/main and is an allowed legacy callback-to-main-actor boundary. Added tests also introduce no prohibited runtime pattern.

Full details: Cmux Swift `@Concurrent`

Explanation

PASS: The PR diff introduces no async, nonisolated async, or @concurrent declaration. The new SocketListenerFailureCaptureGate and posixErrnoCode(from:) APIs are synchronous. The added gate call runs synchronously from the existing @MainActor callback and performs only locked set operations. No new CPU-heavy, file-heavy, parsing-heavy, or network-heavy async call from UI isolation is present.

Full details: Cmux Swift Package Boundaries

Explanation

PASS — The pull request keeps the independently testable socket logic behind the existing CmuxControlSocket SwiftPM target. SocketListenerFailureCaptureGate, SocketListenerPolicy changes, and SocketTransport errno handling are under Packages/macOS/CmuxControlSocket/Sources/CmuxControlSocket, with matching package tests under its test target. Sources/TerminalController.swift only performs app-lifecycle composition and injects the gate into host callbacks, which the boundary rules allow. No changed production domain logic remains in the app target.

Full details: Cmux Swiftpm Lockfiles

Explanation

PASS. The PR changes only Swift source and test files. Packages/macOS/CmuxControlSocket/Package.swift, .gitignore, cmux.xcodeproj/project.pbxproj, and the root Xcode Package.resolved are unchanged. No package dependency, package-reference, workflow, or ignore-policy change requires a lockfile diff.

Full details: Cmux Swift Logging

Explanation

PASS: The PR adds no print, debugPrint, dump, NSLog, ad hoc file logging, stdout/stderr logging, or Logger declarations. The runtime change only gates existing sentryBreadcrumb/sentryCaptureError calls through SocketListenerFailureCaptureGate; it does not add a logging destination or new sensitive payload. The diff also contains no new secret or personal-data logging.

Full details: Cmux User-Facing Error Privacy

Explanation

PASS — The production diff changes socket recovery and internal Sentry telemetry only. The failure callback sends breadcrumbs and captured errors through sentryBreadcrumb/sentryCaptureError; it is not wired to UI text, CLI responses, or API error bodies. New strings are socket stages, errno data, and paths, with no vendor/provider details, secrets, tokens, headers, raw upstream messages, or payload dumps. References to Sentry, sudo, and internal incident identifiers occur only in source documentation/comments or tests, which the rule allows.

Full details: Cmux Full Internationalization

Explanation

PASS: The diff adds no user-facing UI, menu, alert, command, web, metadata, or localized app text. The new literals (socket.listener.path.missing, failure stages, and socket.listener.start.failed) are socket telemetry/protocol identifiers used for Sentry breadcrumbs and capture, not displayed copy. The added prose is developer-facing Swift documentation and comments. No string catalog or web locale files require updates.

Full details: Cmux Swiftui State Layout

Explanation

PASS: The pull request does not introduce or materially expand SwiftUI state or layout code. The changed app file, Sources/TerminalController.swift, uses AppKit and changes socket listener event wiring only. The new SocketListenerFailureCaptureGate is a non-SwiftUI Sendable class. The diff adds no ObservableObject, @Published, @Observable, GeometryReader, lazy/list row store references, or render-time state mutations.

Full details: Cmux Architecture Rethink

Explanation

PASS. The diff does not introduce an architectural-rethink failure. The socket fallback and errno changes are small local correctness fixes. The new capture gate has one construction and one event-seam owner. Its lock protects a narrow cross-thread telemetry set; it does not add timing, polling, delayed dispatch, or lifecycle repair. The previous TerminalController NSLock and cooldown cache are removed. SocketControlServer remains the authoritative owner of listener lifecycle state, and the existing synchronous listenerDidStart transition resets the gate. No duplicate entrypoint wiring or UI lifecycle ownership changes were introduced.

Full details: Cmux Swift Auxiliary Window Close Shortcuts

Explanation

PASS. The PR changes socket policy, transport error handling, failure capture, and related tests. The diff adds or modifies no user-visible NSWindow, NSPanel, NSWindowController, SwiftUI Window, WindowGroup, close-shortcut handler, or window identifier assignment. The deterministic lint also passes: scripts/lint_auxiliary_window_close_shortcuts.py checked 36 identifiers.

Full details: Cmux Source Artifacts

Explanation

PASS — The PR changes only Swift source, documentation comments, and Swift test files under the expected source and test directories. The complete diff contains no artifact-like paths, binary files, generated logs, caches, build output, or scratch directories. The /tmp paths appear only as deliberate runtime test fixtures and product fallback strings.

Full details: Cmux No Test Or Debug Seam In Production Source

Explanation

PASS: The production diff adds no test/debug seam. SocketListenerFailureCaptureGate is a production component called by TerminalController for real listener-failure telemetry, not an accessor for private state. Its public API is used by the application, and its tests use @testable import from the test target. The other production changes add socket fallback logic and a private errno-unwrapping helper. No new #if DEBUG test accessor, ForTesting/TestHook member, or wrapper around widened state was added.

Full details: Cmux No Ambient Global State

Explanation

PASS: The diff adds no ambient global state that matches the failure conditions. SocketListenerFailureCaptureGate is a constructable instance type with instance-owned state and is injected at the TerminalController composition seam. Its only static member is the permitted pathMissingMessage constant. The new posixErrnoCode helper is private and scoped to SocketTransport; it is not a top-level API. The diff adds no top-level production API function, mutable global, static-only namespace, or shared/standard/default singleton. It also removes the previous listener capture globals.

  • Fix all pre-merge checks with AI
✨ 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 fix-sentry-socket-listener

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.

@azooz2003-bit
azooz2003-bit merged commit 97da40e into main Aug 31, 2026
7 checks passed
rustybret pushed a commit to rustybret/bmux that referenced this pull request Aug 31, 2026
23866f3 CLI Sentry: per-failure-class fingerprints, mute Not-connected race, throttle timeouts (manaflow-ai#11051)
aa865fb iOS: opening a workspace restores its last opened tab (manaflow-ai#11188)
97da40e Escape uncreatable socket state directory to /tmp; dedupe listener-failure captures per episode (manaflow-ai#11050)
ammachado pushed a commit to ammachado/cmux that referenced this pull request Sep 1, 2026
…ilure captures per episode (manaflow-ai#11050)

* Add failing tests for stable-socket state-directory escape and mkdir errno fidelity

Machines whose ~/.local/state/cmux cannot be created (root-owned after a
sudo install, or an I/O-erroring home volume) loop forever at stage
create_lock_directory: the current fallback routes the stable default to
a sibling inside the same uncreatable directory, and applies no fallback
at all when path resolution already selected the user-scoped sibling
(CMUXTERM-MACOS-2MHE/2FVF/25PE breadcrumbs show wake restarts at
cmux-<uid>.sock with zero fallback crumbs). The transport also collapses
Cocoa-domain mkdir errors to EIO, hiding the real errno in telemetry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Escape uncreatable socket state directory to /tmp and dedupe listener-failure captures per episode

A machine whose ~/.local/state/cmux cannot be created (root-owned after a
sudo install, or an I/O-erroring home volume) never got a working socket
listener: the bind fallback moved the shared stable path to the
user-scoped sibling inside the same uncreatable directory, and applied no
fallback at all when resolution had already picked the user-scoped path.
Every wake/activation restart re-failed at create_lock_directory and
re-captured to Sentry after each 60s cooldown window (~1400 events/day
per wedged machine).

Now both stable paths escape create_directory/create_lock_directory
failures to the legacy /tmp per-user path, which the CLI already
discovers, so the listener starts and the wake loop ends. mkdir failures
surface the underlying POSIX errno instead of collapsing Cocoa-domain
errors to EIO. Listener-failure captures are deduped by a stateful gate:
once per (message|stage|path|errno) key per failure episode, reset when
the listener starts successfully, and path.missing on debug-like bundle
ids stays breadcrumb-only because dev cleanup scripts delete /tmp dev
sockets and the path monitor self-heals.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant