mirror of
https://github.com/stablyai/orca.git
synced 2026-10-23 16:03:49 +00:00
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.