Skip to content

iOS: show per-build entries with build tags in computer pickers - #8816

Merged
azooz2003-bit merged 4 commits into
mainfrom
feat-picker-build-tags
Jul 24, 2026
Merged

azooz2003-bit merged 4 commits into
mainfrom
feat-picker-build-tags

Conversation

@azooz2003-bit

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

Copy link
Copy Markdown
Collaborator

A Mac paired with two builds (e.g. Nightly and Stable) shows two labeled rows in the Computers sheet, but the workspace-list "Choose Computer" picker collapsed both into one unlabeled entry, and the task composer machine menu showed two identical rows that both read as selected. You could not tell which build you were picking, and picking could not target a specific build.

Picker entries are now pairing-scoped: the entry identity is the same macDeviceID + instanceTag pairing ID the Computers sheet uses, so each build is its own row. Each row shows the build-channel label ("Nightly", "Stable", "RC", "DEV · tag") as a menu subtitle, resolved with the same priority as the sheet badge: live presence buildLabel, falling back to MacBuildChannel on the stored instance tag when offline. Selecting a row switches the foreground connection to that exact app instance via the existing switchToMac(macDeviceID:instanceTag:), including switching between sibling builds on the same physical Mac, which previously was treated as "already there". The task composer menu gets the same labels, carries the instance tag through directory search, pinned-context validation, and submit, and its double-checkmark is fixed by comparing pairing IDs.

Workspace filtering intentionally stays device-scoped: workspace previews carry no instance tag, so both sibling rows scope the list to the same physical Mac, and the filter menu keeps one unlabeled entry per device. taskTemplateStore.setLastMacDeviceID and pendingMacSwitchID also stay device-scoped.

A DEBUG workspace-list preview fixture (CMUX_UITEST_WORKSPACE_LIST_PREVIEW=1) now seeds one device with Nightly + Stable pairings so the picker rows are verifiable in a simulator without live pairings.

Tests: pairing-scoped snapshot/alias/switch coverage in WorkspaceMachineSnapshotsTests (first commit adds them red, second turns them green), plus composer submit coverage. Note CmuxMobileShellUI package tests do not run on a macOS host (pre-existing platform-declaration gap, also not in CI's package list); the composer suites in CmuxMobileShell pass on host (25/25), and behavior was verified in a simulator via the fixture.

🤖 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

Show each paired Mac build as its own entry with a build label in iOS computer pickers, and route actions to the exact app instance. The composer and workspace flows remember and use the selected pairing.

  • New Features

    • Picker entries are pairing-scoped (device + instanceTag) and show build subtitles; the collapsed title appends “Name · Build” when sibling builds share a name. Build labels resolve from live presence or fall back to MacBuildChannel via pairedMacBuildLabelsByEntryID.
    • Composer and workspace are pairing-aware: directory search, list, and submit accept an optional instanceTag; drafts and submission snapshots persist macInstanceTag (legacy drafts decode as nil) and restore the exact pairing. The workspace title picker lists per-build rows and switches only for paired entries; unpaired, workspace-only devices remain single rows. The workspace-list preview pairing fixture moved to a DEBUG-only file behind UITestConfig.
  • Bug Fixes

    • Menu rows render build labels by using bare Text/Text/Image tuples (UIMenu subtitle requirement); selection compares pairing IDs to avoid double-checks. Titles disambiguate as “Name · Build”.
    • Cancels in-flight directory/search calls if the foreground pairing changes and avoids duplicate/ambiguous rows by preferring the active pairing; matchesForegroundPairing is shared across calls.

Written for commit 5254bcf. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Added pairing-aware “instance tag” support for selecting a specific saved Mac instance across workspace and task composer flows, including directory search/listing and task submission routing.
    • Updated Mac pickers to use pairing-based selection with improved build-label display and menu behavior.
  • Bug Fixes
    • Prevented stale workspace/task composer operations from updating connections when the active Mac instance changes.
    • Improved handling for unavailable/cancelled operations during instance-aware switching.
  • Documentation
    • Added a localized Mac picker title format (English/Japanese).
  • Tests
    • Expanded unit and UI test coverage for instance-tagged selection, switching, filtering, and stale-operation safeguards.

@cursor

cursor Bot commented Jul 24, 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 commented Jul 24, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The iOS Mac-selection and task-composer flows now support optional pairing instance tags. Routing, workspace context validation, picker identity, switching, build labels, callbacks, previews, persistence, and related tests were updated to preserve device-level compatibility while distinguishing paired instances.

Changes

Instance-aware Mac pairing

Layer / File(s) Summary
Instance-aware task routing and context
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/*TaskComposer*, *TaskDirectoryList*, WorkspaceCreatePinnedContext.swift, Packages/iOS/CmuxMobileShellModel/Sources/CmuxMobileShellModel/*
Task requests, snapshots, drafts, and workspace-create contexts now carry and validate optional Mac instance tags.
Task Composer instance selection
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TaskComposer/*, TaskComposerSheet.swift, Debug/TaskComposer/*
Composer selection state, callbacks, directory operations, submission, recovery, build labels, draft restoration, and previews propagate pairing identity and instance tags.
Workspace picker identity and switching
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/Workspace*, WorkspaceShellView*, Tests/CmuxMobileShellUITests/*, ios/cmux/Resources/Localizable.xcstrings
Workspace picker entries, alias resolution, switch targets, toolbar routing, menu rendering, localization, and tests now distinguish paired instances and build labels.

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

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant WorkspaceListView
  participant WorkspaceMacSelectionScope
  participant WorkspaceShellView
  participant MobileShellComposite
  User->>WorkspaceListView: select pairing entry
  WorkspaceListView->>WorkspaceMacSelectionScope: resolve switch target
  WorkspaceMacSelectionScope-->>WorkspaceListView: macDeviceID and instanceTag
  WorkspaceListView->>WorkspaceShellView: request Mac switch
  WorkspaceShellView->>MobileShellComposite: switchToMac(macDeviceID, instanceTag)
  MobileShellComposite-->>WorkspaceShellView: updated foreground pairing
Loading

Possibly related PRs

Suggested reviewers: austinywang, lawrencecchen


Important

Pre-merge checks failed

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

❌ Failed checks (3 errors, 1 warning)

Check name Status Explanation Resolution
Cmux Cache Substitution Correctness ❌ Error Completed-operation reconciliation now uses selectedMachine?.instanceTag instead of the persisted submittedSnapshot.macInstanceTag, so a stale/cold UI selection can rewrite a recovery snapshot. Use snapshot.macInstanceTag (or re-resolve from the submitted snapshot) and only fall back to current selection with an explicit freshness/staleness check or documented rationale.
Cmux Algorithmic Complexity ❌ Error WorkspaceMacSelectionScope rebuilds picker state per render, and pairedMacAliasIDs(for:) falls back to a full scan of alias-map values, making picker setup O(p×r) in a hot UI path. Pass a direct representative-ID map (or the alias dictionary) into the scope so lookups are single-pass dictionary/set hits, and cache the scope snapshot instead of rebuilding it repeatedly.
Cmux No Ambient Global State ❌ Error WorkspaceListLayoutPreviewView.swift:383 adds enum WorkspaceListLayoutPreviewFixture { static var ... }, a caseless static-only namespace exposing preview state. Move the preview Mac list onto an instance-owned preview model or inject it into WorkspaceListView instead of exposing a top-level fixture namespace.
Docstring Coverage ⚠️ Warning Docstring coverage is 8.06% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (21 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 The diff only extends value models and @MainActor UI/composite APIs; no new implicit MainActor models, unsafe Sendable references, or background store access.
Cmux Swift Blocking Runtime ✅ Passed PASS: touched production files add pairing routing only; no new semaphores, locks, sync waits, or sleeps, and DEBUG preview Task.sleep calls were preexisting.
Cmux Browser Automation Off-Main ✅ Passed PR only changes iOS shell/UI and model code; it չի touch the browser-automation socket routing files or worker policy covered by the rule.
Cmux Expensive Synchronous Load ✅ Passed Touched interactive Swift paths only rewire pairing selection/routing; no RestorableAgentSessionIndex.load() or other history/JSON/directory scans were added.
Cmux No Hacky Sleeps ✅ Passed PR diff only changes Swift, resources, and workflows; no covered non-Swift runtime/script sleeps or polling were introduced.
Cmux Swift Concurrency ✅ Passed Diff only threads instanceTag through existing async SwiftUI/OS callback boundaries; no new DispatchQueue, Combine, completion-handler, or fire-and-forget Task patterns were introduced.
Cmux Swift @Concurrent ✅ Passed No new @concurrent misuse or nonisolated async regressions found; the added async calls remain @MainActor/UI-bound and the diff introduces no conflicting concurrency annotations.
Cmux Swift Package Boundaries ✅ Passed The app-target additions are Ghostty/TerminalController glue; the reusable picker and pairing logic lives in SwiftPM targets.
Cmux Swiftpm Lockfiles ✅ Passed No cmux-owned .gitignore or Package.resolved changes were touched, and the Xcode project diff only adds source membership—not SwiftPM package references.
Cmux Swift Logging ✅ Passed PASS: PR diff adds no print/debugPrint/dump/NSLog or new Logger calls in changed Swift files; the only Logger hit is pre-existing in MobileShellComposite.swift and not touched by the diff.
Cmux User-Facing Error Privacy ✅ Passed Changed failure/recovery copy stays generic (e.g. “Not connected to your Mac”); no vendor/internal/raw details were introduced.
Cmux Full Internationalization ✅ Passed New UI copy is localized via L10n/String(localized:defaultValue:), and the new xcstrings key has en/ja translations; remaining literals are tests/debug-only or exact tokens.
Cmux Swiftui State Layout ✅ Passed No new ObservableObject/@published, GeometryReader, or list-row store-reference smells were introduced in the changed SwiftUI files; the diff stays on value snapshots and action closures.
Cmux Architecture Rethink ✅ Passed Diff threads instanceTag through existing single-owner snapshot/switch paths; no new sleeps, locks, observers, side channels, or split lifecycle wiring were introduced.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR only changes pickers/menus and related state; no new or modified NSWindow/WindowGroup code or cmux.* window identifiers appear in the diff.
Cmux Source Artifacts ✅ Passed No scratch/build/cache paths appear; the only media files are onboarding PNGs loaded as app resources by OnboardingScreenshot.swift, so they’re intentional assets.
Cmux No Test Or Debug Seam In Production Source ✅ Passed The new fixture is isolated in a DEBUG-only preview file/folder; I found no new test-hook/debug seam names or visibility-widening accessors in production source.
Title check ✅ Passed The title is concise and clearly describes the main computer-picker change.
Description check ✅ Passed The description clearly explains the change and testing; the missing template boilerplate sections do not block review.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-picker-build-tags

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

❤️ Share

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

@greptile-apps

greptile-apps Bot commented Jul 24, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR makes iOS Mac pickers pairing-scoped: each paired build (Nightly, Stable, RC) gets its own labeled row, selection carries the instanceTag through search, directory listing, pinned-context validation, and submit, and sibling builds on the same physical Mac can now be switched between instead of being silently collapsed to one unlabeled entry.

  • Workspace-list picker switches from a Picker to bare Button/Text/Text/Image rows so UIMenu bridging can render the build label as a subtitle; selection and switch logic delegates to WorkspaceMacSelectionScope.shouldSwitch(to:) and switchTarget(for:) using the stored isActive flag as the authority for which sibling is active.
  • Task composer adds selectedMacInstanceTag state, threads it through draft persistence (MobileTaskComposerDraft.macInstanceTag), submission snapshots (MobileTaskSubmissionSnapshot.macInstanceTag), isRequestEquivalent, and the full submit/search/list call chain; the double-checkmark bug is fixed by comparing mac.id (pairing ID) instead of mac.macDeviceID.
  • One inconsistency found: reconcileCompletedOperation in TaskComposerSheet+CompletedOperationRecovery.swift passes selectedMachine?.instanceTag (current UI state) rather than snapshot.macInstanceTag (original submission target), diverging from the main submit path and able to route the recovery submit to the wrong app instance if the user changes the Mac picker after submitting.

Confidence Score: 4/5

Safe to merge after verifying or fixing the recovery submit path — the rest of the pairing-scoped picker plumbing is consistent and well-tested.

The pairing-scoped picker, alias index, selection scope, draft/snapshot model, search, and list paths are all internally consistent and covered by new tests. One gap exists in reconcileCompletedOperation: it uses the current UI selection's instance tag rather than the snapshot's, so a recovery retry after a Mac-picker change could silently submit to the wrong app instance or fail with a misleading not-connected error. The main submit path handles this correctly, making the inconsistency easy to spot and fix.

Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TaskComposer/TaskComposerSheet+CompletedOperationRecovery.swift — the reconcileCompletedOperation function uses selectedMachine?.instanceTag instead of snapshot.macInstanceTag.

Important Files Changed

Filename Overview
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TaskComposer/TaskComposerSheet+CompletedOperationRecovery.swift Recovery submit uses current selectedMachine?.instanceTag instead of snapshot.macInstanceTag, diverging from the main submit path and risking a wrong-instance submission.
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TaskComposer/TaskComposerSheet.swift Adds selectedMacInstanceTag state; wires it through validation, draft, and submit correctly; machineBuildLabelsByID computed per body call but machine list is small.
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceMacPickerAliasIndex.swift Refactored to pairing-scoped representative/alias mapping; two-pass init correctly maps device-level aliases to preferred pairing IDs and self-maps pairing IDs.
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceMacSelectionScope.swift Adds shouldSwitch(to:) and switchTarget(for:) using isActive as primary signal; logic is sound and isActive is the designated authority for active pairing.
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceMachineSnapshots.swift Adds buildLabelsByID and macPickerTitle(for:fallback:) with correct sibling-disambiguation; String(format:) is a cold path, not a loop.
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListView+MacSelection.swift Switches picker to bare Button/label rows with Text/Text/Image tuple for UIMenu subtitle support; selection and switch logic ported to pairing scope correctly.
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+TaskComposer.swift matchesForegroundPairing replaces bare deviceID comparison consistently across search, list, and submit; instanceTag guard in pinned-context validation is correct.
Packages/iOS/CmuxMobileShellModel/Sources/CmuxMobileShellModel/MobileTaskSubmissionSnapshot.swift macInstanceTag added to snapshot, isRequestEquivalent, withOperationID, and draft conversion; legacy drafts decode nil correctly.

Sequence Diagram

sequenceDiagram
    participant UI as WorkspaceMacTitlePicker
    participant Scope as WorkspaceMacSelectionScope
    participant List as WorkspaceListView
    participant Store as MobileShellComposite
    participant Comp as TaskComposerSheet

    UI->>Scope: shouldSwitch(to: pairingID)
    Scope-->>UI: true (active.id ≠ target.id)
    UI->>List: switchMac(macDeviceID, instanceTag)
    List->>Store: switchToMac(macDeviceID:instanceTag:)
    Store-->>List: true (connected)

    Note over Comp: Mac picker (composer)
    Comp->>Comp: selectMachine(macDeviceID, instanceTag)
    Comp->>Comp: "selectedMacInstanceTag = instanceTag"

    Note over Comp: Submit
    Comp->>Comp: captureSnapshot() → MobileTaskSubmissionSnapshot(macInstanceTag:)
    Comp->>Store: submitTaskComposer(macDeviceID, snapshot.macInstanceTag, spec)
    Store->>Store: matchesForegroundPairing → switchToMac if needed
    Store->>Store: captureWorkspaceCreateContext (validates instanceTag)
    Store-->>Comp: .success

    Note over Comp: Recovery path (bug)
    Comp->>Store: submitTaskComposer(snapshot.macDeviceID, selectedMachine?.instanceTag ⚠️, spec)
Loading

Comments Outside Diff (1)

  1. Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TaskComposer/TaskComposerSheet+CompletedOperationRecovery.swift, line 30-36 (link)

    P1 Recovery submits with wrong instance tag

    reconcileCompletedOperation uses selectedMachine?.instanceTag for the instance tag while using snapshot.macDeviceID for the device. These come from two different sources of truth: the current UI state and the original snapshot. If the user changes the Mac picker selection after the initial submission completes (selecting mac-a::stable while the snapshot targets mac-a::nightly), the recovery submit will pair the original device ID with the new instance tag. This either routes to the wrong app instance or causes submitTaskComposer to return .notConnected (because the pinned-context validation in captureWorkspaceCreateContext would fail instanceTag == nil || pinnedContext.instanceTag == instanceTag). The main submit path in TaskComposerSheet.swift consistently uses snapshot.macInstanceTag — the recovery path should match.

Reviews (3): Last reviewed commit: "Merge origin/main into feat-picker-build..." | Re-trigger Greptile

Comment on lines +54 to +57
#if DEBUG
/// Pairing rows supplied by the store-free workspace-list simulator fixture.
var previewDisplayPairedMacs: [MobilePairedMac] = []
#endif

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 Debug seam in production source

previewDisplayPairedMacs is a #if DEBUG-guarded stored property added to the production WorkspaceListView struct with no production caller — the only reach path is inside the #if DEBUG branch of displayPairedMacsForPicker. The canonical fix is to move the property into the dedicated debug file (WorkspaceListLayoutPreviewView.swift, which is already fully guarded by #if canImport(UIKit) && DEBUG) or into a new WorkspaceListView+Debug.swift extension, rather than polluting the main struct's surface.

Rule Used: Do not add new test/debug seams (ForTesting-styl... (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.

Fixed in 76c812d: the fixture rows moved into the DEBUG-only WorkspaceListLayoutPreviewView.swift behind UITestConfig.workspaceListLayoutPreviewEnabled; the production struct no longer carries fixture storage.

@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: 4

🤖 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/MobileShellComposite`+TaskComposer.swift:
- Around line 260-263: The foreground-pairing condition is duplicated instead of
shared. In
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+TaskComposer.swift#L260-L263,
make matchesForegroundPairing(macDeviceID:instanceTag:) module-internal by
removing private; in
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+TaskDirectoryList.swift#L35-L44,
replace both inline foregroundMacDeviceID/activeMacInstanceTag checks with calls
to the shared helper.

In
`@Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TaskComposer/TaskComposerSheet.swift`:
- Around line 566-570: Update the task-composer draft persistence and
restoration flow around submitTaskComposer so the selected machine’s instanceTag
is stored alongside macDeviceID. Read selectedMachine once and derive both
submission identity components from that same value, preserving the exact
selected pairing across relaunches instead of resolving only by Mac device.

In
`@Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListView`+MacSelection.swift:
- Around line 79-99: Extract the shared Mac display-name and build-label
assembly used by macDisplayNamesByID() and macBuildLabelsByID() into a reusable
helper, then update both WorkspaceListView+MacSelection and WorkspaceShellView’s
workspaceShellRenderPresentation to use it. Preserve the existing macDeviceID/id
mappings and presenceSummary/build-label fallback behavior.

In
`@Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceShellView.swift`:
- Around line 576-596: Replace the duplicated name and build-label assembly in
the workspace snapshot construction with the shared macDisplayNamesByID() and
macBuildLabelsByID() helpers from WorkspaceListView+MacSelection.swift. Preserve
the existing build-scope name transformation and pass the consolidated results
into WorkspaceMachineSnapshots.
🪄 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: 5f11ea0d-8c31-424d-a60b-6a878a1498f6

📥 Commits

Reviewing files that changed from the base of the PR and between d3dda7b and 71d741d.

📒 Files selected for processing (25)
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+TaskComposer.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+TaskDirectoryList.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+WorkspaceCreateRequest.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/WorkspaceCreatePinnedContext.swift
  • Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileTaskComposerSubmitTests.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/Debug/TaskComposer/TaskComposerAccessibilityPreviewView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TaskComposer/TaskComposerContextSection.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TaskComposer/TaskComposerMachineMenu.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TaskComposer/TaskComposerMachineMenuActions.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TaskComposer/TaskComposerMachineMenuValue.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TaskComposer/TaskComposerRoutePicker.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TaskComposer/TaskComposerSheet+CompletedOperationRecovery.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TaskComposer/TaskComposerSheet.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceFilterMachine.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListLayoutPreviewView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListView+MacSelection.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceMacPickerAliasIndex.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceMacSelectionScope.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceMachineSnapshots.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceShellView+WorkspaceActions.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceShellView.swift
  • Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/WorkspaceMacSelectionTests.swift
  • Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/WorkspaceMachineSnapshotsTests.swift

…elected pairing

UIMenu bridging drops any Text wrapped in a stack inside a menu button
label, so the build labels never rendered; menu rows are now bare
Text/Text/Image tuples (title, subtitle, icon) in both the workspace
title picker and the task composer machine menu. The collapsed picker
title appends the build label when sibling builds share a name.

Review fixes: the workspace-list preview pairing fixture moves out of
the production view into the DEBUG-only fixture file behind
UITestConfig; matchesForegroundPairing is shared with the directory
list instead of duplicated; build-label derivation lives in one store
helper; submission snapshots and composer drafts persist macInstanceTag
(legacy drafts decode with nil) and submit reads the tag from the
captured snapshot instead of live state.

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

cursor Bot commented Jul 24, 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/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TaskComposer/TaskComposerSheet.swift (2)

111-122: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Do not retarget an unavailable tagged draft to a sibling build.

If the draft requested nightly but that pairing no longer exists, the active/first fallback silently selects another instance on the same Mac. Preserve the requested tag with no selected machine, or clear the selection, until the user explicitly chooses a valid pairing.

As per coding guidelines and path instructions, correctness-critical pairing identity must use a structured source and fail closed when it is unavailable.

🤖 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/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TaskComposer/TaskComposerSheet.swift`
around lines 111 - 122, Update the selectedMac resolution around
draftInstanceTag so a draft with a requested instanceTag only selects the
matching available pairing and otherwise remains unselected. Do not continue to
the active or first same-Mac fallbacks when the requested tag is unavailable;
retain those fallbacks only for drafts without a specific tag, using the
structured pairing identity and fail-closed behavior.

Sources: Coding guidelines, Path instructions


148-152: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Include the instance tag when restoring the idempotency key.

isRequestEquivalent(to:) now treats macInstanceTag as request-defining, but this predicate can reuse a draft operation ID after the selected tag changed (including legacy nil → active tagged pairing). Require tag equality here and in canRestoreCompletedOperation before restoring either ID.

🤖 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/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TaskComposer/TaskComposerSheet.swift`
around lines 148 - 152, Update the draft restoration predicate around
restoredOperationID to also require equality between the selected mac instance
tag and the draft’s macInstanceTag, preserving nil-to-active-tag changes as
non-equivalent. Apply the same tag-equality requirement in
canRestoreCompletedOperation before restoring either operation ID.
🤖 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/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TaskComposer/TaskComposerSheet.swift`:
- Around line 111-122: Update the selectedMac resolution around draftInstanceTag
so a draft with a requested instanceTag only selects the matching available
pairing and otherwise remains unselected. Do not continue to the active or first
same-Mac fallbacks when the requested tag is unavailable; retain those fallbacks
only for drafts without a specific tag, using the structured pairing identity
and fail-closed behavior.
- Around line 148-152: Update the draft restoration predicate around
restoredOperationID to also require equality between the selected mac instance
tag and the draft’s macInstanceTag, preserving nil-to-active-tag changes as
non-equivalent. Apply the same tag-equality requirement in
canRestoreCompletedOperation before restoring either operation ID.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e43a0361-a6b0-42a0-9b24-18a7c548f018

📥 Commits

Reviewing files that changed from the base of the PR and between 71d741d and 76c812d.

📒 Files selected for processing (16)
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+PairedMacAliases.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+TaskComposer.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+TaskDirectoryList.swift
  • Packages/iOS/CmuxMobileShellModel/Sources/CmuxMobileShellModel/MobileTaskComposerDraft.swift
  • Packages/iOS/CmuxMobileShellModel/Sources/CmuxMobileShellModel/MobileTaskSubmissionSnapshot.swift
  • Packages/iOS/CmuxMobileShellModel/Tests/CmuxMobileShellModelTests/MobileTaskSubmissionSnapshotTests.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TaskComposer/TaskComposerMachineMenu.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TaskComposer/TaskComposerSheet+DraftState.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/TaskComposer/TaskComposerSheet.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListLayoutPreviewView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListView+MacSelection.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceMachineSnapshots.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceShellView.swift
  • Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/WorkspaceMachineSnapshotsTests.swift
  • ios/cmux/Resources/Localizable.xcstrings
💤 Files with no reviewable changes (1)
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListView.swift

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

@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/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/WorkspaceMacSelectionTests.swift (1)

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

Assert the pairing instance tag in these stubs.

Each updated switchMac closure accepts the new String? argument but discards it as _. These tests still pass if routing drops or misroutes target.instanceTag. Add a sibling-build fixture sharing one macDeviceID, capture both arguments, and assert the exact (macDeviceID, instanceTag) pair.

Also applies to: 63-66, 96-99, 160-166, 240-246, 323-332, 416-426, 493-499, 579-584

🤖 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/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/WorkspaceMacSelectionTests.swift`
around lines 39 - 42, The switchMac test stubs currently discard the pairing
instance tag, so they do not verify routing. Update each referenced closure to
capture both macDeviceID and instanceTag, add a sibling-build fixture using the
same macDeviceID where needed, and assert the exact expected (macDeviceID,
instanceTag) pair in the associated tests.
🤖 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/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/WorkspaceMacSelectionTests.swift`:
- Around line 39-42: The switchMac test stubs currently discard the pairing
instance tag, so they do not verify routing. Update each referenced closure to
capture both macDeviceID and instanceTag, add a sibling-build fixture using the
same macDeviceID where needed, and assert the exact expected (macDeviceID,
instanceTag) pair in the associated tests.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2a149765-0431-41da-8654-d7ffb572eb8a

📥 Commits

Reviewing files that changed from the base of the PR and between 76c812d and 5254bcf.

📒 Files selected for processing (3)
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift
  • Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/WorkspaceMacSelectionTests.swift
  • ios/cmux/Resources/Localizable.xcstrings

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