Skip to content

iOS: show which features a Mac update unlocks when the connected Mac is older - #7960

Merged
azooz2003-bit merged 13 commits into
mainfrom
feat-ios-mac-update-indicator
Jul 13, 2026
Merged

azooz2003-bit merged 13 commits into
mainfrom
feat-ios-mac-update-indicator

Conversation

@azooz2003-bit

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

Copy link
Copy Markdown
Collaborator

When the connected Mac lacks mobile host capabilities that this iOS build knows how to use, and those capabilities first shipped in a released Mac version newer than the Mac's reported version, the workspace-list toolbar shows a subtle teal up-arrow indicator (same UX pattern as the alt-screen notice). Tapping it opens a popover naming the Mac, its version, and the exact features an update adds (for example: "MacBook Pro (2) is on cmux 0.64.15. Updating to 0.64.16 or later adds: Mark workspaces read or unread, Close workspaces, and Workspace groups."), with a "Don't show again for this version" action. No generic nag: the indicator needs a concrete capability gap, a parseable Mac version, and a released Mac version that closes the gap, otherwise nothing shows.

Mechanism: MobileMacUpdateAdvisor (pure, in CmuxMobileShell) compares the mobile.host.status capability set and mac_app_version (falling back to the attach ticket's version) against a compiled registry mapping each mobile-gated capability to the first released Mac version that advertises it (workspace.actions.v1 -> 0.64.15; read_state/close/groups -> 0.64.16; move/group_actions/create_in_group/group_create -> nil = unreleased, never claimed). Unknown, missing, or suffixed (nightly/prerelease) versions parse to nil and suppress the hint, so the indicator never lies. MacUpdateHintIndicatorButton mounts in the workspace-list trailing toolbar only while a hint exists; dismissal persists per macDeviceID + gap signature (sorted missing capability ids + minimum version) and re-arms only when the gap changes. ios_mac_update_hint_shown/_dismissed analytics fire through the existing emitter. All new strings are localized in English and Japanese. A DEBUG-only Mac seam (CMUX_DEBUG_SUPPRESS_MOBILE_CAPS, CMUX_DEBUG_MOBILE_APP_VERSION) lets a dev Mac impersonate an older host for dogfood; Release behavior is unchanged.

The first pass shipped this as a list banner; after owner dogfood feedback it was reworked into the toolbar indicator + popover (b29224a), reusing the alt-screen notice presentation.

Verification: swift test on CmuxMobileShell (428 tests) and CmuxMobileShellUITests via xcodebuild on an isolated simulator (80 tests) green, including advisor decision tables (older/equal/newer/unknown/prerelease/unreleased/mixed), version parsing, and dismissal-store scoping. Verified live on a dedicated simulator against a tagged Mac impersonating 0.64.14 and 0.64.15: glyph shown with exact popover copy, absent against an up-to-date Mac, dismissal instant and persisted, re-armed when the gap set changed, and a capability whose registry version equals the Mac's version is truthfully omitted. Two independent verifier sessions (one per UI iteration) reproduced the test runs and approved the screenshot/log evidence.

🤖 Generated with Claude Code


Note

Low Risk
Mostly additive UX and pure version/capability logic with conservative fail-closed rules; connection and dismissal paths are covered by unit tests, with no auth or data-plane changes in Release.

Overview
Adds a truthful Mac update advisor on iOS: when mobile.host.status (or attach ticket) shows the connected Mac is older than a released capability the app knows about, the workspace list can surface a teal toolbar indicator with a popover listing the minimum cmux version and unlocked features.

Model: New MobileMacAppVersion, a capability→first-ship-version registry (MobileMacUpdateCapabilityRequirement.standard), and MobileMacUpdateHint that only fires on concrete gaps—unreleased capabilities stay nil, unparseable/nightly versions suppress hints, and missing version can be inferred from advertised caps without stating a false current version in copy. Per-Mac dismissal persists via MobileMacUpdateHintDismissalStore keyed by gap signature.

Shell wiring: MobileShellComposite exposes macUpdateHint, refreshes on host status (including recovery path), clears on disconnect, and recomputes on secondary Mac promotion so the wrong host’s hint does not stick. Analytics: ios_mac_update_hint_eligible / _dismissed.

UI: MacUpdateHintIndicatorButton in the workspace toolbar when connection chrome is idle; localized EN/JA strings. DEBUG Mac seams (CMUX_DEBUG_SUPPRESS_MOBILE_CAPS, CMUX_DEBUG_MOBILE_APP_VERSION) for dogfooding older hosts.

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

Summary by CodeRabbit

  • New Features
    • Added Mac update hinting that detects newly released versions to unlock mobile workspace actions.
    • Added a toolbar indicator with a popover showing affected features and required/current Mac versions and mac name.
    • Added per-Mac, per-version dismissal so hints can be hidden after acknowledgment.
    • Added localized hint text for all supported workspace feature categories.
  • Bug Fixes
    • Update hints now refresh immediately and correctly when switching between connected Macs.
    • Hint display is suppressed when already dismissed for the current device and signature.

azooz2003-bit and others added 3 commits July 12, 2026 13:46
The banner's inputs (host capabilities, resolved Mac version) and the
computed gap signature are otherwise invisible when diagnosing why the
indicator did or did not show; sync.transport already sets the precedent.

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

vercel Bot commented Jul 13, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Jul 13, 2026 7:34am
cmux-staging Ready Ready Preview, Comment Jul 13, 2026 7:34am

@coderabbitai

coderabbitai Bot commented Jul 13, 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

Adds Mac version parsing, capability-based update hint evaluation, per-device dismissal persistence, host synchronization, debug controls, localized SwiftUI presentation, and test coverage.

Changes

Mac update hint

Layer / File(s) Summary
Version and hint evaluation
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileMacAppVersion.swift, MobileMacUpdateFeature.swift, MobileMacUpdateCapabilityRequirement.swift, MobileMacUpdateAdvisor.swift, Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/*
Defines numeric Mac versions, update features, capability requirements, standard mappings, hint generation, dismissal signatures, and validation tests.
Per-device dismissal persistence
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileMacUpdateHintDismissalStore.swift, Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileMacUpdateHintDismissalStoreTests.swift
Stores exact dismissal signatures in UserDefaults using Mac device-scoped keys.
Host synchronization and hint state
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite*.swift, Sources/Mobile/*
Refreshes and clears hints from host status, tracks device and shown signatures, emits analytics, and adds debug version or capability overrides.
Workspace-list hint presentation
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/*, ios/cmux/Resources/Localizable.xcstrings, Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/*
Adds localized hint content, adaptive popover UI, toolbar rendering, layout wiring, dismissal callbacks, connection-state gating, and display tests.

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

Sequence Diagram(s)

sequenceDiagram
  participant MobileHostService
  participant MobileShellComposite
  participant MobileMacUpdateAdvisor
  participant MobileMacUpdateHintDismissalStore
  participant WorkspaceShellView
  participant MacUpdateHintIndicatorButton

  MobileHostService->>MobileShellComposite: provide capabilities and Mac version
  MobileShellComposite->>MobileMacUpdateAdvisor: calculate update hint
  MobileMacUpdateAdvisor-->>MobileShellComposite: return hint or nil
  MobileShellComposite->>MobileMacUpdateHintDismissalStore: check dismissal signature
  MobileShellComposite-->>WorkspaceShellView: expose current hint
  WorkspaceShellView->>MacUpdateHintIndicatorButton: render toolbar indicator
  MacUpdateHintIndicatorButton->>MobileShellComposite: dismiss hint
  MobileShellComposite->>MobileMacUpdateHintDismissalStore: persist dismissal
Loading

Suggested reviewers: lawrencecchen


Important

Pre-merge checks failed

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

❌ Failed checks (2 errors, 1 warning)

Check name Status Explanation Resolution
Cmux No Test Or Debug Seam In Production Source ❌ Error Production Sources/ adds DEBUG env-var seams (CMUX_DEBUG_MOBILE_APP_VERSION, CMUX_DEBUG_SUPPRESS_MOBILE_CAPS) to spoof host version/caps; no production caller. Move spoofing into a dedicated debug-only file/module or the test target; keep production sources free of debug-only overrides and use @testable import for test observation.
Cmux No Ambient Global State ❌ Error Fail: MobileMacUpdateAdvisor.swift:42-50 adds a public caseless enum with a single static API, i.e. a static-helper namespace the rule forbids. Move the advisor logic onto a constructable, injectable type (for example an instance advisor owned by MobileShellComposite) and keep only private/fileprivate file-scope helpers.
Docstring Coverage ⚠️ Warning Docstring coverage is 8.82% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (22 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed New advisor/store code stays on @MainActor shell/view paths; pure value models are not MainActor-isolated, and no background store access was introduced.
Cmux Swift Blocking Runtime ✅ Passed No new semaphores, sync waits, sleeps, polling, or manual locks appear in the PR’s changed production hunks; the one sleep found is pre-existing and unrelated.
Cmux Browser Automation Off-Main ✅ Passed PASS: The PR only touches Mac update hint UI/version logic and localization; no browser automation routing, WebKit/AppKit wait handling, or policy tests changed.
Cmux Expensive Synchronous Load ✅ Passed The PR adds only pure version parsing, UserDefaults dismissal state, and toolbar UI; no agent-history/JSON/transcript loads were added or moved onto main/interactive paths.
Cmux Cache Substitution Correctness ✅ Passed Transient UI-only hint state is refreshed from live mobile.host.status, cleared on reset, and the promotion fallback is explicitly documented.
Cmux No Hacky Sleeps ✅ Passed Diff only touches Swift/localization files; no TypeScript, JavaScript, shell, or build/runtime scripts with sleeps/timers were changed.
Cmux Algorithmic Complexity ✅ Passed PASS: New filter/sort work is only over tiny fixed registries or feature lists, not scalable workspace collections.
Cmux Swift Concurrency ✅ Passed PASS: the new Mac-update code is synchronous/SwiftUI-only; no new DispatchQueue, Combine, completion-handler, or fire-and-forget Task patterns appear in the diff.
Cmux Swift @Concurrent ✅ Passed Diff adds only sync Mac-update logic/UI; no new nonisolated async work or invalid @concurrent annotations appear in the touched Swift files.
Cmux Swift File And Package Boundaries ✅ Passed New update logic is split into small CmuxMobileShell/CmuxMobileShellUI package files (28–98 lines); the oversized MobileShellComposite only gained 10 lines, far below the 250-line threshold.
Cmux Swiftpm Lockfiles ✅ Passed No Package.swift, Package.resolved, .gitignore, or Xcode project package-reference files changed in the PR diff, so the SwiftPM lockfile rule isn’t triggered.
Cmux Swift Logging ✅ Passed The only added logging is MobileDebugLog.anchormux in the new hint path, and that helper is DEBUG-only; no print/debugPrint/dump/NSLog or unsafe Logger changes were added.
Cmux User-Facing Error Privacy ✅ Passed New user-facing copy is informational only; it exposes no vendor/internal details, env vars, tokens, or raw errors, and the only new strings use safe product terms.
Cmux Full Internationalization ✅ Passed All new user-facing Swift text uses L10n.string, and every new Localizable.xcstrings key has translated en/ja entries; no other locale surfaces changed.
Cmux Swiftui State Layout ✅ Passed PASS: the new SwiftUI state is only local @State in MacUpdateHintIndicatorButton; no ObservableObject/@published, GeometryReader, list-row store refs, or render-time writes were introduced.
Cmux Architecture Rethink ✅ Passed The hint state has one owner (MobileShellComposite) and is passed as values/closures; no sleeps, locks, observers, or split lifecycle ownership were introduced.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed Only adds a toolbar button using SwiftUI popover; no NSWindow/WindowGroup or cmux.* window-ID changes, and popovers are explicitly allowed by the rule.
Cmux Source Artifacts ✅ Passed Changed paths are only Swift source/tests and a localization catalog; no logs, caches, build output, screenshots, or scratch dirs appear.
Title check ✅ Passed The title clearly matches the main change: an iOS UI that shows what features a Mac update unlocks when the connected Mac is older.
Description check ✅ Passed The description covers the summary and testing details well, but it omits the demo video, review trigger, and checklist sections from the template.
✨ 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-ios-mac-update-indicator

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

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds an iOS hint that explains which features a Mac update unlocks. The main changes are:

  • A version and capability registry for released Mac features.
  • Per-Mac hint dismissal and analytics tracking.
  • A localized toolbar indicator and explanatory popover.
  • Hint refresh and cleanup during status updates, disconnects, and Mac switches.
  • Debug-only capability and version overrides for dogfooding.

Confidence Score: 5/5

This looks safe to merge.

  • Anonymous hosts no longer share persisted dismissals.
  • Analytics deduplication now includes the Mac identity.
  • Connection reset and secondary promotion paths clear or recompute the hint.
  • No blocking issue remains in the reviewed fixes.

Important Files Changed

Filename Overview
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+MacUpdateHint.swift Adds per-host hint refresh, dismissal, cleanup, and analytics deduplication.
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+SecondaryPromotion.swift Recomputes the hint when a secondary Mac becomes the foreground connection.
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift Stores observable hint state and updates it across status, recovery, and reset paths.
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileMacUpdateHint.swift Computes conservative update recommendations from reported versions and capabilities.
Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/MacUpdateHintIndicatorButton.swift Adds the localized toolbar button and update-details popover.

Reviews (10): Last reviewed commit: "Share one injectable dismissal store acr..." | Re-trigger Greptile

return
}

let resolvedMacDeviceID = macDeviceID ?? "unknown"

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 Anonymous Macs Share Dismissals

When both the status response and attach ticket lack a device ID, every Mac uses the persistent key for "unknown". Dismissing a gap on one unidentified Mac therefore suppresses the same gap on another unidentified Mac, breaking the store's per-Mac contract; avoid persisting until a stable host identity is available.

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

Comment on lines +311 to +313
public internal(set) var macUpdateHint: MobileMacUpdateHint?
@ObservationIgnored var macUpdateHintMacDeviceID: String?
@ObservationIgnored var macUpdateHintShownSignatures: Set<String> = []

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 Host Switch Retains Old Hint

The foreground-host switch replaces activeTicket and supportedHostCapabilities without clearing this new connection-scoped state. Until the new host returns another status response, Mac A's banner can appear under Mac B's name, and a quick dismissal is persisted for Mac A; clear the hint during the host transition before rebuilding it from Mac B's status.

Rule Used: Flag Swift fixes that patch symptoms while leaving... (source)


macUpdateHint = hint
macUpdateHintMacDeviceID = resolvedMacDeviceID
guard macUpdateHintShownSignatures.insert(hint.dismissalSignature).inserted else { return }

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.

P2 Analytics Gate Merges Different Macs

The shown-event gate uses only the gap signature. If Mac A and Mac B have the same missing capabilities, both banners appear but only Mac A emits ios_mac_update_hint_shown, so multi-Mac sessions are undercounted.

Suggested change
guard macUpdateHintShownSignatures.insert(hint.dismissalSignature).inserted else { return }
let shownSignature = "\(resolvedMacDeviceID):\(hint.dismissalSignature)"
guard macUpdateHintShownSignatures.insert(shownSignature).inserted else { return }

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!

Comment thread Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift Outdated

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

🤖 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 `@ios/cmux/Resources/Localizable.xcstrings`:
- Around line 3863-3877: Update the localized values for
mobile.macUpdateHint.dismiss in the en and ja stringUnit entries to describe
suppression for the current feature gap, such as “these features,” rather than
the entire Mac version. Preserve the existing dismissal persistence behavior and
translated states.

In
`@Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileMacUpdateCapabilityRequirement.swift`:
- Around line 35-60: Add a registry invariant test covering
MobileMacUpdateCapabilityRequirement.standard that filters entries with a
declared release version and asserts each has a non-nil firstReleasedMacVersion.
Ensure the test exercises every released capability, including the
workspaceGroups path, so malformed MobileMacAppVersion(parsing:) literals fail
immediately.

In
`@Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite`+MacUpdateHint.swift:
- Around line 36-48: Update the Mac update hint flow around resolvedMacDeviceID
to require a non-empty stable macDeviceID before calling
MobileMacUpdateHintDismissalStore or persisting/showing the hint; when
unavailable, fail closed without evaluating the hint. Update
dismissMacUpdateHint to remove its "unknown" fallback and only dismiss using a
valid device ID, preserving existing behavior for identified devices.
🪄 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: 2518d2ee-1696-43d6-8b88-9abf30dbd9ba

📥 Commits

Reviewing files that changed from the base of the PR and between 74e166a and 2a30214.

📒 Files selected for processing (20)
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileMacAppVersion.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileMacUpdateAdvisor.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileMacUpdateCapabilityRequirement.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileMacUpdateFeature.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileMacUpdateHintDismissalStore.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+MacUpdateHint.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift
  • Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileMacAppVersionTests.swift
  • Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileMacUpdateAdvisorTests.swift
  • Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileMacUpdateHintDismissalStoreTests.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/MobileMacUpdateFeatureDisplay.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/MobileMacUpdateHintBanner.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListConnectionChrome.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceListView.swift
  • Packages/iOS/CmuxMobileShellUI/Sources/CmuxMobileShellUI/WorkspaceShellView.swift
  • Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/MobileMacUpdateFeatureDisplayTests.swift
  • Packages/iOS/CmuxMobileShellUI/Tests/CmuxMobileShellUITests/WorkspaceListConnectionChromeTests.swift
  • Sources/Mobile/MobileHostBuildIdentity.swift
  • Sources/Mobile/MobileHostService+Capabilities.swift
  • ios/cmux/Resources/Localizable.xcstrings

Comment thread ios/cmux/Resources/Localizable.xcstrings
Comment on lines +35 to +60
public static let standard: [MobileMacUpdateCapabilityRequirement] = [
.init(
capability: "workspace.actions.v1",
feature: .workspaceActions,
firstReleasedMacVersion: MobileMacAppVersion(parsing: "0.64.15")
),
.init(
capability: "workspace.read_state.v1",
feature: .workspaceReadState,
firstReleasedMacVersion: MobileMacAppVersion(parsing: "0.64.16")
),
.init(
capability: "workspace.close.v1",
feature: .workspaceClose,
firstReleasedMacVersion: MobileMacAppVersion(parsing: "0.64.16")
),
.init(
capability: "workspace.groups.v1",
feature: .workspaceGroups,
firstReleasedMacVersion: MobileMacAppVersion(parsing: "0.64.16")
),
.init(capability: "workspace.move.v1", feature: .workspaceMove, firstReleasedMacVersion: nil),
.init(capability: "workspace.group_actions.v1", feature: .workspaceGroupActions, firstReleasedMacVersion: nil),
.init(capability: "workspace.create_in_group.v1", feature: .workspaceCreateInGroup, firstReleasedMacVersion: nil),
.init(capability: "workspace.group_create.v1", feature: .workspaceGroupCreate, firstReleasedMacVersion: nil),
]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check whether MobileMacUpdateAdvisorTests already validates the standard registry.
rg -n 'standard' Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileMacUpdateAdvisorTests.swift

Repository: manaflow-ai/cmux

Length of output: 329


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Requirement source =="
sed -n '1,140p' Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileMacUpdateCapabilityRequirement.swift

echo
echo "== Version parser =="
rg -n 'init\\(parsing:|struct MobileMacAppVersion|enum MobileMacAppVersion|firstReleasedMacVersion' Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell -S

echo
echo "== Existing advisor tests around standard registry =="
sed -n '1,240p' Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileMacUpdateAdvisorTests.swift

Repository: manaflow-ai/cmux

Length of output: 3241


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '110,180p' Packages/iOS/CmuxMobileShell/Tests/CmuxMobileShellTests/MobileMacUpdateAdvisorTests.swift

Repository: manaflow-ai/cmux

Length of output: 1623


Add a registry invariant test for released capabilities

MobileMacAppVersion(parsing:) can return nil, and the current advisor test only covers the .workspaceGroups hint path. Add a test that asserts every standard entry with a declared release version still has a non-nil firstReleasedMacVersion, so a typo in one of the literals fails fast instead of silently making that capability look unreleased.

🤖 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/CmuxMobileShell/Sources/CmuxMobileShell/MobileMacUpdateCapabilityRequirement.swift`
around lines 35 - 60, Add a registry invariant test covering
MobileMacUpdateCapabilityRequirement.standard that filters entries with a
declared release version and asserts each has a non-nil firstReleasedMacVersion.
Ensure the test exercises every released capability, including the
workspaceGroups path, so malformed MobileMacAppVersion(parsing:) literals fail
immediately.

terminalScrollbackPrefetchStatesBySurfaceID = [:]
terminalOutputTransport = .rawBytes
supportedHostCapabilities = []
clearMacUpdateHint()

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 Secondary promotion keeps stale hint — This clears the hint for transitions that call resetTerminalOutputTracking(), but promoteSecondaryToForeground() switches to an existing secondary connection without using this reset or recomputing the hint. When Mac A has a visible hint and Mac B is promoted, A's hint can remain visible under B's name until another status response arrives. Dismissing it during that interval records A's gap for A's stored device ID. Clear or recompute the hint as part of secondary promotion before exposing the new foreground host.

Rule Used: Flag Swift fixes that patch symptoms while leaving... (source)

cmux reload-cloud and others added 2 commits July 12, 2026 20:15
The workspace-list toolbar renders items with its own monochrome tint, so
without an explicit .tint the indicator loses the color that marks it as
an update hint rather than a neighboring control.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Resolves the supportedHostCapabilities access-level conflict (main relaxed it
to internal(set) for secondary promotion) and recomputes the Mac-update hint
when a secondary Mac is promoted to foreground, since promotion reuses the
live client without a fresh status probe.

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.

Actionable comments posted: 6

Caution

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

⚠️ Outside diff range comments (2)
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift (2)

1189-1193: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Clear Mac update hint state on sign-out.

The supplied signOut() path resets the active Mac and workspace state but does not clear macUpdateHint or macUpdateHintShownSignatures. A previous account’s Mac/version/features can remain visible and the next account can inherit the session gate. Clear both at the account boundary.

🤖 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/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift`
around lines 1189 - 1193, Update signOut() near the existing workspace and
selection resets to also clear macUpdateHint and macUpdateHintShownSignatures.
Reset both values at sign-out so no prior account’s Mac update data or session
gate carries into the next account.

6095-6109: 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Validate host identity before publishing capabilities and hints.

This code updates observable capabilities and the Mac-update hint before applyHostReportedIdentity validates the reported device and instance tag. A stale route serving another tagged build can publish the wrong feature set/version before rejection. Normalize empty IDs as missing and complete identity validation before mutating capability or hint state.

🤖 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/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift`
around lines 6095 - 6109, Update the host-handshake flow around
applyHostReportedIdentity to normalize empty device and instance IDs as missing,
validate the reported identity first, and only then assign
supportedHostCapabilities or call updateForegroundWorkspaceActionCapabilities
and refreshMacUpdateHint. Ensure invalid or stale tagged routes cannot publish
capabilities or update hints before identity validation succeeds.
🤖 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.swift`:
- Around line 3735-3740: Remove the production-only test seam
refreshRoutesFromRegistryForTesting from MobileShellComposite.swift. Update the
test target to call the internal refreshRoutesFromRegistry helper through
`@testable` import, or relocate the wrapper into the Tests target without changing
production Sources.
- Around line 2286-2295: Update the reuse condition in the switch-to-Mac logic
around foregroundMacDeviceID, connectionState, and remoteClient so it relies
directly on
MobileMacInstanceTagAuthority.sameStoredAuthority(refreshedTarget.instanceTag,
activeMacInstanceTag). Ensure legacy reuse succeeds only when both instance tags
are absent, and missing authority never qualifies a tagged connection as
reusable.
- Around line 3241-3253: Eliminate repeated full-store scans in the aggregation
revalidation paths around the paired-Mac lookups in the aggregation loop. Load
one keyed batch snapshot before iterating, or use a targeted authoritative
lookup by macDeviceID, and reuse it at the affected validation sites (including
the paths around lines 3322, 3348, and 3441). Preserve all existing post-await
subscription, scope, forgotten-device, and instance-tag authority checks.

In
`@Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite`+SecondaryPromotion.swift:
- Around line 5-8: Update the file-scoped secondaryPromotionLog declaration to
use nonisolated private let, preserving its existing Logger configuration and
category.
- Around line 52-54: Update the secondaryPromotionLog.info call in the secondary
promotion flow to mark macID as private instead of public, preserving the
existing reuse diagnostic while ensuring the stable device identifier remains
redacted in production logs.
- Around line 18-30: The guard-failure cleanup in the secondary promotion flow
can cancel a newer subscription that replaced the captured sub during the
awaited load. In the guard’s failure branch, only cancel and remove
secondaryMacSubscriptions[macID] when the currently stored subscription is
identical to sub; otherwise leave the replacement subscription intact.

---

Outside diff comments:
In
`@Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift`:
- Around line 1189-1193: Update signOut() near the existing workspace and
selection resets to also clear macUpdateHint and macUpdateHintShownSignatures.
Reset both values at sign-out so no prior account’s Mac update data or session
gate carries into the next account.
- Around line 6095-6109: Update the host-handshake flow around
applyHostReportedIdentity to normalize empty device and instance IDs as missing,
validate the reported identity first, and only then assign
supportedHostCapabilities or call updateForegroundWorkspaceActionCapabilities
and refreshMacUpdateHint. Ensure invalid or stale tagged routes cannot publish
capabilities or update hints before identity validation succeeds.
🪄 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: e2624efe-e68b-41b0-a2a9-4abc30e3cee0

📥 Commits

Reviewing files that changed from the base of the PR and between f825a82 and 06b3368.

📒 Files selected for processing (3)
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+SecondaryPromotion.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift
  • ios/cmux/Resources/Localizable.xcstrings

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

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

Actionable comments posted: 6

Caution

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

⚠️ Outside diff range comments (2)
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift (2)

1189-1193: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Clear Mac update hint state on sign-out.

The supplied signOut() path resets the active Mac and workspace state but does not clear macUpdateHint or macUpdateHintShownSignatures. A previous account’s Mac/version/features can remain visible and the next account can inherit the session gate. Clear both at the account boundary.

🤖 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/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift`
around lines 1189 - 1193, Update signOut() near the existing workspace and
selection resets to also clear macUpdateHint and macUpdateHintShownSignatures.
Reset both values at sign-out so no prior account’s Mac update data or session
gate carries into the next account.

6095-6109: 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Validate host identity before publishing capabilities and hints.

This code updates observable capabilities and the Mac-update hint before applyHostReportedIdentity validates the reported device and instance tag. A stale route serving another tagged build can publish the wrong feature set/version before rejection. Normalize empty IDs as missing and complete identity validation before mutating capability or hint state.

🤖 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/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift`
around lines 6095 - 6109, Update the host-handshake flow around
applyHostReportedIdentity to normalize empty device and instance IDs as missing,
validate the reported identity first, and only then assign
supportedHostCapabilities or call updateForegroundWorkspaceActionCapabilities
and refreshMacUpdateHint. Ensure invalid or stale tagged routes cannot publish
capabilities or update hints before identity validation succeeds.
🤖 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.swift`:
- Around line 3735-3740: Remove the production-only test seam
refreshRoutesFromRegistryForTesting from MobileShellComposite.swift. Update the
test target to call the internal refreshRoutesFromRegistry helper through
`@testable` import, or relocate the wrapper into the Tests target without changing
production Sources.
- Around line 2286-2295: Update the reuse condition in the switch-to-Mac logic
around foregroundMacDeviceID, connectionState, and remoteClient so it relies
directly on
MobileMacInstanceTagAuthority.sameStoredAuthority(refreshedTarget.instanceTag,
activeMacInstanceTag). Ensure legacy reuse succeeds only when both instance tags
are absent, and missing authority never qualifies a tagged connection as
reusable.
- Around line 3241-3253: Eliminate repeated full-store scans in the aggregation
revalidation paths around the paired-Mac lookups in the aggregation loop. Load
one keyed batch snapshot before iterating, or use a targeted authoritative
lookup by macDeviceID, and reuse it at the affected validation sites (including
the paths around lines 3322, 3348, and 3441). Preserve all existing post-await
subscription, scope, forgotten-device, and instance-tag authority checks.

In
`@Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite`+SecondaryPromotion.swift:
- Around line 5-8: Update the file-scoped secondaryPromotionLog declaration to
use nonisolated private let, preserving its existing Logger configuration and
category.
- Around line 52-54: Update the secondaryPromotionLog.info call in the secondary
promotion flow to mark macID as private instead of public, preserving the
existing reuse diagnostic while ensuring the stable device identifier remains
redacted in production logs.
- Around line 18-30: The guard-failure cleanup in the secondary promotion flow
can cancel a newer subscription that replaced the captured sub during the
awaited load. In the guard’s failure branch, only cancel and remove
secondaryMacSubscriptions[macID] when the currently stored subscription is
identical to sub; otherwise leave the replacement subscription intact.

---

Outside diff comments:
In
`@Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift`:
- Around line 1189-1193: Update signOut() near the existing workspace and
selection resets to also clear macUpdateHint and macUpdateHintShownSignatures.
Reset both values at sign-out so no prior account’s Mac update data or session
gate carries into the next account.
- Around line 6095-6109: Update the host-handshake flow around
applyHostReportedIdentity to normalize empty device and instance IDs as missing,
validate the reported identity first, and only then assign
supportedHostCapabilities or call updateForegroundWorkspaceActionCapabilities
and refreshMacUpdateHint. Ensure invalid or stale tagged routes cannot publish
capabilities or update hints before identity validation succeeds.
🪄 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: e2624efe-e68b-41b0-a2a9-4abc30e3cee0

📥 Commits

Reviewing files that changed from the base of the PR and between f825a82 and 06b3368.

📒 Files selected for processing (3)
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+SecondaryPromotion.swift
  • Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift
  • ios/cmux/Resources/Localizable.xcstrings
🛑 Comments failed to post (6)
Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift (3)

2286-2295: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Fail closed when stored instance authority is missing.

refreshedTarget.instanceTag == nil is treated as proof that the current tagged connection is reusable. With multiple tagged builds on one Mac, switchToMac can return success without dialing the requested instance and route actions to the wrong build. Use sameStoredAuthority directly; legacy reuse should require both tags to be absent.

As per path instructions, correctness-critical identity must use one reliable source and missing signals must fail closed.

🤖 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/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift`
around lines 2286 - 2295, Update the reuse condition in the switch-to-Mac logic
around foregroundMacDeviceID, connectionState, and remoteClient so it relies
directly on
MobileMacInstanceTagAuthority.sameStoredAuthority(refreshedTarget.instanceTag,
activeMacInstanceTag). Ensure legacy reuse succeeds only when both instance tags
are absent, and missing authority never qualifies a tagged connection as
reusable.

Source: Path instructions


3241-3253: 🚀 Performance & Scalability | 🟠 Major | 🏗️ Heavy lift

Avoid O(M²) paired-Mac store scans during aggregation.

The outer aggregation loop processes every Mac, while these revalidation paths call loadAll(...).first(where:) again for each Mac. For roughly 1,000 Macs this becomes repeated full-store I/O and O(M²) work. Reuse one keyed batch snapshot or add a targeted authoritative lookup by device ID while retaining post-await revalidation.

As per path instructions, scalable production collections must avoid repeated full scans and rescans.

Also applies to: 3322-3329, 3348-3358, 3441-3458

🤖 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/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift`
around lines 3241 - 3253, Eliminate repeated full-store scans in the aggregation
revalidation paths around the paired-Mac lookups in the aggregation loop. Load
one keyed batch snapshot before iterating, or use a targeted authoritative
lookup by macDeviceID, and reuse it at the affected validation sites (including
the paths around lines 3322, 3348, and 3441). Preserve all existing post-await
subscription, scope, forgotten-device, and instance-tag authority checks.

Sources: Coding guidelines, Path instructions


3735-3740: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Remove the ForTesting wrapper from production Sources.

refreshRoutesFromRegistryForTesting is a test-only seam under production Sources. Exercise the internal helper from the test target via @testable import, or move the wrapper into Tests.

As per path instructions, production Swift under Sources/ must not add test-only or debug-only seams.

🤖 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/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite.swift`
around lines 3735 - 3740, Remove the production-only test seam
refreshRoutesFromRegistryForTesting from MobileShellComposite.swift. Update the
test target to call the internal refreshRoutesFromRegistry helper through
`@testable` import, or relocate the wrapper into the Tests target without changing
production Sources.

Source: Path instructions

Packages/iOS/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite+SecondaryPromotion.swift (3)

5-8: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Declare the file-scoped logger nonisolated.

This logger does not require MainActor access. Use nonisolated private let to comply with the repository’s Swift 6 isolation guidance.

🤖 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/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite`+SecondaryPromotion.swift
around lines 5 - 8, Update the file-scoped secondaryPromotionLog declaration to
use nonisolated private let, preserving its existing Logger configuration and
category.

Source: Coding guidelines


18-30: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Do not cancel a replacement subscription on stale failure.

sub is captured before the awaited store read. If a refresh replaces it while that read is suspended and the guard fails, this cleanup cancels whichever subscription is currently stored, potentially destroying the newer subscription. Guard cleanup with secondaryMacSubscriptions[macID] === sub.

🤖 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/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite`+SecondaryPromotion.swift
around lines 18 - 30, The guard-failure cleanup in the secondary promotion flow
can cancel a newer subscription that replaced the captured sub during the
awaited load. In the guard’s failure branch, only cancel and remove
secondaryMacSubscriptions[macID] when the currently stored subscription is
identical to sub; otherwise leave the replacement subscription intact.

52-54: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Keep the Mac device ID private in logs.

macID is a stable device identifier but is logged with .public. Use .private or log a non-identifying diagnostic.

As per coding guidelines, dynamic identifiers must remain redacted in production logs.

🤖 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/CmuxMobileShell/Sources/CmuxMobileShell/MobileShellComposite`+SecondaryPromotion.swift
around lines 52 - 54, Update the secondaryPromotionLog.info call in the
secondary promotion flow to mark macID as private instead of public, preserving
the existing reuse diagnostic while ensuring the stable device identifier
remains redacted in production logs.

Source: Coding guidelines

cmux reload-cloud and others added 2 commits July 12, 2026 21:19
…chrome-gated indicator

Fail closed when neither the status payload nor the attach ticket carries a
Mac device id, so anonymous hosts cannot share a dismissal record. Key the
shown-analytics session gate by mac id + signature so two Macs with the same
gap each count. Hide the toolbar indicator while reauth/recovery/offline
chrome is active (new WorkspaceListConnectionChrome.showsMacUpdateHintIndicator,
tested). Soften the dismiss copy to "Don't Show Again" since a changed gap
re-arms the hint by design.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cmux reload-cloud and others added 2 commits July 12, 2026 21:46
…ecovery

Structured review caught that the registry's target releases predate the
version fields themselves: mobile.host.status gained mac_app_version in
0.64.16 and attach tickets gained macAppVersion in 0.64.17, so a released
0.64.15 Mac reports no version anywhere and the production hint could never
fire. When no explicit version exists, the advisor now infers the version as
the newest firstReleasedMacVersion among registry capabilities the host DOES
advertise (a released Mac advertising a 0.64.15 capability is at least
0.64.15); hosts advertising no registered capability stay silent, and an
unparseable explicit version still suppresses inference. Inferred versions
use a body copy that names only the target version, never asserting the
Mac's current version.

Also refresh the hint from the full-timeout status recovery path
(scheduleHostIdentityAdoptionIfNeeded), which decodes a complete status
payload but previously applied only theme and identity, leaving the hint
absent or stale after a slow transport probe.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rename the shown event to ios_mac_update_hint_eligible (it fires when the
model computes a visible hint, not when the toolbar indicator renders), tag
both events with mac_app_version_inferred so inferred lower bounds cannot
pollute version-segmented metrics, and move the recovery-path refresh into
the MacUpdateHint extension so the over-budget composite stays at its
recorded length.

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

@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 1 potential issue.

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 e4d64c0. Configure here.

// free in the common case and keeps the phone's colors in sync with
// the Mac even when the probe could not.
self.applyTerminalTheme(payload.theme)
self.refreshMacUpdateHintFromRecoveredStatus(payload)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale status updates hint

Medium Severity

After the slow mobile.host.status recovery request finishes, the handler updates the Mac update hint without checking that remoteClient is still the same client that sent the request. A response from a superseded connection can populate macUpdateHint for the wrong Mac while the UI shows another host’s name.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e4d64c0. Configure here.

cmux reload-cloud and others added 3 commits July 12, 2026 22:08
@ObservationIgnored cannot annotate a multi-variable declaration (the
previous commit failed to compile), so the per-session bookkeeping moves
into a MacUpdateHintSessionState reference type owned by the extension,
which also keeps the over-budget composite at its recorded length.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Split MobileMacUpdateHint into its own file and fold the caseless
MobileMacUpdateAdvisor namespace enum into a failable initializer on the
owning type. Convert the MobileMacUpdateFeatureDisplay static namespace into
displayName/bodyText extensions on the owning types. Consciously kept: the
immutable .standard registry constant (declaration data with an explicit
lint allowance, not runtime state) and the dismissal store's private static
helpers (per the no-free-functions ruling; the store itself carries injected
UserDefaults state).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both paths constructed MobileMacUpdateHintDismissalStore() ad hoc, binding
the composite to process-wide UserDefaults.standard despite the store's
injection seam. The store now lives on MacUpdateHintSessionState so lookup
and dismissal share one instance and tests/previews can swap in a
suite-scoped store.

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

This branch was successfully deployed

1 active deployment
Preview – cmux — 8de2ae17 Deployed Jul 13, 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