Repository navigation
Forget and Devices Remove each take out both the SSH machine and its acpmux peer - #28799
Conversation
…acpmux peer HQ #4877 break 8: remote.forget left the acpmux peer, which kept running agents, and Settings > Devices Remove left the sidebar's SSH machine. - A written Forget (after its Undo toast ends) runs `acp host rm` for the peer at the machine's exact ssh route, unless another of the app's SSH sessions still uses that route. Undo needs nothing more: the peer is only removed when the Forget is written. - Devices Remove of a peer reads its ssh route first, and once the remove succeeds forgets the SSH machines at that route. - Routes match only exactly: host (any case), user, and no ssh port. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-4bbc87e99e6352cca67a
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
web and size checks: green Default changesNo defaults change at Shipped in:
|
…bind (a tracked default) is unchanged Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-4bbc87e99e6352cca67a
|
Review (router-review gpt-6-astra high fast, independent Codex): SHIP at a3421a4 Range a06031f..a3421a4. No blocking findings. Follow-ups (filed as manaflow-ai/cmuxterm-hq#5504, which the lane that opened this PR owns):
|
…arrived) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
…ep it while another Forget's Undo shows Review at 4f15f4c (BLOCK): a reconnect during the peer CLI runs then lost its session record to forgetSession; a second pending Forget on the route lost its peer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-4bbc87e99e6352cca67a
|
Found 1 test failure on Blacksmith runners: Failure
|
…ark is its own Review at 43964a9 (BLOCK): a reconnect during host ls/rm still lost the peer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-4bbc87e99e6352cca67a
Bugbot needs on-demand usage enabledBugbot uses usage-based billing for this team and requires on-demand usage to be enabled. A team admin can enable on-demand usage in the Cursor dashboard. |
|
Review (router-review gpt-6-astra high fast, independent Codex): SHIP at 103e799 Range 4f4a957..103e799. This follows BLOCKs at 4f15f4c and 43964a9 (a reconnect racing the peer removal, stale Undo marks), both fixed here. Follow-ups are filed on manaflow-ai/cmuxterm-hq#5504: SHIP at 103e799 Visual verdict: no images supplied (range review); the visual verdict must come separately
Static review completed; macOS tests could not run because this Linux environment lacks Swift. Follow-ups:
router-review: follow-up: Coordinate reconnects with in-flight peer removal and cover the race. |
|
Review (codex gpt-6.1-sol high fast, router-review): SHIP at f338b2b The head is a lander base merge (update-branch) of 103e799, taken to pick up base fixes (#29007 xcstrings, current guards). No blocking finding in the PR's own diff. Follow-ups:
|
|
Review (codex gpt-6.1-sol high fast, router-review): SHIP at 78940de The head is a cmux-bot base merge of f338b2b. No blocking finding in the PR's own diff. Follow-ups:
|
|
Review (codex gpt-6.1-sol high fast, router-review): SHIP at 255ca75 This head is the lander's update-branch for stale guards. The full diff was reviewed.
|
… row key) (#29486) The feat tip does not compile its tests (merge-batch compile job adbfd4f046d9e75e9635af65 at 644491f): - ForgetRemovesBothListsTests.swift:18: cannot find 'MainWorkScheduler' / 'MainFrameBudget' in scope. The file came with 4a46cfa (#28799) without `import CmuxNextWakeups`, where both types are public. - SidebarStatusGroupingTests.swift:58: type 'SidebarRowKey' has no member 'tab'. 46cf844 (#28563) added `if case .tab = row.key` after 8a3af6b had deleted the sidebar's tab-row keys; with no tab rows, the line has nothing to skip, so it goes.
…_lines) (#29478) #28799 (4a46cfa) added 75 CmuxNextApp Swift lines (SSHService.swift, AddDeviceServices+App.swift) with no exception entry; arch-ratchet's app_lines row refuses it alone (--base 4a46cfa^ --head 4a46cfa: +75), and the tip watcher's range 30806df..644491f is +75. - SSHPeerForgets (new, CmuxNextServer/AddDevice, next to DeviceDirectory) owns the removal of a written Forget's acpmux peer: the default `acp host ls`/`acp host rm` through the app's cmux-tui, the marks of Forgets whose Undo still shows, the pending Forget record (Pending, was SSHService.PendingForget) and the exact-route match (reaches, sameRoute). CmuxNextServer now depends on CmuxNextRemote (ui -> service). - SSHService keeps the calls: hide, unhide, commitForget (with its "Forget still holds and no other session reaches the route" check), forgetMachines(reachingPeer:) and the connect's mark clear. - Reconnect's decision table moves to CmuxNextRemote as SSHConnectionMachine.Status.reconnectStep(daemonConnected:daemonFailed:) (it read only `daemon == .connected`), so the move takes out more App lines than #28799 added. CmuxNextApp -79; the watcher's range is -4. No behavior change. ForgetRemovesBothListsTests read the same cases through the moved code, now also check that a written Forget takes the SSH machine out of the list as well as its peer, and test SSHPeerForgets on its own. RemoteConnectRecoveryTests read the moved reconnect step.
…xtLayout (app_lines) (#29514) The tip's arch-ratchet app_lines row is red over 30806df: three commits add CmuxNextApp lines with no exception entry, each refused alone by `arch-ratchet.py --base <c>^ --head <c>`: - 0703de4 (#28049, Move Space to This Window / Merge All Windows): +99 - 088b1bc (#27919, a link from another app never reshapes Chief's Home): +16 - 7a12ed3 (#27825, terminals stay quiet while a handoff adopts their shell): +12 (the last two came in through the direct-push merge 8dd8bdc; #28799's +75 is #29478's). Their own code is wired into WindowManager, ExternalOpenController and AppControl, so it cannot leave the App by itself. Instead, the App's pure window membership model moves out whole: WindowRegistry (struct, Window, Changes, every transition) and its repairedSelection extension go unchanged to CmuxNextLayout/Windows with `public` access; its persistence extension (WindowRegistry+Records) and the observable store stay in the App. WindowRegistry used only CoreGraphics and Foundation (and Design's FocusAfterClose, which CmuxNextLayout already depends on). App and test files that name the type import CmuxNextLayout. CmuxNextApp -426 against the tip; the watcher's range from 30806df is app_lines -226 with this alone. No behavior change.
Base moved the reconnect step to SSHConnectionMachine.Status.reconnectStep (#28799); this lane's SSHReconnectStep goes, and .restart with retriesSpent (HQ #4877 G4) joins base's API. SSHMachineSession.waitsForUser reads the link's gate directly, not only once the mirrored status reads .failed (review P1 follow-up at c11edce: the status reaches the session asynchronously). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?id=aid-4bbc87e99e6352cca67a
![Fix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/fix-with-codesmith-light-3x.png)
Fixes break 8 of HQ #4877 (manaflow-ai/cmuxterm-hq#4877), the walkthrough of remote machines in NEXT. Leo asked there: "how is our setup flow anyways? like cmux-next remote and whatnot".
Design
When you add a computer with Add Device, it lands in two lists: the sidebar's SSH machine, and the acpmux peer that enroll adds at the same
ssh://[user@]host.remote.forget):SSHService.commitForgetnow also runsacp host rmfor the peer at the machine's route. That write happens only when the Undo toast ends, so Undo needs no change: the peer is never removed while Undo is still possible. The peer is kept if another of the app's SSH sessions still uses the same route, for example a second named session on that host. When automation forgets a machine, the write happens right away, so the peer goes then too.peer:NAMErow:DeviceDirectory.removefirst reads that peer's ssh route fromacp host ls --json. Ifdevice removesucceeds, the SSH machines at that route are also forgotten, written at once (Remove for Good was already confirmed). A failed remove forgets nothing.ssh://are never touched.removal.rscannot see the app's SSH machines, andDeviceDirectoryalready runs the bundled cmux-tui.HostCandidate.sshTarget(peerURL:)is the existingssh://reader, pulled out as a static function so both places can use it.plans/cmux-next/add-device-DESIGN.md§2.5 records the rule.Risk
Medium-low. Removal is destructive, so it only acts on an exact route match. Peer removal runs only after a Forget has been written, and SSH-machine removal runs only after a confirmed Remove succeeded. The
acp host rmcall is best effort: if it fails, the peer stays, which is how things worked before this change. There are no new strings and no visible UI change.Tests
Tests/CmuxNextAppTests/ForgetRemovesBothListsTests.swift:acp host lsparsing (ssh peers only, daemon port dropped);removePeersremoves only the matching peer.No capture: there is no visible UI change (no new strings or controls). The only difference is that a machine now leaves both lists.
Agent session: agent session
🤖 Generated with Claude Code