fix(cloud): retry restored port panes after machine refresh
Merged
AU
10d ago+298+298+012345678901234567890123456789-19-19-01234567890123456789
Summary
After relaunch, a Cloud browser pane on a forwarded VM port (e.g. http://10.107.80.1:3400/) stayed on "Cloud session unavailable" and the sidebar showed Ports 0, even though the server was running.
Root cause: the restored pane is staged in pendingRestoredProjections until a port scan publishes its port:N resource, but CloudPortDiscovery.mayScan only allowed scans after an explicit Ports request. Every post-restart scan logged cloud.portScan.begin requested=false and returned nothing, so the staged pane never resolved.
- A live or staged forwarded-port pane is now standing scan demand (
hasProjectedPortPanes), so the first scan after the link connects publishes the port and the staged pane configures itself. - Restored panes show "Reconnecting to Cloud…" until the route configures. They drop to the Reload card only when a settled scan misses the port (
settleRestoredPortPanes) or a 30 s deadline (injected clock) passes. Reload returns to the reconnecting state immediately. - Providers rehydrated for restored machines keep the saved private address when the status read omits one.
- Removed a synthetic port upsert that only covered live projections and never ran for staged ones.
Validation
- Tagged build
pr-17232-cloud-restore-retry-v25, relaunched with the reporter's saved layout:cloud.portScan.result ports=3400thencloud.desktop.proxy.ready port=3400, and the restored pane rendered the page. - New
CloudDesktopAccessTestscases cover the restore deadline, settled miss, Reload flip, and deadline cancellation on configure (CI run https://github.com/manaflow-ai/cmux/actions/runs/37298537520). verify-local.py --only swift-syntax --swift-changed,git diff --check.
— unregistered
🤖 Generated with Claude Code