Skip to content

Add opt-in Mac discovery with consistent workspace mirrors - #12105

Merged
austinywang merged 319 commits into
mainfrom
issue-8001-devices-sidebar
Sep 21, 2026
Merged

austinywang merged 319 commits into
mainfrom
issue-8001-devices-sidebar

Conversation

@austinywang

@austinywang austinywang commented Sep 8, 2026 •

Copy link
Copy Markdown
Contributor

Summary

My Devices adds opt-in discovery and terminal mirrors for other Macs on the same account. Outgoing discovery, incoming Mac access, and iPhone pairing remain independent choices. Opened Mac workspaces preserve their source splits, divider proportions, tab order, selection, terminal geometry, and scrollback; names reconcile across the device tree, workspace sidebar, and terminal tabs.

Mac layout synchronization uses authenticated, workspace-scoped revisions, stale-write rejection, idempotent request IDs, bounded validation, and rollback. Cmd-N in a device workspace creates on that same Mac. Disconnected mirrors retain their state and offer a pane-owned Retry/dismiss notice. Mac-only layout RPCs are not exposed through the SSH relay.

Updated from origin/main through c1fe9f87db (81cce8891b), with merge conflicts resolved while preserving the Devices integration: the Devices tree uses main's reference Cloud sidebar layout, and the "Run My Devices regressions" CI gate sits beside main's new "Run main window zoom placement regressions" gate on the same shard. Review fixes in 1e93365cdd:

  • Preserve presence and registry publication for users who enabled only iPhone pairing.
  • Cancel every queued/active broker registration on deactivation.
  • Preserve native tab insertion order and retain layout events during queue congestion.
  • Validate layout replies at decoding, including depth, count, uniqueness, and split ratios.
  • Group projections once during name reconciliation and remove printf formatting from device rows.
  • Use the shared cancellation-aware lease scheduler and complete the changed CLI/row translations.
  • Preserve the initiating-window host in main's workspace-creation reservation/rollback path.

The opt-in discovery default is intentional. The presence subscriber uses an injected clock for actual ping/pong protocol deadlines, with cancellation tied to its socket session; the corresponding review thread explains the existing architecture carve-out.

App-host CI stabilization

Every app-host unit test shard failed on this branch after main merged #13178, which fails a shard on any test-host restart or Swift Testing time limit. The crashes behind those restarts predate that change: this branch's last green run (892c765503) had 17 host crashes across its six shards and passed only because the old classifier tolerated a restarted host. Each crash was symbolicated against the run's own build products and fixed at its source:

Signature Where Fix
AgentChatTranscriptService.deinit asserting the main actor while AppDelegate was freed on the session-persistence queue (7 of 17) AppDelegate.persistSessionSnapshot captured self in the write block 1a34b07fc6: the block retains only the snapshot store
Unbounded recursion retiring a windowless recoverable route whose manager was already finalized retireRecoverableMainWindowRouteIfCurrent resolved owners before dropping the route 4d92128a2b (failing test) then 1b8551f38c
HIToolbox trap from KeyboardLayout on a Swift Testing worker thread KeyboardShortcutSpaceKeyTests 16f2efb0ed: suite runs on the main actor
Fatal index errors in test code after a failed expectation NewCloudWorkspaceShortcutTests, VMSSHCommandTests, ViewerNavigationTests 16f2efb0ed, 2371a90055, fa25d4d6c0: require the element first
TabManager.init precondition from a test subclass that rejected every creation WorkspaceCreateReviewRegressionTests 1c6f8da198: rejection is armed after init
responds(to:) forwarding to itself in SidebarWorkspaceDragPasteboardWriter provisional delegate installed twice a033d766d7: bounded forwarding chain
UInt(windowNumber) trap for a window without a window-server number CompositorBlurController.resetBackgroundBlur a033d766d7: non-positive numbers ignored

Not fixed here: a ghostty_surface_new null dereference seen twice in the 892c765503 run and not since (GhosttyKit internals, no symbols), and the CLI integration assertion failures in vm dev --dry-run and the vm ssh alias, which the classifier tolerates and which come from main's Cloud CLI alias unification and #13193, not from this branch.

On head 6f0d450afd (run 35555487415) shards 2 and 6 had zero host crashes; both failed on Swift Testing one-minute limits (CloudTerminalLayoutCreationTests, CloudDesktopWebSocketTests, CloudTerminalMutationRetirementTests, DeferredActionReplacementStackTests, all unchanged by this branch) while a WebKit content process took 49 to 51 seconds to launch (Could not signal service com.apple.WebKit.WebContent: 113, then WebContent process took 50.92 seconds to launch), which blocks the main actor for every test in flight. Those launch stalls are chronic on the runners: the last green run had a 50.6 s launch in shard 1 and a 41 s launch in shard 3 that tripped four limits, tolerated before #13178. That interaction is a main/CI-side reliability problem (64 tests carry .timeLimit(.minutes(1))); shards that fail only on a stall are re-run rather than patched here.

Two of the limit trips were deterministic on the runners rather than stall-starved:

  • smoothScrollingPageCapturesRequestedRegionAndRestoresOffset (shard 5, and shard 1 of the last green run) hung until the 300 s allowance: BrowserScreenshotSnapshotter.scroll(_:to:) and the DOM probe collector waited on two requestAnimationFrame callbacks, which a WKWebView outside a visible window never delivers. That is also a real hang for a capture from a hidden web view. 4c4b22daf6 bounds the wait with a 250 ms timer; visible pages still settle on the frames first.
  • computerUseFilesystemCallbacksHopSafelyToMainActor (shard 3, and shard 3 of the last green run) hung because its target was the test host itself, which the watcher ignores. Main rewrote that test around focus events (taken in the merge); this branch's interim fix was dropped in favor of main's.

Main also fixed, in its own way, the VMSSHCommandTests bind indexing and the rejecting TabManager fixture in WorkspaceCreateReviewRegressionTests; the merge takes main's versions. The four RemoteTmuxMirrorPaneInputMappingTests 300 s hangs seen in shard 1 (and in the last green run) are bounded by main's #13173, which arrives with this merge.

Testing

  • Passed: 7 DeviceWorkspaceLayoutTests, including malformed and excessive-depth/count snapshots.
  • Passed: 5 IrxBrokerArmingTests, including cancellation of an active registration behind a queued tail.
  • Added app-host regressions for iPhone-only presence, native A/B/C/D tab ordering with C selected, and lossless layout delivery during congestion. GitHub CI executes these on the current head.
  • Head 6f0d450afd (run 35555487415): Fast static checks, linux preflight, macOS compile admission, swift-package-tests, tests-build-and-lag, release-build, and app-host shard 4 passed. Shards 1, 2, 3, 5, and 6 each ran with zero host crashes; every one failed only on a Swift Testing time limit (shards 2 and 6 on WebKit launch stalls, shards 1, 3, and 5 on the deterministic hangs described above, all now addressed by this branch or by main). The relay-tls system-keychain check failed once on a runner DNS outage at checkout and passed on re-run.
  • Current head 81cce8891b (merge of main c1fe9f87db): CI run 35573799419 passed (Fast static checks, linux preflight, macOS compile admission); every PR check is green. The full-ci label was removed on 2026-09-21 07:21 UTC, so this run used the compile-only pull-request policy and skipped the app-host shards, swift-package-tests, tests-build-and-lag, and release-build; the merge queue runs the full suite on the commit that lands. The full suite was last exercised on 6f0d450afd as described above (zero host crashes; time-limit trips only). No local xcodebuild was run for any of this.
  • Passed: changed Swift parsing, Xcode test wiring (1,018 files), workspace package grouping, Package.resolved policy, and localization catalog parity (6 catalogs, all 9 supported macOS locales). Changed command prose, mode lists, device age/status labels, and plural workspace counts were audited.
  • The previous tests-build-and-lag failure was runner DNS failure fetching Ghostty dependencies (UnknownHostName); app compilation and all six unit-test shards had passed. Current-head GitHub checks remain the authoritative result.
  • Exact-head tagged build: controller job 2fa138e085738efe4fc81587, tag issue-8001-devices-review-fixes, SHA 892c7655037d644e4655e651c914124f2a7bb660. The preceding build caught main's row-grid API change; 892c765503 updates all three Devices call sites to style.rowGrid. The tagged build passed and its archive name, bundle identity, digest, and HQ manifest were verified: issue-8001-devices-review-fixes. Artifact SHA-256: c63e028be5242da5a4f266aaeba20601d65255693ece28fee19bb0c73d5dbfa2. Both controller receipts retain cleanup and timing evidence.

Existing feature dogfood was performed on this Mac and an Intel MacBook Pro; that earlier build does not substitute for validation of this review-fix revision. No new iOS installation is claimed.

Demo Video

No new recording for this CI/review update. The existing feature has been dogfooded; this revision's automated and build evidence is listed above.

Review Trigger

Existing automatic review bots continue on pushed commits. Review threads are answered with the fix or a concrete explanation; no additional second-model review was requested.

Checklist

  • I tested the change locally
  • I added or updated tests for behavior changes
  • I updated changed CLI help and localization
  • All current-head GitHub checks pass (compile-only policy on the PR; the merge queue runs the full suite)
  • Exact-head tagged build passes
  • All previously open review threads have a fix or documented resolution
  • All human review comments are addressed

Full-suite investigation (2026-09-21)

The optional full-suite label is currently removed. I audited the failed full-suite runs instead of treating every failure as a Devices regression. The broad app-host runs exercised hundreds of unchanged tests in one process and produced unrelated failures across CLI notifications, Ghostty colors, SSH/session snapshots, Dock/browser state, shortcuts, and mobile lifecycle. The deterministic mechanisms found were:

  • The Computer Use watcher test could select the test host itself and wait for a callback the host intentionally ignores. 166f76ff72 excludes the host process and bounds the wait.
  • Screenshot capture waited forever for two animation frames in an invisible WKWebView. 4c4b22daf6 adds a bounded timer fallback.
  • Swift Testing global-state suites run concurrently inside one app host; width experiments reduced the cascade but did not provide a supported full-suite fix. Width 1 and width 4 still exposed independent async timeout tests. Those CI-only timeouts are separate from the Devices-focused checks.
  • One shard failed before tests because SwiftPM could not resolve github.com (Could not resolve host: github.com), an infrastructure DNS failure.

The supported PR run on head 1881e4c906 has 39 passing checks, 8 policy skips, and only the known CLA Assistant pagination failure. The Devices-focused package/app checks and compile admission pass.

Loading
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.

2 participants