Skip to content

Comprehensive Sentry telemetry for iroh/transport failures (iOS + macOS) - #9305

Merged
azooz2003-bit merged 5 commits into
mainfrom
feat-iroh-sentry-diagnostics
Jul 31, 2026
Merged

azooz2003-bit merged 5 commits into
mainfrom
feat-iroh-sentry-diagnostics

Conversation

@azooz2003-bit

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

Copy link
Copy Markdown
Collaborator

Every iroh/transport failure a user can hit is now diagnosable from Sentry alone, on both the iOS client and the macOS host, without pulling logs off the device by hand.

The existing DiagnosticLog ring (fixed integer taxonomy, privacy-safe by construction) gains a single event tap delivered on its drain task. A new shared TransportSentryReporter (Packages/Shared/CmuxSentryTelemetry) consumes it and emits three surfaces: a scrubbed breadcrumb per event (category transport, decoded names, so crashes and hangs carry the recent connection timeline), a budget-limited Sentry structured log line per event (enableLogs, 300/hour sliding budget so retry storms cannot flood quota), and, for failures that cross the pure TransportIncidentPolicy gates, a Sentry event fingerprinted by code/failureKind/transportKind signature with the compact cmuxdiag v1 ring export attached. The policy coalesces repeats behind a 10-minute per-signature cooldown, caps failure captures at 30/hour, escalates 5+ consecutive failures over 60s with no success into one error-severity transport-outage issue, and suppresses what an operator can already attribute (cancelled/superseded churn, offline while reachability reports no network, idle timeout while backgrounded). Reachability, app phase, streak counts, and seconds-since-last-success ride on every capture.

To unlock iOS, the pure scrubbing layer moved from the macOS-only CmuxFoundation to the shared package (CmuxSentryScrubbing + CmuxSentryReporting glue; mac app and CLI re-linked, existing tests moved). iOS crash reporting now installs beforeSend scrubbing (plus the existing consent gate), beforeBreadcrumb, beforeSendLog, and enableLogs; swizzling and automatic network capture stay off. macOS enables logs and taps MobileHostIrohRuntime.hostDiagnosticLog (role macHost) after SentrySDK.start. pairFail now records the classified DiagnosticFailureKind in its b slot so pairing failures group by cause. Design notes in docs/transport-sentry-diagnostics.md.

Tests: 340 CMUXMobileCore (new tap/presentation/policy suites), 65 CmuxSentryTelemetry (reporter, budget, log scrub, moved scrubber suites), 16 CmuxMobileCrashReporting (new scrub/log-gate contract tests). Verified live on the tagged mac build: category = transport breadcrumbs in the SDK debug stream, envelopes written and accepted by ingest, log-batch envelopes at transport-activity timestamps, and the host ring exporting a real relayPolicyRefreshFailed/policyUnavailable failure.

No user-facing strings added (telemetry only); localization audit not applicable.

🤖 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

Adds end-to-end Sentry telemetry for iroh/transport failures on iOS and macOS so we can diagnose issues from Sentry alone, without pulling device logs. Events are scrubbed, budgeted, grouped, and outage‑escalated to reduce noise and protect privacy.

  • New Features

    • Added DiagnosticLog.setEventTap(_:) to stream retained events to telemetry sinks.
    • Introduced DiagnosticEventPresentation for stable, human-readable event names and fields.
    • Added TransportIncidentPolicy to throttle and group failures (10‑min per-signature cooldown, 30/hour cap) and escalate outages (5+ consecutive failures in 60s) while suppressing attributable noise (cancelled/superseded, offline, background idle).
    • New CmuxSentryTelemetry package:
      • CmuxSentryScrubbing for shared, testable value scrubbing.
      • CmuxSentryReporting with TransportSentryReporter that emits:
        • Breadcrumbs (category transport) per event.
        • Structured logs with a sliding 300/hour budget.
        • Sentry events for gated failures, fingerprinted by code/failureKind/transportKind and attaching the compact ring export.
    • iOS: enabled beforeSend, beforeBreadcrumb, beforeSendLog, and enableLogs; swizzling and automatic network capture remain off.
    • macOS: starts reporting after SentrySDK.start and taps the host transport ring; carries reachability, app phase, streaks, and time-since-last-success on captures. pairFail records DiagnosticFailureKind for better grouping.
    • Added docs (docs/transport-sentry-diagnostics.md) and extensive tests across CMUXMobileCore, CmuxSentryTelemetry, and iOS crash reporting.
  • Bug Fixes

    • Event tap now honors an admission floor: installing a tap no longer delivers pre-install queued events.
    • Incident policy no longer stamps cooldown on budget-dropped captures, preventing phantom cooldowns when the budget window slides.
    • Structured-log scrubbing now handles string-array attributes and writes back via SentryLog.Attribute.
    • One pairFail is recorded per exhausted connect (with transport in a and DiagnosticFailureKind in b), avoiding double-counted outage streaks; presentation decodes transport for pairFail and routeUnavailable.
    • Aligned iOS workspace lockfiles to sentry-cocoa 9.24.0; introduced CmuxSentryTelemetry and linked where needed.

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

Review in cubic

Summary by CodeRabbit

  • New Features
    • Added privacy-safe transport diagnostics with breadcrumbs, structured logs, failure incidents, and outage escalation.
    • Added human-readable diagnostic event details and failure classifications.
    • Added consent-aware crash and telemetry reporting across supported platforms.
  • Bug Fixes
    • Pairing failures now include their classified failure type for clearer diagnostics.
    • Sensitive information is redacted from events, logs, breadcrumbs, URLs, and user paths.
    • Diagnostic reporting now suppresses expected failures and limits repeated or excessive reports.
  • Documentation
    • Added guidance for interpreting transport diagnostic reports and attachments.

azooz2003-bit and others added 4 commits July 30, 2026 23:21
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… policy

DiagnosticLog gains a single settable event tap delivered on the drain task
(after ring retention, so selected-path dedup is respected and the hot-path
record() stays untouched). DiagnosticEventPresentation decodes events into
stable case names and per-code fields for telemetry sinks. Pure
TransportIncidentPolicy turns the failure stream into a bounded set of
reportable incidents: per-signature cooldown with coalesced counts, hourly
capture budget, sustained-streak outage escalation, and suppression of
attributable noise (cancelled/superseded churn, offline-while-unreachable,
idle timeout while backgrounded). pairFail now records the classified
DiagnosticFailureKind in its b slot so pairing failures group by cause.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
TransportSentryReporter (CmuxSentryReporting) consumes the DiagnosticLog tap:
every retained event becomes a scrubbed breadcrumb and a budget-limited
structured log line, and failures that cross TransportIncidentPolicy's gates
become Sentry events fingerprinted by code/failure/transport signature with
the compact diagnostic ring export attached, so one issue carries the full
connection timeline that previously had to be pulled off the device by hand.

iOS gains the shared last-mile scrubber it was waiting on: beforeSend now
scrubs (in addition to the consent gate), beforeBreadcrumb and beforeSendLog
are installed, and enableLogs is on; swizzling and automatic network capture
stay off. macOS enables logs, scrubs them, and taps the Mac host's
hostDiagnosticLog with role macHost after SentrySDK.start.

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

coderabbitai Bot commented Jul 31, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds shared diagnostic presentation and incident policy types, privacy scrubbing, and a Sentry transport reporter. It connects these components to iOS, Mac, CLI, and Xcode targets with consent controls, event taps, structured logs, attachments, and tests.

Changes

Diagnostic event processing

Layer / File(s) Summary
Diagnostic presentation contracts
Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/DiagnosticEventPresentation.swift, DiagnosticEventCode.swift, Packages/iOS/CmuxMobileShell/..., Packages/Shared/CMUXMobileCore/Tests/.../DiagnosticEventPresentationTests.swift
Diagnostic events now expose stable names, decoded fields, typed failure and transport values, and raw integer fallbacks. Pair-failure payload documentation identifies the failure kind.
Transport incident policy
Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/TransportIncidentPolicy.swift, Packages/Shared/CMUXMobileCore/Tests/.../TransportIncidentPolicyTests.swift
The policy suppresses expected failures, coalesces repeated signatures, enforces capture budgets, and escalates sustained failures into outage incidents.
Live diagnostic event taps
Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/DiagnosticLog.swift, Packages/Shared/CMUXMobileCore/Tests/.../DiagnosticLogTests.swift
DiagnosticLog now delivers retained events to a replaceable live observer without replaying history or repeating deduplicated events.

Telemetry and Sentry integration

Layer / File(s) Summary
Telemetry scrubbing foundation
Packages/Shared/CmuxSentryTelemetry/Package.swift, Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryScrubbing/*, Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryReporting/SentryEventScrubber.swift, Packages/Shared/CmuxSentryTelemetry/Tests/*
The shared package adds denylist and regex-based scrubbing for secrets, paths, URLs, queries, structured values, Sentry events, breadcrumbs, spans, and logs.
Sentry transport reporter
Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryReporting/TransportSentryReporter.swift, TransportTelemetryLogBudget.swift, Packages/Shared/CmuxSentryTelemetry/Tests/CmuxSentryReportingTests/*
TransportSentryReporter emits breadcrumbs and budgeted logs, applies incident policy, and asynchronously captures qualifying incidents with metadata and diagnostic-ring attachments.
Application wiring and consent controls
Sources/AppDelegate.swift, ios/cmux/AppCompositionRoot.swift, Packages/iOS/CmuxMobileCrashReporting/*, CLI/CLISocketSentryTelemetry.swift, cmux.xcodeproj/project.pbxproj, cmuxTests/MacSentryStartupPolicyTests.swift, docs/transport-sentry-diagnostics.md
The applications link the shared package, retain platform reporters, connect diagnostic logs, enable structured logs, scrub outgoing telemetry, and gate events and logs on consent. Startup-policy tests and pipeline documentation were added.

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

Possibly related PRs

Sequence Diagram(s)

sequenceDiagram
  participant DiagnosticLog
  participant TransportSentryReporter
  participant TransportIncidentPolicy
  participant DiagnosticRing
  participant Sentry
  DiagnosticLog->>TransportSentryReporter: Ingest retained diagnostic event
  TransportSentryReporter->>TransportIncidentPolicy: Decide incident outcome
  TransportSentryReporter->>Sentry: Send breadcrumb and admitted log
  TransportSentryReporter->>DiagnosticRing: Export ring for qualifying incident
  DiagnosticRing-->>TransportSentryReporter: Return diagnostic data
  TransportSentryReporter->>Sentry: Capture incident with metadata and attachment
Loading

Important

Pre-merge checks failed

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

❌ Failed checks (4 errors, 1 warning)

Check name Status Explanation Resolution
Cmux Swift Concurrency ❌ Error TransportSentryReporter.captureIncident adds an unowned Task.detached for ring export and Sentry capture; tests explicitly await this async work, so it has meaningful lifecycle. Replace the fire-and-forget detached task with a reporter-owned actor/AsyncStream worker or stored task collection, and cancel or drain it during reporter teardown.
Cmux Swiftpm Lockfiles ❌ Error cmux.xcodeproj/project.pbxproj adds the CmuxSentryTelemetry SwiftPM reference, but cmux.xcodeproj/project.xcworkspace/.../Package.resolved is unchanged. Commit the root Xcode lockfile diff at cmux.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved with the package-reference change.
Cmux No Test Or Debug Seam In Production Source ❌ Error TransportSentryReporter.swift adds public TransportSentryReporter.Delivery explicitly “injectable for tests”; only tests construct it, so shipping source contains a test delivery seam. Make Delivery and its injected initializer internal, use the existing @testable import, and keep only the public live-Sentry initializer. Follow #6452.
Cmux No Ambient Global State ❌ Error DiagnosticEventPresentation.swift:15 adds a caseless public enum with static-only API (lines 41–108), which violates the static namespace rule. Replace it with a constructable DiagnosticEventPresenter. Inject it into TransportSentryReporter and keep decoding helpers private instance methods.
Docstring Coverage ⚠️ Warning Docstring coverage is 35.00% 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
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 New background telemetry uses Sendable types and documented OSAllocatedUnfairLock state; UI roots are explicitly @MainActor, and no new service protocol or background UI-store access appears.
Cmux Swift Blocking Runtime ✅ Passed Production diff adds no waits, sleeps, delayed dispatch, timers, polling, or main-queue sync; its two tiny OSAllocatedUnfairLock regions document synchronous callback requirements and keep work out...
Cmux Browser Automation Off-Main ✅ Passed The PR changes neither scoped browser automation file and adds no browser command or routing; the rule is not applicable.
Cmux Expensive Synchronous Load ✅ Passed The full PR diff adds no agent-history loaders or large-file scans; transport ring export runs in Task.detached, and tap ingestion runs on the DiagnosticLog drain task.
Cmux Cache Substitution Correctness ✅ Passed The diff adds live DiagnosticLog taps and actor-backed ring exports; it does not replace an authoritative persistence, history, undo, or snapshot read with a cache.
Cmux No Hacky Sleeps ✅ Passed The PR adds no TypeScript, JavaScript, shell, or covered runtime-script timing changes; non-Swift changes are package/project metadata, while runtime code is Swift.
Cmux Algorithmic Complexity ✅ Passed Production paths use linear scans or explicit bounded windows: 30 failure captures/hour, 300 logs/hour, and a 4096-event ring; no nested scalable scans, sorting, or per-target rescans were added.
Cmux Swift @Concurrent ✅ Passed No changed async helper lacks an actor hop: TransportSentryReporter uses Task.detached(.utility) before ring export and capture; UI integrations only install synchronous tap callbacks.
Cmux Swift Package Boundaries ✅ Passed Transport policy, presentation, scrubbing, budgeting, and reporting live in SwiftPM targets; AppDelegate/AppCompositionRoot changes only wire lifecycle and event taps, which the rule allows.
Cmux Swift Logging ✅ Passed The complete PR diff adds no print/debugPrint/dump/NSLog or ad hoc file logging; Sentry logs use fixed taxonomy fields, and SentryEventScrubber redacts free-text secrets and paths.
Cmux User-Facing Error Privacy ✅ Passed The full PR diff adds no UI alerts, CLI output, or API error bodies; new failure text uses fixed taxonomy in internal Sentry telemetry, while docs, tests, and comments are allowed.
Cmux Full Internationalization ✅ Passed The PR adds no UI or localized-string catalog changes; new literals are stable diagnostic taxonomy/Sentry telemetry fields, and the documentation is operational.
Cmux Swiftui State Layout ✅ Passed The PR adds no prohibited SwiftUI state, GeometryReader, lazy-row store, or render-time mutation. SwiftUI files only receive telemetry wiring; MobileShellComposite changes existing @Observable-adja...
Cmux Architecture Rethink ✅ Passed The tap is a documented single bridge from the ring’s existing owner; reporter state has one owner, locks protect only policy/budget state, and no timing repair or duplicate action path was added.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed The PR adds no standalone NSWindow, NSPanel, NSWindowController, Window, or WindowGroup code; the auxiliary-window lint also passes for all 34 identifiers.
Cmux Source Artifacts ✅ Passed All changed paths are Swift source, tests, package manifests/lockfiles, project configuration, or transport telemetry documentation; no artifact directory, cache, log, screenshot, recording, or bui...
Title check ✅ Passed The title clearly identifies the primary change: comprehensive Sentry telemetry for transport failures across iOS and macOS.
Description check ✅ Passed The description gives a detailed summary, testing results, design notes, and implementation scope, but it omits the template headings and checklist.
✨ 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 feat-iroh-sentry-diagnostics

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

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🤖 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 `@docs/transport-sentry-diagnostics.md`:
- Around line 3-9: Qualify the Sentry coverage claim in the transport
diagnostics documentation to state that Sentry contains only policy-eligible
telemetry. Explicitly note that delivery may be disabled and that policy,
cooldown, or hourly-budget rules can suppress events; remove the implication
that every transport failure is guaranteed to appear.

In
`@Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift`:
- Around line 8234-8237: Update the exhausted-connect handling in
MobileShellComposite so one failed connect advances TransportIncidentPolicy’s
streakCount and signature cooldown only once. Remove the duplicate reportable
diagnostic event or route one event outside the streak/signature policy, while
preserving the intended failure kind and exhausted-connect diagnostics.

In
`@Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/DiagnosticEventPresentation.swift`:
- Around line 122-125: Add .routeUnavailable to the codesWithTransportA set and
update decodeA(_:code:) so this code follows the branch that decodes a using
DiagnosticTransportKind and returns the key "transport", preserving transport
data for route-unavailable incidents.

In `@Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/DiagnosticLog.swift`:
- Around line 149-150: The setEventTap method can install an observer after
record queues an event but before the drain delivers it, causing the new
observer to receive events recorded before registration. Fix this by assigning
an ingress sequence ID to each event under the ingress lock in the record
method, storing the last admitted sequence ID when setEventTap installs the
observer via tap.set, and filtering delivered events to only those with sequence
IDs greater than the stored ID. Add a regression test that records an event
before calling setEventTap and verifies the new observer does not receive the
pre-registration event.

In
`@Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/TransportIncidentPolicy.swift`:
- Around line 297-307: Make SignatureState.lastCaptureTNanos optional so a
budget-rejected signature can be tracked without starting a cooldown; initialize
new rejected states with nil, and update the cooldown logic to apply only when a
capture timestamp exists. Extend hourlyBudgetDropsAndReports or its related
tests with a non-zero signatureCooldown, a new signature dropped by the budget,
and a later capture after the budget window slides.

In
`@Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryReporting/SentryEventScrubber.swift`:
- Around line 157-185: Update scrub(_:) to write scrubbed values using
SentryLog.Attribute(string:) rather than SentryAttribute(string:), matching the
attribute type stored by SentryLog. Extend stringValues collection and writeback
to include string-array attributes, ensuring arrays are passed through the
scrubber and restored without bypassing redaction.

In
`@Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryReporting/TransportSentryReporter.swift`:
- Around line 181-191: Update captureIncident to retain each detached capture
task using the reporter’s existing synchronization mechanism and pending-task
storage, rather than leaving it fire-and-forget. Add or connect shutdown
handling so pending incident captures can be awaited or drained with a bounded
timeout before termination, while preserving the existing exportRing, attachment
creation, and delivery.capture behavior.

In
`@Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryScrubbing/SentryRegexMatch.swift`:
- Around line 30-35: Update captureGroup(_:) so its existing bounds guard
rejects negative indices as well as indices at or beyond result.numberOfRanges
before calling result.range(at:). Preserve the current nil return behavior for
all invalid or unmatched ranges.

In
`@Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryScrubbing/SentryScrubber.swift`:
- Around line 187-197: Update the recursive scrubber’s doc comment to remove
Data from the safe scalars that pass through untouched, and document that Data
values are replaced with redactedData. Keep the existing implementation behavior
unchanged.
🪄 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: 32a9aabd-ce70-4c79-bf6d-863af90e9a5f

📥 Commits

Reviewing files that changed from the base of the PR and between 35fb1af and 609ea8c.

⛔ Files ignored due to path filters (4)
  • Packages/Shared/CmuxSentryTelemetry/Package.resolved is excluded by !**/Package.resolved
  • Packages/iOS/CmuxMobileCrashReporting/Package.resolved is excluded by !**/Package.resolved
  • cmux.xcworkspace/contents.xcworkspacedata is excluded by !**/*.xcworkspace/contents.xcworkspacedata
  • ios/cmuxPackage/Package.resolved is excluded by !**/Package.resolved
📒 Files selected for processing (29)
  • CLI/CLISocketSentryTelemetry.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/DiagnosticEventCode.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/DiagnosticEventPresentation.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/DiagnosticLog.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/TransportIncidentPolicy.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/DiagnosticEventPresentationTests.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/DiagnosticLogTests.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/TransportIncidentPolicyTests.swift
  • Packages/Shared/CmuxSentryTelemetry/Package.swift
  • Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryReporting/SentryEventScrubber.swift
  • Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryReporting/TransportSentryReporter.swift
  • Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryReporting/TransportTelemetryLogBudget.swift
  • Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryScrubbing/ScrubberDenylists.swift
  • Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryScrubbing/SentryRegexMatch.swift
  • Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryScrubbing/SentryRegexPattern.swift
  • Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryScrubbing/SentryScrubber.swift
  • Packages/Shared/CmuxSentryTelemetry/Tests/CmuxSentryReportingTests/SentryEventScrubberTests.swift
  • Packages/Shared/CmuxSentryTelemetry/Tests/CmuxSentryReportingTests/TransportSentryReporterTests.swift
  • Packages/Shared/CmuxSentryTelemetry/Tests/CmuxSentryScrubbingTests/ScrubberDenylistsTests.swift
  • Packages/Shared/CmuxSentryTelemetry/Tests/CmuxSentryScrubbingTests/SentryScrubberTests.swift
  • Packages/iOS/CmuxMobileCrashReporting/Package.swift
  • Packages/iOS/CmuxMobileCrashReporting/Sources/CmuxMobileCrashReporting/MobileCrashReporter.swift
  • Packages/iOS/CmuxMobileCrashReporting/Tests/CmuxMobileCrashReportingTests/MobileCrashReporterTests.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift
  • Sources/AppDelegate.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/MacSentryStartupPolicyTests.swift
  • docs/transport-sentry-diagnostics.md
  • ios/cmux/AppCompositionRoot.swift

Comment thread docs/transport-sentry-diagnostics.md Outdated
Comment thread Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift Outdated
Comment thread Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/DiagnosticLog.swift Outdated
Comment on lines +181 to +191
private func captureIncident(_ incident: TransportIncidentPolicy.Incident) {
Task.detached(priority: .utility) { [self] in
let ring = await exportRing()
let attachment = ring.isEmpty ? nil : Attachment(
data: ring,
filename: "cmux-transport-diag.txt",
contentType: "text/plain"
)
delivery.capture(makeEvent(incident), attachment)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Track the incident-capture task so a quit does not silently drop it.

captureIncident starts a fire-and-forget Task.detached to export the ring and call delivery.capture. Nothing stores, awaits, or cancels this task. If the app quits (Cmd+Q on macOS, or process termination on iOS) while the task is mid-flight, the ring export or the Sentry capture can be interrupted. This drops exactly the failure or outage diagnostic the feature exists to deliver, and it can happen more often than average during real connectivity incidents, since those incidents correlate with app restarts and force-quits.

Store each task (for example in a Set<Task<Void, Never>> guarded by the existing lock) so a shutdown path can wait for pending captures to finish, or drain them with a bounded timeout before the process exits.

♻️ Proposed direction
     private struct MutableState: Sendable {
         var policy: TransportIncidentPolicy
         var logBudget: TransportTelemetryLogBudget
+        var pendingCaptures: [UUID: Task<Void, Never>] = [:]
     }
 
     private func captureIncident(_ incident: TransportIncidentPolicy.Incident) {
-        Task.detached(priority: .utility) { [self] in
+        let taskId = UUID()
+        let task = Task.detached(priority: .utility) { [self] in
             let ring = await exportRing()
             let attachment = ring.isEmpty ? nil : Attachment(
                 data: ring,
                 filename: "cmux-transport-diag.txt",
                 contentType: "text/plain"
             )
             delivery.capture(makeEvent(incident), attachment)
+            state.withLock { $0.pendingCaptures.removeValue(forKey: taskId) }
         }
+        state.withLock { $0.pendingCaptures[taskId] = task }
     }
+
+    /// Awaits pending incident captures. Call before process/app termination
+    /// so an in-flight ring export + Sentry capture is not interrupted.
+    public func drainPendingCaptures() async {
+        let tasks = state.withLock { Array($0.pendingCaptures.values) }
+        for task in tasks {
+            await task.value
+        }
+    }

Based on learnings, this repo's coding guidelines state: "Do not create fire-and-forget Task { ... } work with meaningful lifecycle unless it is stored, cancellable, or tied to a caller-owned operation."

🤖 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
`@Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryReporting/TransportSentryReporter.swift`
around lines 181 - 191, Update captureIncident to retain each detached capture
task using the reporter’s existing synchronization mechanism and pending-task
storage, rather than leaving it fire-and-forget. Add or connect shutdown
handling so pending incident captures can be awaited or drained with a bounded
timeout before termination, while preserving the existing exportRing, attachment
creation, and delivery.capture behavior.

Source: Path instructions

@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

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 9

🤖 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 `@docs/transport-sentry-diagnostics.md`:
- Around line 3-9: Qualify the Sentry coverage claim in the transport
diagnostics documentation to state that Sentry contains only policy-eligible
telemetry. Explicitly note that delivery may be disabled and that policy,
cooldown, or hourly-budget rules can suppress events; remove the implication
that every transport failure is guaranteed to appear.

In
`@Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift`:
- Around line 8234-8237: Update the exhausted-connect handling in
MobileShellComposite so one failed connect advances TransportIncidentPolicy’s
streakCount and signature cooldown only once. Remove the duplicate reportable
diagnostic event or route one event outside the streak/signature policy, while
preserving the intended failure kind and exhausted-connect diagnostics.

In
`@Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/DiagnosticEventPresentation.swift`:
- Around line 122-125: Add .routeUnavailable to the codesWithTransportA set and
update decodeA(_:code:) so this code follows the branch that decodes a using
DiagnosticTransportKind and returns the key "transport", preserving transport
data for route-unavailable incidents.

In `@Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/DiagnosticLog.swift`:
- Around line 149-150: The setEventTap method can install an observer after
record queues an event but before the drain delivers it, causing the new
observer to receive events recorded before registration. Fix this by assigning
an ingress sequence ID to each event under the ingress lock in the record
method, storing the last admitted sequence ID when setEventTap installs the
observer via tap.set, and filtering delivered events to only those with sequence
IDs greater than the stored ID. Add a regression test that records an event
before calling setEventTap and verifies the new observer does not receive the
pre-registration event.

In
`@Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/TransportIncidentPolicy.swift`:
- Around line 297-307: Make SignatureState.lastCaptureTNanos optional so a
budget-rejected signature can be tracked without starting a cooldown; initialize
new rejected states with nil, and update the cooldown logic to apply only when a
capture timestamp exists. Extend hourlyBudgetDropsAndReports or its related
tests with a non-zero signatureCooldown, a new signature dropped by the budget,
and a later capture after the budget window slides.

In
`@Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryReporting/SentryEventScrubber.swift`:
- Around line 157-185: Update scrub(_:) to write scrubbed values using
SentryLog.Attribute(string:) rather than SentryAttribute(string:), matching the
attribute type stored by SentryLog. Extend stringValues collection and writeback
to include string-array attributes, ensuring arrays are passed through the
scrubber and restored without bypassing redaction.

In
`@Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryReporting/TransportSentryReporter.swift`:
- Around line 181-191: Update captureIncident to retain each detached capture
task using the reporter’s existing synchronization mechanism and pending-task
storage, rather than leaving it fire-and-forget. Add or connect shutdown
handling so pending incident captures can be awaited or drained with a bounded
timeout before termination, while preserving the existing exportRing, attachment
creation, and delivery.capture behavior.

In
`@Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryScrubbing/SentryRegexMatch.swift`:
- Around line 30-35: Update captureGroup(_:) so its existing bounds guard
rejects negative indices as well as indices at or beyond result.numberOfRanges
before calling result.range(at:). Preserve the current nil return behavior for
all invalid or unmatched ranges.

In
`@Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryScrubbing/SentryScrubber.swift`:
- Around line 187-197: Update the recursive scrubber’s doc comment to remove
Data from the safe scalars that pass through untouched, and document that Data
values are replaced with redactedData. Keep the existing implementation behavior
unchanged.
🪄 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: 32a9aabd-ce70-4c79-bf6d-863af90e9a5f

📥 Commits

Reviewing files that changed from the base of the PR and between 35fb1af and 609ea8c.

⛔ Files ignored due to path filters (4)
  • Packages/Shared/CmuxSentryTelemetry/Package.resolved is excluded by !**/Package.resolved
  • Packages/iOS/CmuxMobileCrashReporting/Package.resolved is excluded by !**/Package.resolved
  • cmux.xcworkspace/contents.xcworkspacedata is excluded by !**/*.xcworkspace/contents.xcworkspacedata
  • ios/cmuxPackage/Package.resolved is excluded by !**/Package.resolved
📒 Files selected for processing (29)
  • CLI/CLISocketSentryTelemetry.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/DiagnosticEventCode.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/DiagnosticEventPresentation.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/DiagnosticLog.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/TransportIncidentPolicy.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/DiagnosticEventPresentationTests.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/DiagnosticLogTests.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/TransportIncidentPolicyTests.swift
  • Packages/Shared/CmuxSentryTelemetry/Package.swift
  • Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryReporting/SentryEventScrubber.swift
  • Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryReporting/TransportSentryReporter.swift
  • Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryReporting/TransportTelemetryLogBudget.swift
  • Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryScrubbing/ScrubberDenylists.swift
  • Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryScrubbing/SentryRegexMatch.swift
  • Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryScrubbing/SentryRegexPattern.swift
  • Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryScrubbing/SentryScrubber.swift
  • Packages/Shared/CmuxSentryTelemetry/Tests/CmuxSentryReportingTests/SentryEventScrubberTests.swift
  • Packages/Shared/CmuxSentryTelemetry/Tests/CmuxSentryReportingTests/TransportSentryReporterTests.swift
  • Packages/Shared/CmuxSentryTelemetry/Tests/CmuxSentryScrubbingTests/ScrubberDenylistsTests.swift
  • Packages/Shared/CmuxSentryTelemetry/Tests/CmuxSentryScrubbingTests/SentryScrubberTests.swift
  • Packages/iOS/CmuxMobileCrashReporting/Package.swift
  • Packages/iOS/CmuxMobileCrashReporting/Sources/CmuxMobileCrashReporting/MobileCrashReporter.swift
  • Packages/iOS/CmuxMobileCrashReporting/Tests/CmuxMobileCrashReportingTests/MobileCrashReporterTests.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift
  • Sources/AppDelegate.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/MacSentryStartupPolicyTests.swift
  • docs/transport-sentry-diagnostics.md
  • ios/cmux/AppCompositionRoot.swift
🛑 Comments failed to post (2)
Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryScrubbing/SentryRegexMatch.swift (1)

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

Complete the bounds check on captureGroup.

The guard checks only the upper bound. A negative index passes it and reaches result.range(at: index), which is defined only for 0..<numberOfRanges and traps outside that range. captureGroup is public API of CmuxSentryScrubbing, so an out-of-module caller can pass a negative index. A trap here runs inside a Sentry beforeSend hook and crashes the host app.

Add the lower bound to the existing guard.

🛡️ Proposed fix
     public func captureGroup(_ index: Int) -> String? {
-        guard index < result.numberOfRanges else { return nil }
+        guard index >= 0, index < result.numberOfRanges else { return nil }
         let range = result.range(at: index)
         guard range.location != NSNotFound, range.length >= 0 else { return nil }
         return source.substring(with: range)
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    public func captureGroup(_ index: Int) -> String? {
        guard index >= 0, index < result.numberOfRanges else { return nil }
        let range = result.range(at: index)
        guard range.location != NSNotFound, range.length >= 0 else { return nil }
        return source.substring(with: range)
    }
🤖 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
`@Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryScrubbing/SentryRegexMatch.swift`
around lines 30 - 35, Update captureGroup(_:) so its existing bounds guard
rejects negative indices as well as indices at or beyond result.numberOfRanges
before calling result.range(at:). Preserve the current nil return behavior for
all invalid or unmatched ranges.
Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryScrubbing/SentryScrubber.swift (1)

187-197: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Correct the Data claim in the doc comment.

Line 190 lists Data among the safe scalars that "pass through untouched". The implementation at lines 209-212 replaces every Data value with redactedData. The two statements contradict each other inside the same doc comment.

This matters because the doc describes a privacy decision. A maintainer who trusts line 190 would conclude that binary payloads are forwarded, and could reintroduce a pass-through case.

📝 Proposed doc fix
     /// Strings are scrubbed; dictionaries and arrays are walked; safe scalars
-    /// (`NSNumber`/`Bool`/`Int`/`Double`, `Date`, `Data`, `NSNull`) pass through
-    /// untouched. Any other object (notably `URL` / `NSURL`, which carry a file
+    /// (`NSNumber`/`Bool`/`Int`/`Double`, `Date`, `NSNull`) pass through
+    /// untouched. `Data` is replaced wholesale with ``redactedData``, because
+    /// Sentry serializes it to a hex description that the string rules cannot
+    /// reach. Any other object (notably `URL` / `NSURL`, which carry a file
     /// path) is converted to its string form and scrubbed, because Sentry
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    /// Recursively scrubs every string found inside a JSON-like value tree.
    ///
    /// Strings are scrubbed; dictionaries and arrays are walked; safe scalars
    /// (`NSNumber`/`Bool`/`Int`/`Double`, `Date`, `NSNull`) pass through
    /// untouched. `Data` is replaced wholesale with ``redactedData``, because
    /// Sentry serializes it to a hex description that the string rules cannot
    /// reach. Any other object (notably `URL` / `NSURL`, which carry a file
    /// path) is converted to its string form and scrubbed, because Sentry
    /// serializes unsupported Foundation objects to their description *after*
    /// `beforeSend` runs, which would otherwise leak the unscrubbed path.
    ///
    /// - Parameter value: A `String`, `[String: Any]`, `[Any]`, or scalar.
    /// - Returns: The value with all nested strings scrubbed.
🤖 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
`@Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryScrubbing/SentryScrubber.swift`
around lines 187 - 197, Update the recursive scrubber’s doc comment to remove
Data from the safe scalars that pass through untouched, and document that Data
values are replaced with redactedData. Keep the existing implementation behavior
unchanged.

…ys, single pairFail

The event tap now gates on an ingress admission sequence: installing an
observer while recorded events are still queued on the drain task no longer
delivers those pre-installation events (regression test records a 500-event
burst and installs the tap with no drain sync). A budget-dropped capture no
longer stamps lastCaptureTNanos, so a brand-new failure signature arriving
during budget exhaustion captures as soon as the window slides instead of
serving a phantom cooldown. The structured-log scrubber now handles
string-array attributes (previously bypassed) and writes back via
SentryLog.Attribute. One exhausted connect now records a single pairFail
carrying transport (a) and failure (b) instead of a pairFail+rpcFailed pair
that double-counted the outage streak; pairFail and routeUnavailable decode
their transport slot in presentation. The iOS workspace lockfile aligns
sentry-cocoa to 9.24.0, matching the package-local pins (fixes the SwiftPM
lockfile policy guard). Doc states coverage is policy-shaped, not per-event.

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

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

@azooz2003-bit

Copy link
Copy Markdown
Collaborator Author

Addressed the CodeRabbit round in d0087f3:

  • Tap no-replay race: events now carry an ingress admission sequence assigned under the ingress lock; setEventTap records the last admitted sequence as its activation floor and the tap drops anything at or below it. Regression test records a 500-event burst and installs the tap with no drain sync.
  • Cooldown stamped on budget drop: SignatureState.lastCaptureTNanos is now optional; a budget-dropped capture leaves it nil, so a new signature seen during budget exhaustion captures as soon as the hourly window slides. New test with non-zero cooldown covers it.
  • Log attribute scrubbing: string arrays now go through the key-aware scrubber (element-wise for content, wholesale for sensitive keys) and writeback uses SentryLog.Attribute. New test.
  • Doubled failure on exhausted connect: single .pairFail record now carries transport in a and failure in b; the adjacent .rpcFailed record is gone, so one connect attempt advances the outage streak by one. pairFail/routeUnavailable added to the transport-A decode set.
  • Docs: coverage claim qualified as policy-shaped (consent, cooldown, budgets), with breadcrumbs called out as the widest net.

Skipped: tracking the incident-capture Task for shutdown draining (Trivial). The capture task is a bounded ring export plus one SentrySDK.capture call, the SDK persists the envelope to disk at capture time, and macOS/iOS teardown gives no reliable async drain point; revisit if we observe dropped incident envelopes in practice.

@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 (2)
docs/transport-sentry-diagnostics.md (1)

29-32: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Document the runtime role in the fingerprint.

The Sentry fingerprint includes roleName and incident.signature. State that the fingerprint contains the runtime role plus the code/failureKind/transportKind signature.

Proposed wording
-fingerprinted by `code/failureKind/transportKind` signature
+fingerprinted by runtime role plus the `code/failureKind/transportKind` signature
🤖 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 `@docs/transport-sentry-diagnostics.md` around lines 29 - 32, Update the “Error
events” documentation to state that Sentry fingerprints include the runtime role
(roleName) together with the code/failureKind/transportKind incident.signature.
Preserve the existing description of the compact diagnostic ring export.
Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryReporting/SentryEventScrubber.swift (1)

157-197: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Scrub all typed log attributes and preserve scalar attributes.

scrub(_:) only collects String and [String] attribute values, so a sensitive key with integer, double, or bool attributes is not sent through scrub(dictionary:). The key-aware dictionary path already redacts sensitive keys by name and keeps safe scalars unchanged, so pass every supported attribute value through it and add a regression case for sensitive numeric attributes.

🤖 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
`@Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryReporting/SentryEventScrubber.swift`
around lines 157 - 197, Update CmuxSentryReporting.scrub(_:) to include every
supported log attribute value, not only String and [String], when building the
dictionary passed to scrubber.scrub(dictionary:). Preserve scalar numeric and
boolean values when the dictionary scrubber returns them, while retaining the
existing String and [String] attribute reconstruction; add a regression case
covering redaction of a sensitive key with a numeric attribute.
🤖 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 `@docs/transport-sentry-diagnostics.md`:
- Around line 7-8: Update the breadcrumb descriptions in
docs/transport-sentry-diagnostics.md, including the additional wording around
the referenced retained-event passage, to state that delivery includes only
transport events admitted after DiagnosticLog.setEventTap(_:) installation.
Replace claims that imply all retained events are delivered while preserving the
existing explanation of breadcrumb scope.

---

Outside diff comments:
In `@docs/transport-sentry-diagnostics.md`:
- Around line 29-32: Update the “Error events” documentation to state that
Sentry fingerprints include the runtime role (roleName) together with the
code/failureKind/transportKind incident.signature. Preserve the existing
description of the compact diagnostic ring export.

In
`@Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryReporting/SentryEventScrubber.swift`:
- Around line 157-197: Update CmuxSentryReporting.scrub(_:) to include every
supported log attribute value, not only String and [String], when building the
dictionary passed to scrubber.scrub(dictionary:). Preserve scalar numeric and
boolean values when the dictionary scrubber returns them, while retaining the
existing String and [String] attribute reconstruction; add a regression case
covering redaction of a sensitive key with a numeric attribute.
🪄 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: af68c160-c04c-442c-b716-5d77b8406693

📥 Commits

Reviewing files that changed from the base of the PR and between 609ea8c and d0087f3.

⛔ Files ignored due to path filters (1)
  • ios/cmux.xcworkspace/xcshareddata/swiftpm/Package.resolved is excluded by !**/Package.resolved
📒 Files selected for processing (10)
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/DiagnosticEventCode.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/DiagnosticEventPresentation.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/DiagnosticLog.swift
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/TransportIncidentPolicy.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/DiagnosticLogTests.swift
  • Packages/Shared/CMUXMobileCore/Tests/CMUXMobileCoreTests/TransportIncidentPolicyTests.swift
  • Packages/Shared/CmuxSentryTelemetry/Sources/CmuxSentryReporting/SentryEventScrubber.swift
  • Packages/Shared/CmuxSentryTelemetry/Tests/CmuxSentryReportingTests/SentryEventScrubberTests.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift
  • docs/transport-sentry-diagnostics.md

Comment on lines +7 to +8
budgets, and structured logs pass their own budget. Breadcrumbs are the widest
net (every retained transport event, attached to whatever ships next). The

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Document the event-tap delivery boundary.

DiagnosticLog.setEventTap(_:) does not replay events admitted before tap installation. The test eventTapNeverDeliversEventsQueuedBeforeInstallation covers this behavior. Replace “every retained transport event” and “each retained event” with wording that limits delivery to events admitted after tap installation.

Proposed wording
-`DiagnosticLog.setEventTap(_:)` delivers each retained event
+`DiagnosticLog.setEventTap(_:)` delivers events admitted after tap installation

Also applies to: 18-25

🤖 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 `@docs/transport-sentry-diagnostics.md` around lines 7 - 8, Update the
breadcrumb descriptions in docs/transport-sentry-diagnostics.md, including the
additional wording around the referenced retained-event passage, to state that
delivery includes only transport events admitted after
DiagnosticLog.setEventTap(_:) installation. Replace claims that imply all
retained events are delivered while preserving the existing explanation of
breadcrumb scope.

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