Expand description
Background polling loop that keeps Session state in sync with reality.
Corresponds to packages/core/src/lifecycle-manager.ts in the reference
repo, trimmed to what Slice 1 Phase C actually needs:
- Every
poll_interval, list all non-terminal sessions from disk. - For each one, probe
Runtime::is_aliveandAgent::detect_activity. - Apply state transitions and persist the new
Sessionatomically. - Broadcast
OrchestratorEvents so subscribers (CLI, reaction engine, notifiers, …) can react without polling themselves.
Design notes:
-
Trait objects, not generics. The manager owns
Arc<dyn Runtime>etc. so the sameLifecycleManagertype can be used in tests (with mocks) and in the real CLI (with tmux/claude-code). Generic parameters would have leaked through every consumer. -
Disk is the source of truth. The loop re-reads from
SessionManager::listeach tick rather than holding state in memory. This matches the Slice 1 design principle established in Phase A, and meansao-rs spawnrunning in a separate process is immediately visible on the next tick. (A future Slice 2+ may add an in-memory cache + file-watcher for efficiency.) -
Per-session errors don’t stop the loop. If one session’s runtime probe fails, we emit
TickErrorand continue. Only fatalSessionManager::listerrors bubble up (and even then we log and keep looping). -
Event channel lag. We use
tokio::sync::broadcast, which drops old events when a slow subscriber can’t keep up. That’s fine for observability — a reaction engine that misses a tick just picks up the next one. Anyone needing lossless delivery should snapshot viaSessionManager::liston startup and then subscribe.
Structs§
- Lifecycle
Handle - Handle returned by
LifecycleManager::spawn. Dropping it does not stop the loop — the caller must.stop().awaitexplicitly, so a CLI handler that accidentally drops the handle doesn’t silently kill the background worker. - Lifecycle
Manager
Constants§
- DEFAULT_
POLL_ INTERVAL - Default poll interval. Increased from the TS reference’s 5 s to 10 s to further reduce GitHub API pressure now that batch enrichment + ETag guards handle the hot path.