Files
orca/src
Brennan Benson 1b8301e6e3 feat(native-chat): give a structured session a surface-holder lifetime
Nothing told the host that a chat WANTED a session, and nothing told it when
one stopped. Both halves cost real processes: closing a chat left its codex
app-server running until the app quit (9 orphans, 420 MB, oldest 21 hours),
and every launch resumed a child for every record on disk — `released` with no
handoff in flight is the normal end state of a cleanly closed chat, so a
healthy profile respawned everything it had ever opened, in parallel, with no
client attached.

A surface takes a HOLD when it binds and drops it when it goes away: the
desktop chat view, the paired mobile session view. Holders are a SET, not a
count — every release path can fire twice or not at all, and an integer cannot
tell a duplicate release from a lost one. Transport close is the backstop, not
the mechanism: a phone that loses signal never sends its release, so the hold
registers a cleanup against its connection, and a live subscription holds the
session on its own.

Eviction runs the existing steps, unreordered, under a per-step deadline: a
step that times out aborts the rest, which leaves the session indexed and the
child LOADED rather than killed. The clock starts when the last holder leaves
and re-arms while a turn is running, so a session is never stopped mid-answer.
Teardown now also hands the lease back — a record left claiming a live owner is
one nothing can resume.

Startup no longer resumes anything. It reconciles, exits recovery, and restores
the journal for READING; a provider child exists because a surface asked for
the session. Paired builds that predate holds keep working: they do not
advertise `agent-session.structured.hold.v1`, and for them a subscription is
the resuming kind of hold.
2026-08-19 14:22:12 -07:00
..