fix(cmux-tui): a new owner never ends a shell the holder still runs (an adopting row re-attaches, a failed re-attach keeps the shell, only ended rows are closed) (QUIT P0)
Merged
LA
6d ago+226+226+012345678901234567890123456789-17-17-01234567890123456789
What
QUIT P0 (Lawrence 2026-11-01: "after quitting and reopening, i lose all the workspaces and terminals"). In holder mode (cmux-tui __holder, on every channel), a new owner's startup pass ended the person's shell in two cases:
- A terminal whose registry row was not exactly
running(a previous owner that stopped mid-adoption: a version handoff at the app's reopen, a crash) was recorded ended (adopt_from_holder_or_end), and then release_unclaimed_holder_terminalssent CLOSE (2 s hang-up) to EVERY holder terminal no surface re-attached, a terminal with no registry row too. A failed re-attach ended the shell the same way.
Now:
- A row left
adoptingre-attaches like a running one. - A re-attach that fails while the holder lists the terminal and its row is still running or adopting keeps the row and the shell (adopt_on_holder's failure paths now detach the shell instead of closing it), and the tab shows adopting (
PendingTerminal::Adopting), not a live terminal that takes no input. The next start re-attaches it (the failed attach already took the holder's listed entry, so this process cannot retry it). - After the pass the holder ends only terminals whose row exited or was tombstoned (the shell exited, or the person closed the tab). A terminal with no registry row stays held, on purpose: a registry that comes back thin (the P0 itself) reads "no row" for every terminal with no read error, so "absent = ended" would close every shell in exactly the failure this fixes. A visible "Running in background" list (pty-holder.md section 5) is a follow-up.
Tests (red first, fleet cargo on macOS, scripts/ci/cmux-tui-rust-check.sh test <filter>)
holder_terminals a_restart_reattaches_a_holder_terminal_whose_row_was_left_adopting(2 holdercatterminals, SIGKILL the daemon, set one rowadopting, restart: both shells kept by pid, screens kept, input works).- First branch fix/p0-quit-reopen-holder: red 3e9146edeef, step 6dfde043d7436ab48f80fb89 (aws-m4pro-2): FAILED at holder_terminals.rs:175, the terminal came back as "— session restored (previous process ended; it ran /bin/cat) —" with a NEW shell: the base ends the person's shell. Green 6c746e5cffd, step 7e88d4e215446ab8f43257dc (aws-m4pro-4): 1 test run, 1 passed.
holder_terminals a_restart_closes_only_holder_terminals_whose_row_ended(a tombstoned row's shell is closed; a terminal with no registry row keeps its shell).- This branch: red 48fac40093d step b54edea31a2b8a815cab67d5 (aws-m4pro-2): the adopting test FAILED at holder_terminals.rs:175 as on the first branch (a second test there failed at its own set-up, a foreign-key refusal of a row DELETE; that test was replaced). Head cc4b006e88e (after the review FIX): step 7d7f0cd255c5c7ad5dcd5579 (aws-m4pro-9, macOS, filter a_restart_):
a_restart_reattaches_a_holder_terminal_whose_row_was_left_adoptingPASS,a_restart_closes_a_holder_terminal_whose_row_was_tombstoned_and_keeps_the_restPASS, all holder_terminals PASS; one acpmux test (durable_agents restart_reattach) failed once and passed on its rerun, not in this diff. Compile-check of cc4b006e88e: 1e94d277757362b79298f099 passed (CmuxNext, app, cmux-tui). - Clippy step 6298c55e7fe041d7e44d0356 stopped on a BASE red: acpmux/src/hub/processes.rs:256 redundant closure (feat base autofix 704abda602b), fixed on feat by #30009 (55361f16bf0). Clippy for this PR's crates: step 2ab060fade549d7c4c993c40 (aws-m4pro-6) on scratch ref ffe8515e4c3 (this head merged with feat, which has #30009; never merged): clippy -D warnings PASS (
cmux-tui-rust-check summary (mode clippy): clippy pass). - Not covered by a test: the failed re-attach branch (no seam to inject an attach error without a test-only hook).
Risk
risk:high (lead 01:2xZ): this decides whether a person's running shell ends at a daemon start. Kept shells are user data. Needs an independent review receipt at the exact head and a green compile of the head.
Owners
PL-daemon holder (plans/cmux-next/pty-holder.md): told in STATUS. DAEMON SKEW owner (a619d54a5cbae4d7d) read the diff: no conflict with its host-mode design.
Changelog
- Fixed: a reopen after an update or a daemon restart no longer ends terminals whose re-attach was interrupted or failed.
Observed / Not run
- Observed: red and green of the first test above (fleet logs); prepush gate (no new violations); rustfmt --check.
- Not run yet: a journey on a build with this fix.
Open follow-ups (DAEMON SKEW design review)
- A Retry for a tab held as adopting (needs a fresh holder list); a UI and End path for no-row held shells; a seam to test the failed re-attach branch; a future holder ADOPT handoff must never end a held shell.