Skip to content

Stagger Iroh relay credential refreshes - #9581

Merged
azooz2003-bit merged 4 commits into
mainfrom
fix-iroh-refresh-stagger
Aug 4, 2026
Merged

azooz2003-bit merged 4 commits into
mainfrom
fix-iroh-refresh-stagger

Conversation

@azooz2003-bit

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

Copy link
Copy Markdown
Collaborator

Summary

  • assign stable refresh slots from each endpoint identity
  • keep Mac refreshes in seconds 0–14 and iOS refreshes in seconds 30–44
  • prevent both peers from rotating relay credentials together while preserving the endpoint

Verification

Principled fix: refresh ownership is encoded as a deterministic scheduling invariant instead of a timing retry.


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

Staggered Iroh relay credential refreshes by role and endpoint so host and client don’t rotate at the same time. Slots are stable per endpoint to reduce reconnect churn.

  • Bug Fixes
    • Introduced a deterministic scheduler (CmxIrohRelayRefreshSchedule) that assigns per-endpoint refresh slots using FNV hashing: host 0–14s, client 30–44s within each minute.
    • Wired the schedule into client and host runtimes via the jitter callback to compute deadlines clamped between now and refreshAfter.
    • Expanded tests to assert stable per-endpoint slots across cycles, per-role slot spread, and bounded deadlines.

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

Review in cubic

Summary by CodeRabbit

  • Improvements

    • Relay credentials now refresh on client- and host-specific schedules, reducing simultaneous refresh activity.
    • Refresh timing is deterministically distributed across short time windows while still respecting required deadlines.
    • Relay connectivity management is more balanced and predictable across endpoints.
  • Tests

    • Added coverage to verify refresh timing separation, deadline compliance, and distribution across multiple scheduling slots.

@coderabbitai

coderabbitai Bot commented Aug 4, 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: 5f706792-7eff-480b-a2c5-2ed1b88b4b42

📥 Commits

Reviewing files that changed from the base of the PR and between d405a66 and a30cdb1.

📒 Files selected for processing (1)
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohRelayCredentialCoordinatorTests.swift

📝 Walkthrough

Walkthrough

The change adds deterministic, endpoint-specific relay refresh schedules. Host and client runtimes pass schedule-based deadline callbacks to the managed relay credential coordinator. Tests verify role separation, deadline bounds, and slot distribution.

Changes

Relay refresh scheduling

Layer / File(s) Summary
Refresh schedule implementation
Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohRelayRefreshSchedule.swift
CmxIrohRelayRefreshSchedule hashes endpoint identities into role-specific second-of-minute slots and clamps deadlines between now and refreshAfter.
Runtime coordinator integration
Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohClientRuntime+RelayPolicy.swift, Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohHostRuntime+RelayPolicy.swift
Host and client runtimes create endpoint-specific schedules and provide their deadline calculations as coordinator jitter callbacks.
Refresh schedule validation
Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohRelayCredentialCoordinatorTests.swift
Tests verify separate host and client windows, deadline bounds, and slot variation across endpoint identities.

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

Possibly related PRs

Sequence Diagram(s)

sequenceDiagram
  participant CmxIrohHostRuntime
  participant CmxIrohClientRuntime
  participant CmxIrohRelayRefreshSchedule
  participant ManagedRelayCredentialCoordinator
  CmxIrohHostRuntime->>CmxIrohRelayRefreshSchedule: Create host schedule for endpoint identity
  CmxIrohClientRuntime->>CmxIrohRelayRefreshSchedule: Create client schedule for endpoint identity
  CmxIrohHostRuntime->>ManagedRelayCredentialCoordinator: Provide deadline callback
  CmxIrohClientRuntime->>ManagedRelayCredentialCoordinator: Provide deadline callback
  ManagedRelayCredentialCoordinator->>CmxIrohRelayRefreshSchedule: Calculate refresh deadline
  CmxIrohRelayRefreshSchedule-->>ManagedRelayCredentialCoordinator: Return scheduled deadline
Loading

Important

Pre-merge checks failed

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

❌ Failed checks (1 error)

Check name Status Explanation Resolution
Cmux Swift Blocking Runtime ❌ Error Production adds wall-clock host/client refresh slots via Date/floor and wires them into jitter; the coordinator then awaits clock.sleep until those deadlines, creating timing-based synchronization. Replace wall-clock role slots with actor-owned coordination or an explicit broker/event signal. Do not use deterministic time windows to synchronize credential rotation.
✅ Passed checks (24 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: staggering Iroh relay credential refreshes.
Description check ✅ Passed The description explains the change and verification results, but it omits the template checklist and review trigger sections.
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 CmxIrohRelayRefreshSchedule is correctly marked Sendable with only immutable properties; closures passed to @Sendable jitter parameter implicitly Sendable by capturing only Sendable values; no impl...
Cmux Browser Automation Off-Main ✅ Passed PR modifies Iroh relay credential refresh scheduling only. No changes to browser automation, WebKit, AppKit, or socket automation code covered by the policy.
Cmux Expensive Synchronous Load ✅ Passed PR adds lightweight hash-based relay scheduling with no file I/O, JSON parsing, agent history access, or syscalls. Operations are in-memory only and occur outside main actor/interactive paths.
Cmux Cache Substitution Correctness ✅ Passed The diff adds deterministic relay scheduling and jitter callbacks only; it does not replace an authoritative read with a cache in persistence, history, undo, or snapshot paths.
Cmux No Hacky Sleeps ✅ Passed The PR changes only Swift source and Swift tests; it adds no TypeScript, JavaScript, shell, or build/runtime-script delays covered by this rule.
Cmux Algorithmic Complexity ✅ Passed The PR adds O(1) constant-time scheduling logic. The only loop iterates over a fixed-size 64-character endpoint ID string (FNV hashing), not a scalable collection. deadline() performs pure arithmet...
Cmux Swift Concurrency ✅ Passed The PR adds a Sendable schedule and synchronous @Sendable jitter closures only; the diff adds no Dispatch queues, Combine state, fire-and-forget Tasks, or completion-handler APIs.
Cmux Swift @Concurrent ✅ Passed PR adds synchronous relay refresh scheduling functions and test code. No nonisolated async functions lacking @concurrent; no invalid @concurrent on sync/isolated functions; no heavy async helpers w...
Cmux Swift Package Boundaries ✅ Passed All production changes are inside the existing CmuxIrohTransport SwiftPM target, with package tests; the scheduler uses Foundation and CMUXMobileCore, not app lifecycle or UI globals.
Cmux Swiftpm Lockfiles ✅ Passed The PR changes only Swift source and test files; it changes no Package.swift, Package.resolved, .gitignore, workflow, or Xcode project dependency references.
Cmux Swift Logging ✅ Passed No logging violations found. The PR adds deterministic relay refresh scheduling with no print(), NSLog(), file I/O, or sensitive data exposure in runtime code. Tests are properly scoped.
Cmux User-Facing Error Privacy ✅ Passed The production diff adds only scheduling logic and runtime jitter wiring; it adds no user-facing errors, alerts, output, or recovery text. The added test data is allowed.
Cmux Full Internationalization ✅ Passed The full feature diff changes only relay scheduling Swift code and tests; it adds no user-facing text, localization keys, catalogs, plist entries, or web locale data.
Cmux Swiftui State Layout ✅ Passed The complete diff changes only relay transport code and tests. It adds no SwiftUI import, state wrapper, GeometryReader, lazy row, or render-time mutation.
Cmux Architecture Rethink ✅ Passed The PR adds an immutable Sendable schedule with explicit host/client slot invariants, injects it through the existing coordinator path, and adds tests without new production sleeps, locks, observer...
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed The PR changes only Iroh relay scheduling and tests. The diff adds no NSWindow, NSPanel, NSWindowController, SwiftUI Window, WindowGroup, or auxiliary-window identifier code.
Cmux Source Artifacts ✅ Passed All four changed files are legitimate hand-written Swift source code in proper directory structures. No local tool output, generated artifacts, cache files, DerivedData, or prohibited scratch direc...
Cmux No Test Or Debug Seam In Production Source ✅ Passed The production diff adds only CmxIrohRelayRefreshSchedule and runtime scheduling callbacks. It adds no DEBUG guard, test-named member, visibility widening, or test-only accessor.
Cmux No Ambient Global State ✅ Passed CmxIrohRelayRefreshSchedule is a constructable, injectable struct with instance methods and proper encapsulation. The type is created locally and injected into coordinators; no ambient global state...
✨ 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-iroh-refresh-stagger

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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohRelayCredentialCoordinatorTests.swift`:
- Around line 47-63: Extend refreshSlotsSpreadEndpointsWithinEachRole to create
a client identity cohort using CmxIrohRelayRefreshSchedule with role .client,
then compute its refresh slots like the host cohort. Assert the client slots
contain more than one distinct value and every slot falls within 30...44, while
preserving the existing host assertions.
🪄 Autofix

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: de629dd6-5b47-4bf4-aba9-9c157f9377a9

📥 Commits

Reviewing files that changed from the base of the PR and between a0680fd and 7b9cace.

📒 Files selected for processing (4)
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohClientRuntime+RelayPolicy.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohHostRuntime+RelayPolicy.swift
  • Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohRelayRefreshSchedule.swift
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohRelayCredentialCoordinatorTests.swift

@cursor

cursor Bot commented Aug 4, 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.

@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 (2)
Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohRelayCredentialCoordinatorTests.swift (2)

26-37: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert slot stability across refresh cycles.

The loop calls each schedule with the same endpoint identity eight times, but it checks only window membership. A non-deterministic scheduler could select a different second on every call and still pass. Record the first host and client seconds, then assert that later cycles return the same values.

Suggested assertions
+        var hostSeconds: [Int] = []
+        var clientSeconds: [Int] = []
+
         for cycle in 1 ... 8 {
...
             let clientSecond = Int(clientDeadline.timeIntervalSince1970) % 60
+            hostSeconds.append(hostSecond)
+            clientSeconds.append(clientSecond)
...
         }
+        `#expect`(Set(hostSeconds).count == 1)
+        `#expect`(Set(clientSeconds).count == 1)
🤖 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/Tests/CmuxIrohTransportTests/CmxIrohRelayCredentialCoordinatorTests.swift`
around lines 26 - 37, Update the refresh-cycle loop in
CmxIrohRelayCredentialCoordinatorTests to capture the first hostSecond and
clientSecond values, then assert on subsequent cycles that each schedule returns
the same second for the unchanged endpoint identity. Preserve the existing
deadline and window-membership checks.

41-42: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert the lower deadline bound.

CmxIrohRelayRefreshSchedule.deadline clamps the result to now in Packages/Shared/CmuxIrohTransport/Sources/CmuxIrohTransport/CmxIrohRelayRefreshSchedule.swift, Lines 34-46. This test checks only deadline <= refreshAfter. A deadline from a previous minute can satisfy the slot-window assertions while still being earlier than now. Add lower-bound assertions.

Suggested assertions
             `#expect`(hostDeadline <= refreshAfter)
             `#expect`(clientDeadline <= refreshAfter)
+            `#expect`(hostDeadline >= now)
+            `#expect`(clientDeadline >= now)
🤖 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/Tests/CmuxIrohTransportTests/CmxIrohRelayCredentialCoordinatorTests.swift`
around lines 41 - 42, Update CmxIrohRelayCredentialCoordinatorTests to assert
both hostDeadline and clientDeadline are greater than or equal to the
current-time lower bound (now), in addition to the existing refreshAfter
upper-bound checks. Preserve the existing slot-window assertions and use the
same now value captured for the schedule calculation.
🤖 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/Tests/CmuxIrohTransportTests/CmxIrohRelayCredentialCoordinatorTests.swift`:
- Around line 26-37: Update the refresh-cycle loop in
CmxIrohRelayCredentialCoordinatorTests to capture the first hostSecond and
clientSecond values, then assert on subsequent cycles that each schedule returns
the same second for the unchanged endpoint identity. Preserve the existing
deadline and window-membership checks.
- Around line 41-42: Update CmxIrohRelayCredentialCoordinatorTests to assert
both hostDeadline and clientDeadline are greater than or equal to the
current-time lower bound (now), in addition to the existing refreshAfter
upper-bound checks. Preserve the existing slot-window assertions and use the
same now value captured for the schedule calculation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 63cca8be-b936-422e-8b97-ff5cdc21e4bf

📥 Commits

Reviewing files that changed from the base of the PR and between 7b9cace and d405a66.

📒 Files selected for processing (1)
  • Packages/Shared/CmuxIrohTransport/Tests/CmuxIrohTransportTests/CmxIrohRelayCredentialCoordinatorTests.swift

@cursor

cursor Bot commented Aug 4, 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
azooz2003-bit merged commit 28f88c8 into main Aug 4, 2026
16 of 24 checks passed
@azooz2003-bit
azooz2003-bit deleted the fix-iroh-refresh-stagger branch August 4, 2026 12:57
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