Check "exited" against the process record before believing it

A session adopted at a backend start keeps the transcript's last status,
so one whose process had been reported gone and was then found again
read as `exited` while its CLI was running. `exited` is the word that
draws the phone's Start button and lets `start_session` build a driver,
so Start was accepted every time it was pressed -- and since starting
replaces the driver without retiring the old one, each press left
another reader on the same process. Every line the CLI wrote was then
translated once per reader: three presses put three interleaved copies
of one reply on screen, which is what it was reported as.

So `exited` is now checked against `session::process`, the one authority
on whether a process exists, in `launch` and again in `start_session`. A
record that is not known to be dead makes it false, and what replaces it
is `unknown` -- there is a process, and nothing here has heard from it,
which is the answer `status_of_unlaunched` already gave to the same
question. The correction goes out through the sink rather than into the
manager's view alone, or the list and the session screen would disagree
about it in the way this same button did a commit ago.

A driver that `start_session` replaces now gets `Driver::detach`, which
already existed for the backend going away and is the whole of what a
driver whose process has exited is owed.

On the phone the process button is disabled while its own request is in
flight, so a second press cannot be decided against a status the first
has not changed yet. That is a courtesy rather than the fix; the server
refuses it either way, because a phone that has lost the stream cannot
be relied on to know.

Verified against a stand-in CLI, with the state forced by hand: before,
three Starts returned 204 and left four readers on one process and the
status still `exited`; after, the session reports `unknown` on both
surfaces and all three are refused. Then driven on the emulator --
Stop, Start, Stop, Start alternated correctly with one process at a
time, and the list, the transcript and the record all agree.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
irisandClaude Opus 5 committed 2026-08-30 13:40:54 -04:00
1 parent 558095520d
commit 50f9b956d9
4 files changed
+210 -10

No files matched your search

+11
View File
@@ -302,6 +302,17 @@ day:
launch has just started a process reports `idle`, because `exited` is the
word that refuses every command and offers a phone the chance to start a
second CLI on a live conversation.
- **`exited` is never taken on trust; it is checked against the process
record** (`corrected` in `session/mod.rs`). It is the one status that draws
the phone's Start button and lets `start_session` build a driver, so a
record that is not known to be dead makes it false and the session reports
`unknown` instead. Without that, a session adopted at a backend start kept
the transcript's `exited` while its CLI was running, Start was accepted
every press, and each press left another reader on the same process —
which reads on screen as one reply written several times, interleaved
(`GotGotGot it — it — it —`), not as anything to do with a button.
A driver that `start_session` replaces gets `Driver::detach` for the same
reason: swapping the `Arc` does not end the tasks the old one is running.
- Remote sessions are adopted too. The pid recorded for one is the **`ssh`
client's**, on this machine — that is the process the backend owns, and it
lives as long as the remote command does. (This said "local only" until