Skip to content

Name lane-failure and send-queue-overflow iroh session close reasons - #8834

Merged
azooz2003-bit merged 2 commits into
mainfrom
feat-iroh-reason-map
Jul 24, 2026
Merged

azooz2003-bit merged 2 commits into
mainfrom
feat-iroh-reason-map

Conversation

@azooz2003-bit

@azooz2003-bit azooz2003-bit commented Jul 24, 2026 •

Copy link
Copy Markdown
Collaborator

Field evidence (2026-07-23, host ring captured on a MacBook during the WiFi path-flap reconnect loop): dozens of admitted iroh session deaths logged transportSessionLifecycle a=7 (applicationLaneFailed) with sessionClosed b=255 (unknown), plus a=4 (controlWriteFailed) with b=17 (protocolViolation) 2-5 seconds after admission. Neither label names the kill mechanism, so cmuxdiag rings stayed indecisive.

#8716 pinned IrohError.message() tokens for stream read/write errors, which arrive wrapped as ConnectionLost(...). Connection-level operations (accept_bi, open_bi, accept_uni, open_uni) throw the bare iroh::endpoint::ConnectionError instead: iroh-ffi 1.0.2-cmux.4 formats it with anyhow!("{:?}"), so the host lane-accept loop sees TimedOut, LocallyClosed, Reset, ApplicationClosed(..), ConnectionClosed(..), TransportError(..), VersionMismatch, or CidsExhausted with no wrapper (noq ConnectionError at manaflow-ai/noq@2271bbc, via the manaflow-ai/iroh fork). None matched, so every lane-failure exit classified unknown. New bare-token mappings, mirroring the wrapped forms:

bare token DiagnosticFailureKind
TimedOut transportIdleTimedOut (21)
LocallyClosed cancelled (20)
Reset connectionClosed (18)
ApplicationClosed( / ConnectionClosed( / TransportError( connectionClosed (18)
TransportError( + Code::crypto( or TLS error: secureChannelFailed (7)
VersionMismatch protocolViolation (17)
CidsExhausted endpointUnavailable (12)

The a=4/b=17 deaths were not write errors at all: no error thrown on the control write path can classify to protocolViolation. They came from MobileHostConnection.sendEvent's bounded event-queue overflow close, which hardcoded .protocolViolation. During a path flap the drain task blocks inside the QUIC write while terminal deltas keep queueing; 256 events fill within seconds and the host kills the session, which matches the observed 2-5s timing. That close now uses the new appended DiagnosticFailureKind.sendQueueOverflow = 24 (no existing case renumbered). Both Connection Report UIs (macOS Settings > Networking, iOS Iroh settings) render the new kind, localized en+ja across all three string catalogs. The two frame-encode closes keep protocolViolation with comments: MobileSyncFrameCodec.encodeFrame only throws frameTooLarge, a genuine local wire-limit violation.

Not done: recording a raw or hashed unknown-error string into the event payload. sessionClosed has a/b/c taken (transport, failure, session ID), ms is documented as a millisecond magnitude, and the diagnostics design deliberately excludes string payloads; hashes of full Debug messages also would not match precomputed candidates because they embed dynamic codes and reasons. With the noq error vocabulary now enumerated, residual unknowns should be structurally rare, and host os_log retains the raw string privately at each classify site.

Commit 1 adds the failing token table only (8 of 9 new rows red); commit 2 adds the fix. swift test passes for CmuxIrohTransport (465 tests) and CMUXMobileCore (283 tests); CmuxSettingsUI builds. Localization audit: the only new user-facing string is the failure label, added with en+ja entries to Resources/Localizable.xcstrings, the CmuxMobileShellUI package catalog, and ios/cmux/Resources/Localizable.xcstrings.

🤖 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

Improves iroh session diagnostics by mapping previously “unknown” lane failures and introducing a clear reason for send-queue overflow. This makes rings and Settings UIs show accurate close causes, especially during path flaps.

  • Bug Fixes

    • Map bare iroh ConnectionError tokens to DiagnosticFailureKind: TimedOut, LocallyClosed, Reset, ApplicationClosed(...), ConnectionClosed(...), TransportError(...), VersionMismatch, CidsExhausted (no more unknown).
    • Tests in CmuxIrohTransport and CMUXMobileCore pin the new classifications.
  • New Features

    • Add sendQueueOverflow = 24 and use it for the host’s bounded control send-queue close (was protocolViolation).
    • Render “Send Queue Overflow” in macOS and iOS settings (CmuxSettingsUI, CmuxMobileShellUI), localized in en and ja.

Written for commit 532ca81. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Added a “Send Queue Overflow” diagnostic reason for clearer connection failure reporting.
    • Added English and Japanese translations across mobile and desktop settings.
    • Expanded diagnostic classification for additional timeout, closure, reset, protocol, and transport error formats.
  • Bug Fixes

    • Improved accuracy when identifying connection failures from transport errors.
    • Queue capacity failures are now reported with their specific diagnostic reason instead of a generic protocol error.

azooz2003-bit and others added 2 commits July 23, 2026 23:32
These Debug tokens reach IrohError.message() from connection-level
operations (accept_bi/open_bi) without the ConnectionLost(...) wrapper
and currently classify as unknown (b=255 in the 2026-07-23 host ring).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bare iroh::endpoint::ConnectionError Debug tokens (TimedOut,
LocallyClosed, Reset, ApplicationClosed(...), ConnectionClosed(...),
TransportError(...), VersionMismatch, CidsExhausted) now map to honest
DiagnosticFailureKinds instead of unknown, and the host's bounded event
queue overflow close is labeled with the new appended
sendQueueOverflow = 24 instead of protocolViolation.

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

coderabbitai Bot commented Jul 24, 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: eaf24557-635b-4161-96e5-99b487ee55ff

📥 Commits

Reviewing files that changed from the base of the PR and between 60cb463 and 532ca81.

📒 Files selected for processing (10)
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/DiagnosticTaxonomy.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/DiagnosticLogTests.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohDiagnosticFailure.swift
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohDiagnosticFailureTests.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/MobileIrohSettingsView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/Resources/Localizable.xcstrings
  • Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/IrohNetworkingSection.swift
  • Resources/Localizable.xcstrings
  • Sources/Mobile/MobileHostService.swift
  • ios/cmux/Resources/Localizable.xcstrings

📝 Walkthrough

Walkthrough

The change adds explicit queue-overflow diagnostics, broadens Iroh error classification for unwrapped connection errors, verifies stable taxonomy mappings, and displays localized queue-overflow labels in mobile and macOS settings.

Changes

Diagnostic reporting updates

Layer / File(s) Summary
Queue overflow failure contract
Packages/Shared/CMUXMobileCore/..., Sources/Mobile/MobileHostService.swift, Packages/Shared/CMUXMobileCore/Tests/...
The bounded event queue now reports .sendQueueOverflow, with documentation and a stable raw-value assertion for 24.
Iroh connection error classification
Packages/Shared/CmuxIrohTransport/...
Classification recognizes direct TransportError( and additional bare connection-level tokens, with tests for pinned Iroh FFI error formats.
Settings diagnostic presentation
Packages/iOS/CmuxMobileShellUI/..., Packages/macOS/CmuxSettingsUI/..., Resources/Localizable.xcstrings, ios/cmux/Resources/Localizable.xcstrings
Mobile and macOS settings display localized “Send Queue Overflow” text in English and Japanese.

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

Sequence Diagram(s)

sequenceDiagram
  participant MobileHostConnection
  participant DiagnosticFailureKind
  participant MobileIrohSettingsView
  participant IrohNetworkingSection
  MobileHostConnection->>DiagnosticFailureKind: record sendQueueOverflow
  DiagnosticFailureKind->>MobileIrohSettingsView: provide lastFailureKind
  DiagnosticFailureKind->>IrohNetworkingSection: provide lastFailureKind
  MobileIrohSettingsView->>MobileIrohSettingsView: localize queue overflow label
  IrohNetworkingSection->>IrohNetworkingSection: localize queue overflow label
Loading

Possibly related PRs

  • manaflow-ai/cmux#8716: Updates shared diagnostic taxonomy, Iroh error classification, and related UI plumbing for a different failure kind.

Important

Pre-merge checks failed

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

❌ Failed checks (1 error, 2 warnings)

Check name Status Explanation Resolution
Cmux Full Internationalization ❌ Error Resources/Localizable.xcstrings adds settings.networking.diagnostics.failure.sendQueueOverflow only for en/ja, but the catalog already supports 19 locales. Add translated entries for the 17 missing locales in the root app catalog (ar, bs, da, de, es, fr, it, ko, nb, pl, pt-BR, ru, th, tr, uk, zh-Hans, zh-Hant).
Description check ⚠️ Warning The description has useful details, but it misses required template sections for Demo Video, Review Trigger, and Checklist. Rewrite it using the repo template: add explicit Summary, Testing, Demo Video, Review Trigger, and Checklist sections, plus local test/manual verification details.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (22 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately reflects the main change: adding a new send-queue-overflow close reason and broader lane-failure mappings.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed PASS: Changes are a value enum, @MainActor SwiftUI views, and actor-backed service code; no new implicit MainActor models, unsafe Sendable refs, or cross-actor store access.
Cmux Swift Blocking Runtime ✅ Passed Diff only adds diagnostic mappings/localization/comments; no new semaphores, sleeps, main-sync, or locks were introduced or expanded.
Cmux Browser Automation Off-Main ✅ Passed Diff only touches diagnostic taxonomy, transport failure labeling, UI/localization, and tests; it doesn’t modify browser automation routing or wait paths.
Cmux Expensive Synchronous Load ✅ Passed Diff only adds diagnostic enum/classifier/UI labels and a queue-overflow failure path; no synchronous agent-history loads, scans, or JSONL parsing were introduced.
Cmux Cache Substitution Correctness ✅ Passed The diff only reclassifies event-queue overflow and updates diagnostics/UI; no authoritative read was replaced by a cache in a persistence/history/undo/snapshot path.
Cmux No Hacky Sleeps ✅ Passed The PR only changes Swift sources, tests, and localization catalogs; no TS/JS/shell/build/runtime files were added with sleeps or polling.
Cmux Algorithmic Complexity ✅ Passed Changed paths use O(1) bounded-queue checks and fixed-size switch/token matching; no new scalable collection rescans or hot-path sorts/filters.
Cmux Swift Concurrency ✅ Passed The diff only adds comments, one enum case, and UI/localization mappings; no new DispatchQueue, Combine, completion-handler, or fire-and-forget Task patterns were introduced.
Cmux Swift @Concurrent ✅ Passed The PR only adds a new failure kind, mappings, and localization/comments; it introduces no new nonisolated async work or invalid @concurrent usage.
Cmux Swift Package Boundaries ✅ Passed The app-target edits are lifecycle/glue (host connection queue close and UI labels); reusable diagnostic logic lives in Shared SwiftPM packages, so no boundary violation.
Cmux Swiftpm Lockfiles ✅ Passed No package/Xcode/.gitignore/workflow/dependency files changed, so the SwiftPM lockfile policy isn’t implicated by this PR.
Cmux Swift Logging ✅ Passed Patch only changes comments/classification/localization; no added print/debugPrint/NSLog/ad hoc logs or secret-bearing logs were introduced.
Cmux User-Facing Error Privacy ✅ Passed New user-facing failure labels are generic (“Send Queue Overflow”); no raw upstream tokens or sensitive details were added to visible error text.
Cmux Swiftui State Layout ✅ Passed The SwiftUI diffs only extend existing failureKindText switch cases and labels; no new ObservableObject, GeometryReader, lazy-row store refs, or render-time state writes were introduced.
Cmux Architecture Rethink ✅ Passed Small correctness fix: adds sendQueueOverflow and broader iroh token mapping with named invariants; no new timing, polling, ownership split, or side-channel machinery.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed Diff only changes diagnostics/UI views and localization; no NSWindow/NSPanel/NSWindowController/WindowGroup or cmuxAuxiliaryWindowIdentifiers changes, so the rule is not triggered.
Cmux Source Artifacts ✅ Passed All changed paths are intentional source, tests, or localization catalogs; none are logs, caches, build output, temp, or other artifact directories.
Cmux No Test Or Debug Seam In Production Source ✅ Passed Only product logic/comment changes were added; no new DEBUG-gated test hook or debug/test accessor appeared in production Sources files.
Cmux No Ambient Global State ✅ Passed PASS: changes are confined to enum case, private instance methods, and localized UI branches; no new file-scope funcs or singletons were introduced.
✨ 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 feat-iroh-reason-map

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

❤️ Share

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

@greptile-apps

greptile-apps Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes two sessionClosed b=255 (unknown) classification gaps observed in field host rings during a 2026-07-23 WiFi path-flap: iroh connection-level operations surface ConnectionError variants as bare Debug tokens (no ConnectionLost(...) wrapper), none of which matched the existing classifier, and the bounded event-queue overflow close hardcoded .protocolViolation when the peer was not at fault.

  • Adds 8 bare-token mappings to CmxIrohDiagnosticFailure.swift (TimedOut, LocallyClosed, VersionMismatch, CidsExhausted, ApplicationClosed(, ConnectionClosed(, TransportError(, Reset) and broadens the secureChannelFailed TLS guard from ConnectionLost(TransportError( to bare TransportError(, with a deliberate ordering that makes non-crypto transport errors land at .connectionClosed before reaching the later TLS keyword fallback.
  • Introduces DiagnosticFailureKind.sendQueueOverflow = 24 (no renumbering), changes the queue-overflow close in MobileHostService.sendEvent from .protocolViolation to the new kind, and surfaces the label as a localized string in both the macOS Settings Networking section and iOS Iroh settings view, with en+ja entries in all three string catalogs.

Confidence Score: 4/5

Safe to merge; the behavioral changes are well-scoped to diagnostic classification with thorough test coverage for all new token mappings.

The classification ordering in CmxIrohDiagnosticFailure.swift carries one non-obvious maintenance trap: the new bare TransportError( arm at line 69 silently shadows the later TLS keyword fallback for any message that contains TransportError( without an explicit Code::crypto( or TLS error: marker. This is intentional per the PR's vocabulary analysis, but lacks an inline comment tying the ordering to that invariant. Everything else — enum addition, raw-value uniqueness test, UI switch coverage, localization in all three catalogs — is correct and complete.

Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohDiagnosticFailure.swift — specifically the ordering relationship between the new bare-token block and the TLS/crypto keyword fallback below it.

Important Files Changed

Filename Overview
Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohDiagnosticFailure.swift Widens TransportError( secureChannelFailed guard from ConnectionLost(TransportError( to bare form, then adds a bare-token block covering TimedOut, LocallyClosed, VersionMismatch, CidsExhausted, ApplicationClosed(, ConnectionClosed(, TransportError(, and Reset; the bare TransportError( catch at line 69 now preempts the later TLS-keyword fallback for non-crypto transport errors.
Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/DiagnosticTaxonomy.swift Appends sendQueueOverflow = 24 before the unknown = 255 sentinel; raw value is unique and confirmed by new uniqueness assertion in the test.
Sources/Mobile/MobileHostService.swift Changes event-queue-overflow session close from .protocolViolation to .sendQueueOverflow, adds explanatory comments at both encode-failure close sites clarifying why protocolViolation is still correct there.
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/MobileIrohSettingsView.swift Adds case .some(.sendQueueOverflow) to the exhaustive DiagnosticFailureKind? switch; uses the correct L10n.string localized API with matching catalog key.
Packages/macOS/CmuxSettingsUI/Sources/CmuxSettingsUI/Sections/IrohNetworkingSection.swift Adds case .some(.sendQueueOverflow) to the macOS exhaustive switch; uses String(localized:defaultValue:) with the matching catalog key.
Resources/Localizable.xcstrings Adds settings.networking.diagnostics.failure.sendQueueOverflow with en and ja translated entries; format matches surrounding catalog entries.
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/Resources/Localizable.xcstrings Adds mobile.iroh.diagnostics.failure.sendQueueOverflow with en and ja translated entries to the CmuxMobileShellUI package catalog.
ios/cmux/Resources/Localizable.xcstrings Adds mobile.iroh.diagnostics.failure.sendQueueOverflow with en and ja translated entries to the iOS app catalog.
Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/DiagnosticLogTests.swift Pins sendQueueOverflow.rawValue == 24 and adds a Set-based uniqueness assertion across all allCases raw values; unknown.rawValue == 255 is still asserted.
Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohDiagnosticFailureTests.swift Adds nine new test rows for all new bare token mappings, including a non-crypto TransportError → connectionClosed and a crypto TransportError → secureChannelFailed row, confirming the step-3 / step-10 ordering.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[IrohError message] --> B{Wrapped ConnectionLost form?}
    B -->|TimedOut| C[transportIdleTimedOut]
    B -->|LocallyClosed| D[cancelled]
    B -->|TransportError plus crypto code| E[secureChannelFailed]
    B -->|Reset or TransportError or AppClosed| F[connectionClosed]
    B -->|no match| G{DNS keywords?}
    G -->|yes| H[dnsFailed]
    G -->|no| I{NEW bare token block}
    I -->|TimedOut| C
    I -->|LocallyClosed| D
    I -->|VersionMismatch| J[protocolViolation]
    I -->|CidsExhausted| K[endpointUnavailable]
    I -->|ApplicationClosed, ConnectionClosed, TransportError, Reset| F
    I -->|no match| L{Generic fallbacks}
    L -->|timed out| M[timedOut]
    L -->|TLS or Handshake keywords| E
    L -->|ConnectionLost or ClosedStream| F
    L -->|no match| N[unknown]

    subgraph MobileHostService sendEvent
        O[queue overflow] -->|was protocolViolation| P[sendQueueOverflow 24]
        Q[frame encode error] --> R[protocolViolation unchanged]
    end
Loading

Reviews (1): Last reviewed commit: "Name lane-failure and send-queue-overflo..." | Re-trigger Greptile

Comment on lines +67 to +72
if message.contains("ApplicationClosed(")
|| message.contains("ConnectionClosed(")
|| message.contains("TransportError(")
|| message.contains("Reset") {
return .connectionClosed
}

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 Bare TransportError( now shadows TLS keyword fallback

The bare TransportError( arm at line 69 causes any message containing TransportError( without an explicit Code::crypto( or TLS error: marker to return .connectionClosed before reaching the TLS/crypto keyword block at lines 78-87 (Handshake, certificate, TLS, CryptoError, etc.). In the old code those fallbacks were reachable for unwrapped TransportError( payloads that embed TLS-adjacent language in their reason strings (e.g. TransportError(Error { code: Code(1), reason: "TLS handshake failed" })), which would have matched Handshake → .secureChannelFailed; now they classify as .connectionClosed. The PR description states iroh always emits Code::crypto( for QUIC crypto errors, which makes this intentional — but a brief comment here tying the ordering to that vocabulary guarantee would make the invariant explicit and prevent a future contributor from moving the TLS keyword block above this arm to "improve coverage" and inadvertently changing both paths.

@azooz2003-bit
azooz2003-bit merged commit e513686 into main Jul 24, 2026
8 checks passed
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