Fix startup wedge when several terminal hosts are unadoptable
A session that restarts with two or more unadoptable terminal hosts behind the same pane never opens again. cmux exits with cmux-tui: pane references missing surface <slot> and writes nothing, so every later start repeats it. Reported from uvx cmux 0.10.0 against a real session; reproduced deterministically against a copy of that session state.
Cause: ordered_terminal_tab_ids required a live surface for every pane tab, while the projection loop directly below it already accepted a restored tab with no surface yet (that fallback landed with the multiview work in #9387). Startup restores tabs before adoption, so an unadoptable host leaves a tab with no surface. The abort happened inside persist_terminal_exit, which builds the exit-detach projection before it commits, so the commit that was supposed to prune that terminal was the one that failed. One orphan host still recovered, because removing it made the tree consistent. Two behind one pane wedged the session permanently.
Both call sites now resolve tab identity through one helper: live surface first, durable indexes as the authority.
Also reorders the two startup paths that prove a host dead so the durable exit commits before the host record is deleted. The record is the only evidence that the host existed, and the old order erased it whenever the commit failed. That is why the reported session ended with no host records and two rows still in adopting.
Regression test in the first commit, fix in the second, so CI shows red then green. daemon_restart_prunes_every_dead_host_behind_one_pane kills two hosts behind one pane while the daemon is stopped, restarts, and requires both terminals to reach exited with the pane pruned.
Deliberately not in this PR: making startup non-fatal (quarantine unprojectable state instead of refusing to start). That would hide real corruption, and it deserves its own change.
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.
Summary by cubic
Prevents a startup wedge when multiple unadoptable terminal hosts share a pane. Previously startup aborted with “pane references missing surface ” during the first exit–detach commit and the session never opened; now restored tabs use durable indexes when no live surface exists, so startup prunes all dead hosts and completes.
- Resolve tab identity via a single helper that prefers the live surface and falls back to durable tab/content indexes; used in both
ordered_terminal_tab_idsand the projection loop. - On startup, commit the durable exit before deleting the host record in both dead-host paths to preserve evidence for a retry if the commit fails.
- Adds regression test
daemon_restart_prunes_every_dead_host_behind_one_pane.
Summary by CodeRabbit
-
Bug Fixes
- Improved recovery of exited terminals after a daemon restart.
- Preserved tab identity for restored terminals when their live surfaces are unavailable.
- Prevented stale terminal records from being removed before exit state is safely saved.
-
Tests
- Added coverage for recovering multiple dead terminal hosts in the same pane without recreating unwanted tabs.