State machine
| From | Transition | To |
|---|---|---|
| Pending | Launch | Launching |
| Launching | Started | Running |
| Launching or Running | StopRequested | Stopping |
| Any non-terminal state | End | Ended |
Invalid transitions leave state unchanged and return LifecycleError. Ended is terminal. A session rejects a second non-terminal run.
RunEnd distinguishes Completed, Exited, LimitReached, Failed, Cancelled, and Terminated. A zero exit code alone does not establish semantic completion.
Outcome precedence
RunOutcome observes normalized events and finalizes using the process result. Supervisor failure outranks forced termination, and forced termination outranks a graceful user stop. A user stop outranks provider signals.
For a natural exit, pending turn signals can determine the result. Semantic end-of-turn followed by a successful exit becomes Completed; otherwise a plain exit remains Exited. Protocol violations are recorded but never decide a terminal outcome by themselves.
Shutdown
The runtime executes ordered shutdown steps with a grace interval. An unsupported or failed step records a diagnostic and can try its defined fallback once. Interrupt falls back to CloseInput.
Exit within the grace period ends as Cancelled. Force termination ends as Terminated, and classification warns that native state may not have been saved.
Direct child and descendants
The direct child’s reap is the finalization trigger. Process-tree cleanup and output drain stay bounded even when descendants hold streams open. The transport delivers exactly one final exit frame, and finalization diagnostics never start a second cleanup loop.
Persistence
Every transition and event is appended to the session journal as it happens. After a crash, replay rebuilds the session and marks a run that never ended as failed. See Sessions & resume.