= core-sessions == purpose Defines the session lifecycle model: session creation, status transitions (created → active → paused/completed/failed), and the projection infrastructure for rebuilding session state from events. Sessions are the top-level unit of work in Correx — a single workflow execution that produces artifacts and consumes LLM inference. == responsibilities * Defines `SessionState` (status, timestamps, invalid transition count) and `SessionStatus` enum (CREATED, ACTIVE, PAUSED, COMPLETED, FAILED) * Implements `SessionReducer` (interface) and `DefaultSessionReducer` (concrete) — translates session and stage lifecycle events into `SessionState` changes * Provides `SessionProjector` — adapts `SessionReducer` into the `Projection` interface for use with the replay infrastructure * Provides `DefaultSessionRepository` — rebuilds `Session` (sessionId + state) from events via `EventReplayer` * Provides `SessionCounterProjection` / `SessionCounterState` — a simple projection that counts events per session * Defines `TransitionResult` sealed interface — models whether a status transition was applied or rejected * Defines `ApprovalMode` enum (DENY, PROMPT, AUTO, YOLO) — the approval policy mode for a session == non-responsibilities * Does not produce events — all events are emitted by the kernel (`core:kernel`) * Does not manage workflow graphs, transitions, or stage execution * Does not interact with inference, tools, or context * Does not enforce session lifecycle invariants — it only computes derived state from events * Does not handle session persistence or storage == key types === SessionStatus * **kind**: enum * **purpose**: lifecycle status of a session * **variants**: CREATED, ACTIVE, PAUSED, COMPLETED, FAILED === SessionState * **kind**: data class * **purpose**: derived projection state for a session * **fields**: status (SessionStatus), createdAt (Instant?), updatedAt (Instant?), invalidTransitions (Int) === Session * **kind**: data class * **purpose**: aggregate holding a sessionId and its current derived state === SessionReducer * **kind**: interface * **purpose**: reduces a `StoredEvent` into a `SessionState` transition === DefaultSessionReducer * **kind**: class * **purpose**: concrete reducer — maps `SessionStartedEvent` → ACTIVE, `SessionPausedEvent` → PAUSED, `SessionCompletedEvent` → COMPLETED, `SessionFailedEvent`/`StageFailedEvent` → FAILED, stage progress events → ACTIVE === SessionProjector * **kind**: class * **purpose**: wraps `SessionReducer` as a `Projection` with initial state = CREATED === DefaultSessionRepository * **kind**: class * **purpose**: wraps `EventReplayer` to provide `getSession(sessionId)` and `rebuild(sessionId)` returning a `Session` === TransitionResult * **kind**: sealed interface * **purpose**: result of attempting a session status transition * **variants**: Applied(newState), Rejected === ApprovalMode * **kind**: enum * **purpose**: approval policy mode for a session * **variants**: DENY (block all), PROMPT (ask user), AUTO (auto-approve), YOLO (skip approval entirely) === SessionCounterProjection / SessionCounterState * **kind**: class / data class * **purpose**: trivial projection counting events per session. Likely a diagnostic or testing utility. == event flow *inbound (consumed by reducer):* * `SessionStartedEvent` → status becomes ACTIVE, createdAt recorded * `SessionPausedEvent` → status becomes PAUSED * `SessionResumedEvent` → status becomes ACTIVE * `SessionCompletedEvent` → status becomes COMPLETED * `SessionFailedEvent` → status becomes FAILED * `StageStartedEvent` → status becomes ACTIVE * `StageCompletedEvent` → status becomes ACTIVE * `StageFailedEvent` → status becomes FAILED * `TransitionExecutedEvent` → status becomes ACTIVE *outbound:* This module does not emit events. All events are emitted by `core:kernel`. == integration points * `:core:events` — `StoredEvent`, `Projection`, `EventReplayer`, `DefaultStateBuilder`, session event types (`SessionStartedEvent`, etc.), stage event types (`StageStartedEvent`, `StageCompletedEvent`, `StageFailedEvent`, `TransitionExecutedEvent`), identity types * `:core:kernel` — uses `DefaultSessionRepository`, `Session` == invariants * `SessionState` is always derived from events via replay. It is never persisted or mutated directly. * `createdAt` is set once from the first event's timestamp and never changes. * `invalidTransitions` field exists in `SessionState` but is never incremented by `DefaultSessionReducer` — it is always 0. * `SessionFailedEvent` and `StageFailedEvent` both map to FAILED status — there is no distinction in the session state between session-level and stage-level failure. == PlantUML diagram [plantuml, core-sessions, "png"] ---- include::../../diagrams/core-sessions.puml[] ---- == known issues * `SessionState.invalidTransitions` is declared but never written by `DefaultSessionReducer`. It is always 0. Either it is a placeholder for future use or dead code. * `TransitionResult` is defined but unused within the module — no callers in the current codebase reference it. == open questions * None.