fix(sessions): keep a session's model through recovery, refuse it off claude

SessionState now carries the model a session launched with, and both
recovery constructors (mux recovery and reboot restore) pass it back, so a
recovered session relaunches on the same --model rather than the account
default. A top-level `model` sent with any other CLI is refused, since
those take their model in their own config object, and an empty string
means no per-session model, as it does for modelOverride.

CLAUDE.md now describes both routes for a Claude model. The tests pin
which of `model` and `modelOverride` reaches the launch and which the
case file, and that a model opening with a dash renders as --model's value.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Michael Grundberg
2026-10-01 17:24:12 +02:00
co-authored by Claude Opus 5.5
parent 4123d229f4
commit 3df113fc54
12 changed files with 136 additions and 12 deletions
@@ -388,14 +388,14 @@ a directory that is not a case (body takes `workingDir`, `mode`, `name`, `effort
differences that break copied code:
- The id is at **`.data.session.id`**, not quick-start's `.data.sessionId`
(`session-routes.ts:878` returns `{ session: lightState }`).
(the `POST /api/sessions` handler in `session-routes.ts` returns `{ session: lightState }`).
- **It spawns no PTY.** The session exists with `pid:null` and nothing running, so
`wait?until=exit` answers `exit` immediately. Follow it with
`POST /api/v1/sessions/:id/interactive` (claude and the other agent CLIs) or
`POST /api/v1/sessions/:id/shell` (shell mode) to actually start the worker.
- Its capacity failure is **`OPERATION_FAILED` (422)**, not quick-start's
`SESSION_BUSY` (409), from the same global-50 / per-user-25 caps
(`session-routes.ts:648`).
(`sessionCapacityMessage()` in `route-helpers.ts`).
⚠️ `POST .../interactive` accepts `{"clearBreaker":true}`, which resets the **PTY-exit
circuit breaker**. That breaker exists to stop a session that keeps crashing on spawn