carry of #28011: Cloud dropped links read Disconnected

TE
7d ago
+599-20

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 Autofix with [code]smith
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, and CloudAppLinks.isDrop(_:) distinguishes them from provider refusals.
  • The cloud-machine-disconnected capture 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 CloudLinkEndedHeaderTests and MachineLinkStateTests regression 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.

LightDark
Beforebefore light(same as light: red "Failed to start")
Afterafter lightafter dark

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.