5.3 KiB
Epic 2 — Session Lifecycle (FSM + Projection Layer)
completed deliverables
1. session state model (projection output)
implemented a deterministic session state representation derived entirely from event streams.
final structure:
SessionState(pure projection output)SessionStatusSessionEvent(FSM input domain)
key characteristics:
- immutable
- replay-safe
- derived only from events
- no identity leakage
session identity explicitly removed from projection state.
2. session identity boundary separation
introduced explicit separation between identity and state.
final model:
Session→ identity wrapperSessionState→ projection result
structure:
Session(sessionId)
↓
SessionState
this removed previous anti-pattern:
- embedding sessionId inside projection state
- late-binding identity during replay fold
3. session FSM (deterministic lifecycle rules)
implemented deterministic finite state machine governing session lifecycle transitions.
states:
CREATEDACTIVEPAUSEDCOMPLETEDFAILEDREPLAYED(diagnostic)
properties:
- deterministic transitions
- no side effects
- replay-safe behavior
- strictly event-driven evaluation
FSM is pure function:
(SessionStatus, SessionEvent) → SessionStatus
4. session event interpretation layer
introduced mapping layer between persisted events and domain FSM events.
components:
SessionEventMapper
responsibilities:
- convert
StoredEvent → SessionEvent - isolate domain semantics from persistence format
properties:
- no state mutation
- no replay logic
- stateless transformation only
5. session projection engine
implemented SessionProjector as domain-specific projection over generic replay infrastructure.
responsibilities:
- consumes ordered event stream
- applies FSM transitions
- produces deterministic session state
- tracks lifecycle metadata
properties:
- pure fold reducer
- stateless across executions
- deterministic replay behavior
state evolution:
StoredEvent → SessionEvent → FSM → SessionState
6. projection infrastructure alignment
aligned session model with generic replay engine (:core:events).
final integration:
Projection<S>reused as abstraction boundaryEventReplayer<S>drives deterministic reconstructionSessionProjectorplugs into generic replay system
no duplication of replay logic inside sessions.
7. session repository (identity boundary)
introduced repository as thin orchestration facade over replay engine.
final structure:
class DefaultSessionRepository(
private val replayer: EventReplayer<SessionState>
) {
fun getSession(sessionId: String): Session =
Session(
sessionId = sessionId,
state = replayer.rebuild(sessionId)
)
}
responsibilities:
- binds session identity to replay result
- no projection logic
- no FSM logic
- no event interpretation
8. replay integration
session lifecycle fully integrated into event-sourced replay pipeline.
final flow:
EventStore
↓
EventReplayer<SessionState>
↓
SessionProjector
↓
SessionState
↓
Session (identity wrapper)
system guarantees:
- full replay determinism
- identical event streams → identical session states
- ordering enforced by store layer
9. test coverage completed
implemented deterministic coverage across session lifecycle:
- session reconstruction from event stream
- FSM transition correctness
- invalid transition detection
- replay determinism guarantees
- empty stream handling
- multi-event lifecycle correctness
introduced fixtures:
stored()event builder for deterministic event creation
aligned contract tests:
- projection contract compliance
- replay contract validation
- event store contract enforcement
10. architectural cleanup (refactor milestone)
removed legacy session coupling patterns:
- sessionId inside
SessionState - implicit state hydration logic
- repository-level replay duplication
- ambiguous projection initialization patterns
removed or deprecated:
SessionCounterProjectionas state-embedded counter logic (moved toward event-derived metrics approach)- FSM leakage into repository layer
final architecture after Epic 2
EventStore
↓
EventReplayer<SessionState>
↓
SessionProjector
↓
SessionState
↓
Session (identity wrapper)
major architectural outcomes
Epic 2 established:
- strict separation between identity and state
- deterministic FSM-driven session lifecycle
- event-sourced state reconstruction model
- reusable generic replay engine (
:core:events) - domain-specific projection layer (
:core:sessions) - repository as pure boundary adapter
- fully replay-safe session lifecycle semantics
what Epic 2 intentionally does NOT include
not implemented:
- workflow graph execution
- transition DSL
- orchestration runtime
- stage execution engine
- scheduling or async coordination
- tool execution or kernel integration
those are explicitly deferred to Epic 3+
final state
Correx now has:
a deterministic, event-sourced session lifecycle system built on a generic replay engine, with strict separation between identity, state, and event interpretation, fully replay-safe and FSM-driven.