Skip to content

Isolate and label tagged iOS dev computers - #7864

Merged
azooz2003-bit merged 37 commits into
mainfrom
task-tag-ios-dev-computer-names
Jul 13, 2026
Merged

azooz2003-bit merged 37 commits into
mainfrom
task-tag-ios-dev-computer-names

Conversation

@azooz2003-bit

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

Copy link
Copy Markdown
Collaborator

Root cause

Tagged macOS builds reused the stable physical Mac device ID for both device-level and tagged-instance presentation. Tagged iOS builds then consumed shared and restored Mac records without applying their own build scope, so switching apps could show a computer left by another dev build.

Fix

  • Keep the base Mac name stable for device registration and backup identity.
  • Publish a tagged instance name for direct attach, authenticated status, and per-tag presence.
  • Apply the current iOS bundle tag to every Computers snapshot, including restored and offline records, with idempotent suffixing.
  • Model ticket-only, simulator-injection, and physical-device attach targets explicitly so loopback and Tailscale routes cannot leak across targets.
  • Reject invalid tags and the reserved default sentinel through one shared validator.

This is a principled identity split: stable hardware identity remains stable, while build-instance presentation and routing are scoped explicitly.

Verification

  • Regression test commit first: bcc71dc
  • Fix commit second: 29d16dd
  • Node attach and tag tests: 18 passed
  • Bash syntax checks passed
  • Swift syntax parsing passed
  • macOS tagged build futr1 succeeded
  • Isolated iPhone 17 Pro simulator cmux-futr1-115512 built, installed, signed in, and paired
  • Final Computers sheet showed MacBook Pro (2) (futr1) with no stale unsuffixed row
  • UI video was split and reviewed across first, middle, and final frames

Local Xcode test actions were not run because project policy prohibits them on the user Mac.


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.


Note

High Risk
Changes pairing persistence, reconnect routing, backup restore, and cross-instance authority—core mobile connectivity paths where mistakes misroute users or resurrect stale hosts.

Overview
Tagged iOS dev builds and multiple Mac app instances on one machine no longer share or overwrite each other’s saved routes, reconnect paths, or backup rows.

Paired-Mac storage gains an instanceTag (SQLite schema v5) plus atomic upsertIfNewer and upsertRoutesIfAuthorized so stale restores and cross-tag writes are rejected. Host status decodes mac_instance_tag; registry refresh, presence push, reconnect, and backup uploads all gate route mutations on matching or unclaimed instance authority.

MobileIOSBuildScope moves to CMUXMobileCore with versioned backup scope (ios:v2:…), rejection of the default sentinel, and computerDisplayName suffixing for the Computers UI. The build-scoped paired-Mac decorator and backup layer thread instanceTag through upserts and conditional restores.

Shell logic is split into focused extensions: tag authority resolution, ticket persistence with conditional unclaimed writes, presence-driven route sync, registry refresh with instance checks, and secondary-client promotion that re-validates stored tags.

CI adds swift test for CmuxMobilePairedMac; new regression suites cover instance-tag migration, route authority, and restore races.

Reviewed by Cursor Bugbot for commit 06348d7. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Tagged iOS dev builds now isolate Mac app instances by tag across routes, reconnects, presence, and backups. Dev builds show computer titles with a “(tag)” suffix; stable builds stay unscoped.

  • New Features

    • Versioned tagged backup scopes ios:v2:<tag> via X-Cmux-Client-Scope; the Mac publisher sends instanceTag with compare‑and‑set. Authenticated host status includes mac_instance_tag; the iOS store adds schema v5 with instanceTag plus atomic upsertIfNewer and upsertRoutesIfAuthorized.
    • Route selection, reconnect, registry lookups, presence sync, and secondary‑client promotion are tag‑aware and reject cross‑tag writes; batched presence route sync reduces redundant writes. Device registry and presence omit cross‑scope fallbacks; exact instance authority gates mutations.
    • UI applies the “(tag)” suffix using CMUXMobileCore MobileIOSBuildScope; presence shows liveness per exact instance. Attach tickets add target (ticket_only, simulator_injection, physical_device); scripts/tests use a shared dev‑tag validator. Attach‑ticket creation moved to TerminalController+MobileAttachTicket and keeps legacy attach_url compatibility.
  • Bug Fixes

    • Legacy restores preserve an authenticated instanceTag and use upsertIfNewer so older backups can’t overwrite newer, tagged authority; worker reads stop falling back from ios:v2 to unscoped data.
    • Prevented cross‑tag overwrites across presence, registry refresh, reconnect, and restore; public status omits tags while authenticated status includes them.
    • Backup uploads enforce instance‑authority modes (authoritative, compare‑and‑set, preserve); the presence worker rejects authority‑less backup host tuples, and tests pin atomic legacy backup authority. CI now runs Packages/iOS/CmuxMobilePairedMac tests to gate tag/restore logic.

Written for commit 06348d7. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Added iOS build-scope aware routing and presence with instance-tag specific presence summaries and build-scoped computer titles.
    • Introduced target-aware attach tickets (ticket-only, simulator injection, physical device) with scope-aware behavior.
  • Bug Fixes
    • Prevented cross-scope route/presence leakage and removed legacy cross-boundary fallback restore behavior so scoped data stays authoritative.
    • Aligned device registration, heartbeat, and backups to use instance-safe display names.
  • Tests
    • Expanded coverage for build-scope/tag isolation, instance-tag presence selection, and attach-ticket request/URL contracts.

@vercel

vercel Bot commented Jul 10, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Canceled Canceled Jul 11, 2026 5:52am
cmux-staging Building Building Preview, Comment Jul 11, 2026 5:52am

@coderabbitai

coderabbitai Bot commented Jul 10, 2026 •

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Changes

Build-scoped identity and paired-Mac routing now use versioned iOS scopes and exact instance tags. Attach-ticket creation supports simulator, physical-device, and ticket-only targets with target-specific route filtering and payloads. Development scripts share tag validation and target propagation, while presence backup restores remain isolated by scope.

Mobile identity and attach flow

Layer / File(s) Summary
Instance identity and scope contracts
Packages/Shared/CMUXMobileCore/..., Sources/Mobile/MobileAttachTicketStore.swift, Sources/Cloud/..., cmuxTests/MobileHostIdentityTests.swift
Adds versioned iOS build scopes, centralized instance tags, base/instance display names, UTF-16 limits, and scoped cloud request headers.
Destination-aware attach tickets
Sources/Mobile/..., Sources/TerminalController+MobileAttachTicket.swift, cmuxTests/MobileHostWorkspaceTicketAuthorizationTests.swift
Adds target-specific route selection, payload encoding, physical-device URL validation, terminal RPC handling, and route/payload tests.
Scoped presence and paired-Mac routing
Packages/iOS/CmuxMobileShell/..., Packages/iOS/CmuxMobileShellUI/..., ios/cmuxPackage/..., Packages/iOS/...Tests/*
Filters registry and pushed presence routes by build scope, applies scoped display names, and validates tagged versus unscoped route behavior.
Validated scripted launch flow
scripts/..., ios/scripts/reload.sh, tests/test_mobile_stability_soak_attach_contract.py
Centralizes development-tag validation and propagates simulator or physical-device attach targets through launch, reload, QR, and soak flows.
Scoped paired-Mac backup isolation
workers/presence/src/*, workers/presence/test/*
Removes unscoped restore fallback and scoped seeding, and tests isolation across legacy and versioned scopes.

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

Sequence Diagram(s)

sequenceDiagram
  participant MobileApp
  participant MobileHostService
  participant AttachTicketStore
  participant PresenceService
  participant PairedMacStore
  MobileApp->>MobileHostService: create target-specific attach ticket
  MobileHostService->>AttachTicketStore: filter routes and encode payload
  AttachTicketStore-->>MobileApp: target-specific ticket
  PresenceService->>MobileApp: tagged presence update
  MobileApp->>PairedMacStore: persist routes in matching scope
Loading

Possibly related PRs

  • manaflow-ai/cmux#7156: Both changes modify the iOS MacComputerSnapshot.snapshots flow and thread instance tags into presence lookups.
  • manaflow-ai/cmux#7384: Both changes touch mobile workspace and attach-ticket authorization paths.

Important

Pre-merge checks failed

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

❌ Failed checks (4 errors, 2 warnings)

Check name Status Explanation Resolution
Cmux Algorithmic Complexity ❌ Error MobileShellComposite+PresenceRouteSync.swift:20-66 batches presence instances but rescans registryDevices and nested instances for each one, making the hot socket path O(n×m). Cache registryDevices by deviceId and instance tag (or build a one-pass grouped index) so each pushed presence update resolves in O(1) instead of rescanning arrays.
Cmux Swift File And Package Boundaries ❌ Error MobileAttachTarget.swift is pure route-selection logic added to app-target Sources/Mobile, even though shared attach/QR types already live in CMUXMobileCore. Move MobileAttachTarget (and any other reusable mobile identity helpers) into Packages/Shared/CMUXMobileCore, then import that package from app code.
Cmux User-Facing Error Privacy ❌ Error FAIL: v2MobileAttachTicketCreate returns internal_error with data:["error": String(describing: error)], and V2CallResult is the RPC response surface. Redact the underlying error from the API body; return a generic internal_error and keep the detailed error only in internal logs/telemetry.
Cmux Full Internationalization ❌ Error Production Swift adds raw user-facing text: the tagged-name suffix " (\(value))" and several attach-ticket API error messages bypass localization and have no catalog entries. Route those strings through String(localized:defaultValue:) (or equivalent) and add matching translated .xcstrings entries for every supported locale.
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The description has useful content, but it doesn't follow the required template and omits Summary, Demo Video, Review Trigger, and Checklist sections. Rewrite it using the repository template and add the missing sections, including the Review Trigger block and checklist items.
✅ Passed checks (19 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 No new Swift 6 isolation debt: the touched APIs are MainActor UI/code, an actor service, or pure value helpers; no new implicitly-mainactor protocols or unsafe Sendable refs were added.
Cmux Swift Blocking Runtime ✅ Passed Changed Swift paths use async task chaining/actors, and I found no new blocking waits, sleeps, semaphores, main-queue sync, or added manual locks.
Cmux Browser Automation Off-Main ✅ Passed HEAD changes only add MobileAttachTarget.swift for attach-target route selection; no browser.*, WebKit/AppKit, or socket-worker automation code is touched.
Cmux Expensive Synchronous Load ✅ Passed Touched Swift files only adjust build-scope/name/routing logic; no new RestorableAgentSessionIndex.load() or large JSON/JSONL agent-history parsing was added to a main-actor/interactive path.
Cmux Cache Substitution Correctness ✅ Passed PASS: The added scope/tag reads are for UI snapshots and exact route authority; I found no fresh authoritative read replaced by a stale cache in persistence/history paths.
Cmux No Hacky Sleeps ✅ Passed HEAD only changes a Swift file; no non-Swift runtime/script diff introduced fixed sleeps, polling, or wall-clock waits.
Cmux Swift Concurrency ✅ Passed PR diff adds no new GCD/completion/Combine patterns; the only new Task is stored in pushedRouteSyncTask and awaited in tests, so it’s lifecycle-managed.
Cmux Swift @Concurrent ✅ Passed Touched Swift async changes stay on @MainActor or actor isolation; no new nonisolated async work or misplaced @concurrent annotations appear in the diff.
Cmux Swiftpm Lockfiles ✅ Passed The checked commit only adds Sources/Mobile/MobileAttachTarget.swift; no .gitignore, Package.swift, Xcode package refs, or Package.resolved files changed, so the lockfile rule isn’t triggered.
Cmux Swift Logging ✅ Passed PASS: The PR diffs only changed routing/identity code; scans found no added or modified print/debugPrint/dump/NSLog or Logger declarations in the touched Swift files.
Cmux Swiftui State Layout ✅ Passed Touched SwiftUI files only adjust presentation/snapshot plumbing; no new ObservableObject/@published, GeometryReader measurement, or render-time state mutation was introduced.
Cmux Architecture Rethink ✅ Passed PASS: the PR centralizes tagged build/routing ownership in explicit scope values and shared async write chains; I found no introduced sleeps, polls, observers, or duplicate lifecycles.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR only touches SwiftUI view/helper code and a new enum; no NSWindow/NSPanel/WindowGroup or cmuxAuxiliaryWindowIdentifiers changes, so the rule isn’t triggered.
Cmux Source Artifacts ✅ Passed All changed paths are source/tests/scripts/configs; none are logs, caches, build output, temp dirs, or scratch/artifact dirs, and no banned artifact paths appear.
Cmux No Test Or Debug Seam In Production Source ✅ Passed No new production test seam was added; the PR removes waitForPushedRouteSyncForTesting and widens state for @testable access. The remaining #if DEBUG is product behavior.
Cmux No Ambient Global State ✅ Passed PASS: merge-base diff adds only methods inside existing types; no new file-scope funcs/mutable globals/new singletons were introduced.
Title check ✅ Passed The title clearly reflects the main change: isolating and labeling tagged iOS dev computers.
✨ 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 task-tag-ios-dev-computer-names

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 10, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR isolates tagged iOS dev builds from other Mac app instances. The main changes are:

  • Versioned iOS build scopes for saved Macs and backups.
  • Instance-tag-aware paired-Mac storage, restore, and route writes.
  • Tag-aware presence, registry refresh, reconnect, and secondary promotion paths.
  • Target-aware mobile attach tickets for legacy, simulator, physical device, and ticket-only flows.
  • Tests and CI coverage for paired-Mac instance isolation and attach-ticket compatibility.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Important Files Changed

Filename Overview
Packages/iOS/CmuxMobilePairedMac/Sources/CmuxMobilePairedMac/MobilePairedMacStore.swift Adds instance-tag persistence, schema migration, and conditional paired-Mac writes.
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/IOSBuildScopedPairedMacStore.swift Scopes paired-Mac rows by iOS build tag and reconciles team-scoped fallback rows.
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+PresenceRouteSync.swift Applies presence-pushed routes only through matching stored instance authority.
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/DeviceRegistryService.swift Filters registry route refreshes by stored Mac instance tag.
Sources/Mobile/MobileAttachTicketStore.swift Generates attach payloads with target-specific route and URL behavior.
Sources/TerminalController+MobileAttachTicket.swift Parses optional attach targets while preserving omitted-target legacy payloads.

Reviews (18): Last reviewed commit: "Reject authority-less backup host tuples" | Re-trigger Greptile

.foregroundStyle(.secondary)
VStack(alignment: .leading, spacing: 2) {
Text(mac.displayName ?? mac.macDeviceID)
Text(scopedDisplayName(mac.resolvedName))

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.

P1 Custom Mac Name Is Dropped

When a paired Mac has a saved display name or falls back to its device id, this row now uses mac.resolvedName instead of the previous mac.displayName ?? mac.macDeviceID. The picker can show the raw host name while other paired-Mac surfaces still use the user-facing name, so users may pick or forget the wrong-looking Mac entry.

Suggested change
Text(scopedDisplayName(mac.resolvedName))
Text(scopedDisplayName(mac.displayName ?? mac.macDeviceID))

Rule Used: Flag correctness-critical detection/identity deriv... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Rejected after checking MobilePairedMac.resolvedName: it returns customName first, then displayName, then macDeviceID. The suggested expression is the pre-change behavior and would drop the user custom name. Using resolvedName makes this picker consistent with the Computers surfaces while the build scope only appends the tag.

— Claude Code

@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 (1)
Sources/TerminalController.swift (1)

14295-14313: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

routeUnavailable now has two causes but the error data only reports one.

routeUnavailable is thrown both when a requested route_id/route_kind can't be matched and (new in this PR) when target.selectRoutes(from:) finds no route matching the destination (e.g. physical_device requested on a Mac with only loopback routes and no explicit route filter). In the latter case route_id/route_kind are absent, so data comes back empty and the message "Requested mobile host route is not available" reads as if a specific route was asked for, obscuring that the real cause is the target having no eligible route. The sibling invalidAttachURL catch (Lines 14308-14313) already includes target in its data for exactly this reason.

🩹 Proposed fix to include target in routeUnavailable diagnostics
         } catch MobileAttachTicketStoreError.routeUnavailable {
             var data: [String: Any] = [:]
             if let routeID {
                 data["route_id"] = routeID
             }
             if let routeKind {
                 data["route_kind"] = routeKind
             }
+            if rawTarget != nil {
+                data["target"] = target.rawValue
+            }
             return .err(
                 code: "unavailable",
                 message: "Requested mobile host route is not available",
                 data: data.isEmpty ? nil : data
             )
🤖 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 `@Sources/TerminalController.swift` around lines 14295 - 14313, Update the
MobileAttachTicketStoreError.routeUnavailable catch in the surrounding
route-selection handler so its diagnostic data always includes target.rawValue,
while retaining route_id and route_kind when present; adjust the message if
needed to cover both unmatched requested routes and targets with no eligible
routes, matching the diagnostic approach used by the invalidAttachURL catch.
🤖 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/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileIOSBuildScope.swift`:
- Around line 54-57: Introduce a shared static convenience method such as
MobileIOSBuildScope.appliedDisplayName(_:) that applies computerDisplayName(_:)
when a current scope exists and otherwise returns the original name. Replace the
repeated MobileIOSBuildScope.current()?.computerDisplayName(x) ?? x expressions
in MacComputerDetailView, MobileHostPickerView, WorkspaceListView+MacSelection,
and MacComputerSnapshot+Store with this helper.

---

Outside diff comments:
In `@Sources/TerminalController.swift`:
- Around line 14295-14313: Update the
MobileAttachTicketStoreError.routeUnavailable catch in the surrounding
route-selection handler so its diagnostic data always includes target.rawValue,
while retaining route_id and route_kind when present; adjust the message if
needed to cover both unmatched requested routes and targets with no eligible
routes, matching the diagnostic approach used by the invalidAttachURL catch.
🪄 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

Run ID: 3379ef71-b5a5-467d-8c55-9cef01128708

📥 Commits

Reviewing files that changed from the base of the PR and between 2b122c4 and 29d16dd.

📒 Files selected for processing (28)
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileIOSBuildScope.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+ManualAttachTicket.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+PairedMacAliases.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/PresenceMap.swift
  • Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/IOSBuildScopedPairedMacStoreTests.swift
  • Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/PresenceMapTests.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/MacComputerDetailView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/MacComputerSnapshot+Store.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/MobileHostPickerView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListView+MacSelection.swift
  • Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/WorkspaceMacSelectionTests.swift
  • Sources/Cloud/DeviceRegistryClient.swift
  • Sources/Cloud/MacPairedMacBackupPublisher.swift
  • Sources/Cloud/PresenceHeartbeatClient.swift
  • Sources/Mobile/MobileAttachTicketStore.swift
  • Sources/Mobile/MobileHostService.swift
  • Sources/Mobile/Pairing/MobilePairingModel.swift
  • Sources/TerminalController.swift
  • cmuxTests/MobileHostAuthorizationTests.swift
  • cmuxTests/MobileHostIdentityTests.swift
  • ios/scripts/reload.sh
  • scripts/dev-setup.sh
  • scripts/lib/attach-url.test.mjs
  • scripts/lib/mobile-attach.sh
  • scripts/lib/mobile-attach.test.mjs
  • scripts/mobile-attach-qr.sh
  • scripts/mobile-dev-launch.sh
  • scripts/reload.sh

Comment thread Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileIOSBuildScope.swift Outdated
@azooz2003-bit

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@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)
Sources/Mobile/MobileHostService.swift (1)

1066-1092: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Preserve the empty-routes distinction

target.selectRoutes(from: []) now throws .routeUnavailable before ticketStore.createTicket runs, so the .noRoutes catch in Sources/TerminalController+MobileAttachTicket.swift no longer covers the common “host not listening yet” case. Add an explicit empty-routes guard here, or let .noRoutes bubble through for .ticketOnly, so the user sees the more accurate message.

🤖 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 `@Sources/Mobile/MobileHostService.swift` around lines 1066 - 1092, Add an
explicit empty-routes check in createAttachTicket before calling
target.selectRoutes, preserving the noRoutes outcome when the host is not
listening; for ticketOnly, either throw the existing .noRoutes error or
otherwise ensure it bubbles to TerminalController+MobileAttachTicket.swift,
while retaining target-specific routeUnavailable behavior where appropriate.
Sources/Mobile/MobileAttachTicketStore.swift (1)

353-377: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Case-sensitive "default" sentinel check diverges from MobileIOSBuildScope's case-insensitive check.

instanceDisplayName only treats an exact-lowercase "default" as the reserved sentinel (line 362), while MobileIOSBuildScope.init? (Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/MobileIOSBuildScope.swift:19) uses trimmed.lowercased() != "default". A build tagged "Default" would be scoped as untagged/stable on the iOS side but would still get suffixed as a real tag (" (Default)") on the Mac display-name side — a cross-platform naming/scoping mismatch for a tag that differs from the reserved sentinel only in case. This contradicts the PR's stated goal of rejecting the sentinel "through a shared validator."

🐛 Proposed fix
         let trimmedTag = buildTag?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
-        guard !trimmedTag.isEmpty, trimmedTag != "default" else {
+        guard !trimmedTag.isEmpty, trimmedTag.lowercased() != "default" else {
             return trimmedName
         }

Do you want me to generate a shared validator (e.g. reuse MobileIOSBuildScope's reserved-tag check) that both the iOS scoping path and this Mac-side naming path call into, so the sentinel definition can't drift again?

🤖 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 `@Sources/Mobile/MobileAttachTicketStore.swift` around lines 353 - 377, The
reserved “default” build-tag check in instanceDisplayName is case-sensitive and
inconsistent with MobileIOSBuildScope. Treat trimmed tags case-insensitively by
rejecting any value whose lowercased form is “default”, preferably through a
shared validator used by both paths to prevent future drift.
🤖 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/CMUXMobileCore/Sources/CMUXMobileCore/MobileIOSBuildScope.swift`:
- Around line 29-32: Update the `MobileIOSBuildScope.current` method’s
`infoDictionary` default from an optional dictionary to
`Bundle.main.infoDictionary ?? [:]`, preserving the existing guard behavior
while avoiding the optional-collection lint warning.

---

Outside diff comments:
In `@Sources/Mobile/MobileAttachTicketStore.swift`:
- Around line 353-377: The reserved “default” build-tag check in
instanceDisplayName is case-sensitive and inconsistent with MobileIOSBuildScope.
Treat trimmed tags case-insensitively by rejecting any value whose lowercased
form is “default”, preferably through a shared validator used by both paths to
prevent future drift.

In `@Sources/Mobile/MobileHostService.swift`:
- Around line 1066-1092: Add an explicit empty-routes check in
createAttachTicket before calling target.selectRoutes, preserving the noRoutes
outcome when the host is not listening; for ticketOnly, either throw the
existing .noRoutes error or otherwise ensure it bubbles to
TerminalController+MobileAttachTicket.swift, while retaining target-specific
routeUnavailable behavior where appropriate.
🪄 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

Run ID: c75bb4bb-9a61-432e-9db9-61a08175ace8

📥 Commits

Reviewing files that changed from the base of the PR and between 29d16dd and 2a54701.

⛔ Files ignored due to path filters (1)
  • .github/swift-file-length-budget.tsv is excluded by !**/*.tsv
📒 Files selected for processing (29)
  • Packages/Shared/CMUXMobileCore/Sources/CMUXMobileCore/MobileIOSBuildScope.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/DeviceRegistryService.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileIOSBuildScope.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+PresenceRouteSync.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/PresenceMap.swift
  • Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/IOSBuildScopedPairedMacStoreTests.swift
  • Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileShellCompositePairedMacCoalescingTests.swift
  • Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/TaggedBuildPresenceRouteIsolationTests.swift
  • Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/TaggedBuildRegistryRouteIsolationTests.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/MobileHostPickerView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListView+MacSelection.swift
  • Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/MacComputerSnapshotBuildScopeTests.swift
  • Sources/Cloud/MacPairedMacBackupPublisher.swift
  • Sources/Mobile/MobileAttachTarget.swift
  • Sources/Mobile/MobileAttachTicketStore.swift
  • Sources/Mobile/MobileHostService.swift
  • Sources/TerminalController+MobileAttachTicket.swift
  • Sources/TerminalController.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/MacPairedMacBackupPublisherScopeTests.swift
  • cmuxTests/MobileHostWorkspaceTicketAuthorizationTests.swift
  • ios/cmuxPackage/Sources/cmuxFeature/CMUXMobileRootScene.swift
  • scripts/mobile-stability-soak/mobile-soak.py
  • tests/test_mobile_stability_soak_attach_contract.py
  • workers/presence/src/do.ts
  • workers/presence/src/syncPairedMacs.ts
  • workers/presence/test/syncPairedMacs.test.ts
  • workers/presence/test/taggedRouteIsolation.test.ts
💤 Files with no reviewable changes (1)
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileIOSBuildScope.swift

Comment on lines +29 to +32
public static func current(
infoDictionary: [String: Any]? = Bundle.main.infoDictionary,
bundleIdentifier: String? = Bundle.main.bundleIdentifier
) -> MobileIOSBuildScope? {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optional-collection lint on infoDictionary default.

SwiftLint's discouraged_optional_collection flags infoDictionary: [String: Any]? = Bundle.main.infoDictionary. Since the guard logic (infoDictionary?["CMUXDevTag"] as? String) treats nil and empty identically, defaulting to Bundle.main.infoDictionary ?? [:] would satisfy the lint without changing behavior.

🧹 Proposed fix
-        infoDictionary: [String: Any]? = Bundle.main.infoDictionary,
+        infoDictionary: [String: Any] = Bundle.main.infoDictionary ?? [:],
📝 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.

Suggested change
public static func current(
infoDictionary: [String: Any]? = Bundle.main.infoDictionary,
bundleIdentifier: String? = Bundle.main.bundleIdentifier
) -> MobileIOSBuildScope? {
public static func current(
infoDictionary: [String: Any] = Bundle.main.infoDictionary ?? [:],
bundleIdentifier: String? = Bundle.main.bundleIdentifier
) -> MobileIOSBuildScope? {
🧰 Tools
🪛 SwiftLint (0.65.0)

[Warning] 30-30: Prefer empty collection over optional collection

(discouraged_optional_collection)

🤖 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/CMUXMobileCore/Sources/CMUXMobileCore/MobileIOSBuildScope.swift`
around lines 29 - 32, Update the `MobileIOSBuildScope.current` method’s
`infoDictionary` default from an optional dictionary to
`Bundle.main.infoDictionary ?? [:]`, preserving the existing guard behavior
while avoiding the optional-collection lint warning.

Source: Linters/SAST tools

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using default effort and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 53d5a9b. Configure here.

@azooz2003-bit
azooz2003-bit merged commit b5d8b9c into main Jul 13, 2026
47 of 50 checks passed
azooz2003-bit pushed a commit that referenced this pull request Jul 15, 2026
Lands main's dev-instance pairing isolation so the phone can tell tagged
dev builds apart from production and each other (instance tags carried
through pairing, routes, authority checks, and computer labels) — the
root cause behind the sim silently rendering another instance's
workspaces, including production's.

This branch's v1 agent-chat deletion stays authoritative: main's interim
chat fixes and the artifact-viewing UI built on the deleted chat package
(#7862-era artifact chips, gallery, sheets, and their tests) are removed
rather than restored; artifact viewing is a recorded parity item to
reintegrate as transcript activity-rail content in the new GUI.
ProcessSnapshotCentralizationTests keeps its compatibility test with the
chat-registry-dependent test and helper actors stripped.
AgentProcessObservationSource adapts to main's actor-backed process
snapshot store, preserving exact-basename detection semantics. Composer
hosting keeps this branch's judged implementation (nothing to port from
main's in-file variant). Full localization-catalog union; budget,
package-group, resolved-policy, and test-wiring gates green.

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

This branch was successfully deployed

1 active deployment
Preview – cmux — 06348d75 Deployed Jul 11, 2026 by vercel[bot]
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