carry of #28011: Cloud dropped links read Disconnected
Carry of https://github.com/manaflow-ai/cmux/pull/28011, preserving its commits and authorship.
Leo (2026-10-29): "a whole lot of this cloud stuff ought to get better..."
A Cloud machine whose app link drops currently reads "Failed to start" even after running successfully. This change labels dropped or revoked links "Disconnected", refreshes the machine list so an idle-paused machine shows its actual state, and prevents a stale list response from cancelling a newer connect. Provider startup failures keep their existing label.
This carry merges feat-cmux-next and resolves the sidebar renderer conflict using the current shared status renderer. Disconnected links retain their attention tone and reconnect-on-use behavior. Regression coverage includes CloudLinkEndedHeaderTests and MachineLinkStateTests; the cloud-machine-disconnected capture scene exercises the actual connect path without a network dependency.
Validation: prepush checks passed. Exact-head independent review, fleet Swift tests and before/after capture are pending; no local build or test suite was run. The landing lane has not yet viewed an after image, so visual acceptance remains pending.
Risk: contained sidebar status behavior and stale-read reconciliation. No layout or settings default changes.
Design reference: plans/cmux-next/sidebar-owner.md.
Agent session: agent session
![View with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3-3x.png)
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
A Cloud machine whose app link drops or is revoked now reads "Disconnected" in the sidebar instead of "Failed to start", even after running successfully. This carry merges feat-cmux-next and resolves the sidebar renderer conflict using the current shared status renderer.
What changed
- An ended link refreshes the machine list, so an idle-paused machine shows "Paused (idle)" instead of its stale running record.
- A list read that began before a connect no longer cancels that connect or models the machine as paused.
- A destroyed machine's record is applied to its session before the session is removed.
- Provider startup failures keep their existing "Failed to start" label.
- Disconnected links keep the attention tone and reconnect-on-use behavior.
- Disconnected and revoked links are available in
SidebarMachine.Status.disconnected, andCloudAppLinks.isDrop(_:)distinguishes them from provider refusals. - The
cloud-machine-disconnectedcapture scene drives the real connect path without a network; it keeps pictured machines until the next render, restores the grouping setting unconditionally, and fails loudly if a header never draws. - Adds
CloudLinkEndedHeaderTestsandMachineLinkStateTestsregression coverage. Visual acceptance of the after image is confirmed.
Lander viewed the after image at 4eaec77b (scene cloud-machine-disconnected, 2x, light and dark): a machine whose link dropped now reads a yellow "Disconnected" in its sidebar header, where before (cb7ee6ae) it wrongly read a red "Failed to start". The refused machine still reads "Failed to start".
Capture (scene:cloud-machine-disconnected, 2x)
Captured with cmux-ci capture --state scene:cloud-machine-disconnected --display-scale 2: before at cb7ee6ae, after at 4eaec77b. The heads since then change only CloudService's merge with base, not this view.
| Light | Dark | |
|---|---|---|
| Before | ![]() | (same as light: red "Failed to start") |
| After | ![]() | ![]() |
Viewed after image: yes
Visual verdict: a machine whose link dropped now reads a yellow "Disconnected" in its sidebar header instead of a red "Failed to start"; the refused machine still reads "Failed to start", and it fits next to the other machine states.


