A backend start adopts, and starts nothing

Restarting the server relaunched a driver for every session in the
config, and ClaudeDriver::launch starts a process when there is none to
adopt -- so a session somebody had deliberately stopped came back at the
next rebuild, and the Idle its new driver announced stamped the session
as active at that moment. On the phone that read as every session idle
and "just now" after every restart, with the list sorted by that time in
an order that meant nothing.

A launch now says why it is happening. Launching::Restart takes charge
of the processes still running and leaves every other session as it
found it; Launching::Asked -- a spawn, a Start, a message -- starts one
where there is none. A session with no process therefore has no driver:
DriverCell is an option rather than a driver whose requests go nowhere,
and LiveSession::ask reports what could not happen instead of sending
into a dead fifo.

Two clocks that moved on their own, both the same lie in the same field
that Transcript::last_activity exists to prevent:

- The status a launch has to correct is written into the transcript at
  the time of the last thing the session actually did. A backend killed
  mid-turn leaves a transcript saying Running, which has to become
  Exited -- but this server noticing is not the session doing something.
- A session that has never done anything reports when it was created. Its
  transcript is empty, since a driver announcing the state it starts in
  is not news, so it is the one session with no line to read a time off
  and the clock was the fallback.

Exercised end to end against a real server: a stand-in CLI adopted
across a restart keeps its status and its time, a stopped session stays
stopped with no process started, a process killed while the backend was
down reports exited stamped at the last thing the session did, and Start
brings it back.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
irisandClaude Opus 5 committed 2026-08-30 14:38:31 -04:00
1 parent 6119926a4d
commit 61af05c732
4 files changed
+461 -81

No files matched your search

+18
View File
@@ -305,6 +305,24 @@ day:
telling, so a failure there says the telling failed rather than the
rename. So the Start button is for when you want a process and nothing to
say to it yet.
- **A backend start adopts and starts nothing** (2026-08-30). It picks up
the processes still running and leaves every other session as it found
it: listed, with its transcript and its stream, reporting `exited`, with
no process and no driver until somebody asks for one. Restarting the
server used to relaunch a driver for every session, which started a CLI
for each one that had none — so a session stopped on purpose came back at
the next rebuild, and the `Idle` the new driver announced stamped every
row as active just now. If you are looking for a stopped session's
process after a restart, there is deliberately none; press Start, or send
it anything.
- **A launch never moves a session's clock.** A status it has to correct is
written at the time of the last thing the session actually did, not at
`now()`, and a session that has never done anything reports
`SessionConfig::created` rather than the clock — its transcript is empty,
since a driver announcing the state it starts in is not news, so there is
no line to read a time off. Both are the same rule as
`Transcript::last_activity`: a restart has been told nothing, so it must
not claim anything happened.
- **Each session directory now holds `process.json`, `stdin.fifo`,
`stdout.log` and `stderr.log`.** `stdout.log` is the driver's input, read
from the byte offset in `process.json`; removing either by hand while the