Skip to content

Harden route-content equivalence against reorders, missing baselines, and install races - #9402

Merged
azooz2003-bit merged 2 commits into
mainfrom
fix-route-content-hardening
Aug 3, 2026
Merged

azooz2003-bit merged 2 commits into
mainfrom
fix-route-content-hardening

Conversation

@azooz2003-bit

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

Copy link
Copy Markdown
Collaborator

Follow-ups to the six P2 findings from the cubic review of #9342. Commit 1 adds the failing tests, commit 2 the fixes, so CI proves each regression is pinned.

  1. Capability order-only changes invalidated sessions (CmxConnectivityRouteContent.BindingMaterial). Capabilities are now sorted when the material is built, matching the admission policy's set semantics (the broker rejects duplicate capabilities at decode, so a sorted array equals set compare).
  2. Relay fleet reorder was treated as an account-material change. AccountMaterial sorts the fleet when built; the discovery decoder already rejects duplicate relay URLs.
  3. Grant verification key reorder was treated as a trust change. AccountMaterial canonicalizes the key set by (kid, alg, spki) so a reorder-only rotation snapshot compares equal.
  4. CmxConnectivityEngine.didInstallRouteRevision's same-revision branch silently adopted content even when the recorded revision had no stored baseline (a sync can store a revision from an unchanged response without a snapshot). It now compares the stored baseline and routes a missing or differing baseline through invalidatePeersSuperseded, which fails closed on a nil baseline.
  5. Overlapping host reconciliations could complete out of order and roll back the installed route revision (CmxIrohHostRuntime.reconcileConnectivityRevision forwards fetched revisions without ordering). The engine now drops didInstallRouteRevision calls older than the recorded revision, so older completions cannot win regardless of the caller.
  6. CmxConnectivityPeerSession.connectedSession returned the previously captured installed.session after awaiting the redundant dial's close; an invalidation, remote close, or replacement during that suspension handed callers a closed session. Both redundant-dial paths now go through settleRedundantDial, which re-reads the active slot and its liveness after the close and retries the dial when the winner changed.

Tests (all in Packages/Shared/CmuxIrohTransport, suite green: 540 tests):

  • reorderedCapabilitiesOnRevisionBumpKeepsTheLivePeerSession
  • reorderedRelayFleetOnRevisionBumpKeepsTheLivePeerSession
  • reorderedGrantVerificationKeysOnRevisionBumpKeepsTheLivePeerSession
  • snapshotInstallForARevisionRecordedWithoutContentFailsClosed
  • sameRevisionReinstallWithUnchangedContentKeepsTheLivePeerSession
  • olderRouteRevisionInstallCannotRollBackANewerInstall
  • invalidationDuringRedundantDialCloseTriggersAFreshDial
  • invalidationDuringPostProbeRedundantDialCloseTriggersAFreshDial

🤖 Generated with Claude Code


Summary by cubic

Hardens route-content comparison and install ordering so reorder-only updates don’t drop sessions and overlapping reconciliations can’t roll back newer installs. Also fixes a redundant-dial race that could return a closed session, with tests added to pin behavior.

  • Bug Fixes
    • Content canonicalization in CmxConnectivityRouteContent: sort binding capabilities, relay fleet, and grant verification keys (by kid, alg, spki). Reorder-only revisions compare equal and keep sessions.
    • Install monotonicity and baseline checks in CmxConnectivityEngine.didInstallRouteRevision: drop installs older than the recorded revision; for same revision, validate the stored baseline and invalidate on missing/different baseline; unchanged content keeps sessions.
    • Redundant-dial race in CmxConnectivityPeerSession: both paths use settleRedundantDial to close the loser, re-check the installed winner and its liveness, and redial if it changed or closed, preventing stale closed sessions from being returned.

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

Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Improved connectivity reliability by preventing outdated route updates from overwriting newer state.
    • Avoided unnecessary peer reconnections when route information is unchanged.
    • Improved handling of duplicate connections, ensuring stale or invalid sessions are not reused.
    • Added safeguards to retry connections when an active session changes during connection setup.
    • Standardized route information so equivalent configurations are handled consistently.
  • Tests
    • Expanded coverage for route updates, connection replacement, invalidation, and concurrent connection scenarios.

azooz2003-bit and others added 2 commits August 1, 2026 18:00
Pins six behaviors from the cubic review of #9342: reorder-only
capability, relay fleet, and grant verification key revisions keep
live sessions; a snapshot installed for a revision recorded without
content fails closed; an older route revision install cannot roll
back a newer one; a redundant-dial close raced by invalidation
redials instead of returning the closed winner.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Canonicalizes route content so order carries no meaning where the
admission policy reads sets: binding capabilities, the relay fleet,
and grant verification keys (by kid) are sorted when the content is
built, so reorder-only revision bumps keep live sessions.

didInstallRouteRevision now drops installs older than the recorded
revision, so an older completion of an overlapping reconciliation
cannot roll back a newer installed revision. The same-revision branch
compares the stored baseline and fails closed through the standard
superseded-peer invalidation when the baseline is missing or differs,
instead of silently adopting the content.

The peer session no longer returns a stale winner capture after the
redundant-dial close: settleRedundantDial re-reads the active slot
and its liveness after the close suspension and redials when the
winner was invalidated, replaced, or remotely closed.

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

coderabbitai Bot commented Aug 2, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR canonicalizes route content, rejects stale revisions, avoids invalidation for equivalent content, and hardens redundant-dial settlement. New tests cover revision handling, route equivalence, invalidation races, and replacement dialing.

Changes

Connectivity consistency and session safety

Layer / File(s) Summary
Canonical route content and revision handling
Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxConnectivityRouteContent.swift, Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxConnectivityEngine.swift, Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxConnectivityEngineTests.swift
Route capabilities, relay fleets, and verification keys are sorted before comparison. Older revisions are ignored. Same-revision content changes invalidate affected peers, while identical content does not.
Redundant dial settlement and replacement dialing
Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxConnectivityPeerSession.swift, Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxConnectivityPeerSessionTests.swift
Redundant dials close the losing session and validate the installed connection before returning it. Failed validation triggers a replacement dial. Tests cover invalidation during asynchronous close operations.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant CmxConnectivityPeerSession
  participant RedundantConnection
  participant InstalledConnection
  participant Dialer

  Caller->>CmxConnectivityPeerSession: connectedSession()
  CmxConnectivityPeerSession->>RedundantConnection: close losing session
  CmxConnectivityPeerSession->>InstalledConnection: verify same connection and open state
  alt installed connection remains valid
    CmxConnectivityPeerSession-->>Caller: return installed connection
  else installed connection is invalid
    CmxConnectivityPeerSession->>Dialer: retry dialing
    Dialer-->>Caller: return replacement session
  end
Loading
🚥 Pre-merge checks | ✅ 25
✅ Passed checks (25 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 Production diff changes actor methods and immutable Sendable values only; it adds no class, service protocol, or UI store, and the package has no MainActor default-isolation setting.
Cmux Swift Blocking Runtime ✅ Passed The full PR diff adds no listed blocking or timing primitive in production Swift; it uses async close/recheck, while the only new continuation is deterministic test scaffolding.
Cmux Browser Automation Off-Main ✅ Passed The full PR changes only CmxIrohTransport source and tests; it does not modify TerminalController, ControlCommandExecutionPolicy, or browser/WebKit automation routing.
Cmux Expensive Synchronous Load ✅ Passed The PR production diff only changes route canonicalization and asynchronous peer-session settlement; it adds no agent-history loader, disk/JSON parsing, or main-actor interactive-path load.
Cmux Cache Substitution Correctness ✅ Passed The production diff does not replace a fresh persistence/history/undo/snapshot read with a cache. It canonicalizes passed discovery snapshots and handles nil/stale route baselines via fail-closed c...
Cmux No Hacky Sleeps ✅ Passed The commit changes only Swift source files. It adds no non-Swift runtime files or fixed-delay primitives; test coordination uses continuations and async state gates.
Cmux Algorithmic Complexity ✅ Passed The diff adds no nested or per-target scans. Its new sorts canonicalize bounded inputs: relays ≤16, capabilities ≤32, and the key set is current/previous (≤2).
Cmux Swift Concurrency ✅ Passed The source diff adds async/await settlement and actor-isolated checks only; it introduces no background Dispatch queues, Combine state, completion-handler API, or fire-and-forget Task.
Cmux Swift @Concurrent ✅ Passed Changed async work remains in actor-isolated CmxConnectivityEngine/CmxConnectivityPeerSession methods; no new @concurrent or nonisolated async code, and callers are actor-isolated runtimes.
Cmux Swift Package Boundaries ✅ Passed All production changes stay in the existing CmuxIrohTransport SwiftPM library target, with a matching test target and no AppKit, SwiftUI, or Ghostty imports.
Cmux Swiftpm Lockfiles ✅ Passed HEAD^..HEAD changes only three Swift source files; no Package.swift, Package.resolved, Xcode project, workflow, or .gitignore paths changed, so the lockfile rule is not triggered.
Cmux Swift Logging ✅ Passed The PR adds no print, debugPrint, dump, NSLog, Logger, stdout/stderr, or ad hoc diagnostic I/O in production Swift; changes only route/session logic and canonicalization.
Cmux User-Facing Error Privacy ✅ Passed The production diff changes route/session logic and developer comments only; it adds no user-facing errors, alerts, command output, API bodies, recovery copy, or sensitive diagnostic text.
Cmux Full Internationalization ✅ Passed The production diff changes internal transport logic and route data canonicalization only; it adds no user-facing text, localization keys, catalogs, or locale/web message files.
Cmux Swiftui State Layout ✅ Passed The diff changes only transport actors and value structs; it adds no SwiftUI imports, views, ObservableObject state, GeometryReader, lazy rows, or render-time state writes.
Cmux Architecture Rethink ✅ Passed Production changes keep ownership in the engine and peer actors, re-check explicit revision/liveness invariants, and add no prohibited timing or blocking repair paths; synchronization is test-only.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed The complete two-commit diff changes only CmuxIrohTransport sources and tests. It adds no standalone window APIs, identifiers, or close-shortcut routing.
Cmux Source Artifacts ✅ Passed All five changed paths are text Swift source or test files under the intended package; no artifact directories, logs, binaries, or generated outputs appear in the diff.
Cmux No Test Or Debug Seam In Production Source ✅ Passed The PR adds no DEBUG/test guard, test-named member, widened visibility, or state accessor in production Sources; the new helper is private runtime logic, and test scaffolding remains under Tests/.
Cmux No Ambient Global State ✅ Passed The production diff adds no file-scope functions, mutable globals, static-only namespaces, or singletons; additions are actor methods, a private instance helper, and a nested initializer.
Title check ✅ Passed The title clearly summarizes the PR's main changes to route-content equivalence, revision ordering, and redundant-dial race handling.
Description check ✅ Passed The description provides a detailed change summary and testing results, but it omits the template's demo video, review trigger, and checklist sections.
✨ 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 fix-route-content-hardening

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.

Caution

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

⚠️ Outside diff range comments (1)
Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxConnectivityEngine.swift (1)

254-271: 🗄️ Data Integrity & Integration | 🔴 Critical | 🏗️ Heavy lift

Re-validate the route-revision guard after peer invalidation.

didInstallRouteRevision reads routeRevision only before asynchronous invalidation, but the same-path updates happen afterward. An older overlapping installation can resume after a newer one has installed and rewind routeRevision and routeContent. Re-check the guard after invalidatePeersSuperseded(by:) in both branches that write routeContent.

🤖 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/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxConnectivityEngine.swift`
around lines 254 - 271, Update didInstallRouteRevision so each path that writes
routeContent re-checks the current routeRevision after awaiting
invalidatePeersSuperseded(by: content). If a newer revision has been installed
during the await, return without overwriting routeRevision or routeContent;
apply this re-validation in both the unchanged-revision baseline branch and the
revision-update branch.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In
`@Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxConnectivityEngine.swift`:
- Around line 254-271: Update didInstallRouteRevision so each path that writes
routeContent re-checks the current routeRevision after awaiting
invalidatePeersSuperseded(by: content). If a newer revision has been installed
during the await, return without overwriting routeRevision or routeContent;
apply this re-validation in both the unchanged-revision baseline branch and the
revision-update branch.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7e800cc6-b7c8-4aa2-a820-40a03a374ba2

📥 Commits

Reviewing files that changed from the base of the PR and between 175127e and d011a69.

📒 Files selected for processing (5)
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxConnectivityEngine.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxConnectivityPeerSession.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxConnectivityRouteContent.swift
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxConnectivityEngineTests.swift
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxConnectivityPeerSessionTests.swift

@azooz2003-bit
azooz2003-bit merged commit eee859d into main Aug 3, 2026
7 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