= test-projections

== purpose

Unit tests for the event-sourced projection and reducer components. Verifies that each projector correctly rebuilds state from a sequence of events, and that reducers produce the correct state transitions for each event type.

== responsibilities

* Test `DefaultSessionReducer` and `SessionProjector` — session lifecycle state transitions
* Test `DefaultOrchestrationReducer` and `OrchestrationProjector` — orchestration state transitions
* Test `InferenceReducer` and `InferenceProjector` — inference state tracking
* Test `DefaultContextReducer` and `ContextProjector` — context state tracking
* Test `ArtifactReducer` — artifact metadata state tracking
* Test `RouterReducer` and `RouterProjector` — router state tracking

== non-responsibilities

* Does not test live event streaming or real-time event processing
* Does not test the event store write path
* Does not test the `SessionOrchestrator` or higher-level orchestration logic
* Does not test application layers

== key types

=== DefaultSessionReducerTest
* **kind**: JUnit 5 test class
* **purpose**: Tests `DefaultSessionReducer` with session lifecycle events (start, pause, resume, fail, complete). Verifies status transitions and state field updates.

=== SessionProjectorTest
* **kind**: JUnit 5 test class
* **purpose**: Tests `SessionProjector` by feeding sequences of events through the projector and verifying the final `SessionState`.

=== OrchestrationReducerTest
* **kind**: JUnit 5 test class
* **purpose**: Tests `DefaultOrchestrationReducer` with orchestration events (stage transitions, approvals, retries). Verifies state machine transitions.

=== OrchestrationProjectorTest
* **kind**: JUnit 5 test class
* **purpose**: Tests `OrchestrationProjector` by replaying orchestration event sequences and validating the final `OrchestrationState`.

=== InferenceReducerTest / InferenceProjectorTest
* **kind**: JUnit 5 test classes
* **purpose**: Tests inference event reduction and projection — request lifecycle, completion, timeout, and failure.

=== ContextReducerTest / ContextProjectorTest
* **kind**: JUnit 5 test classes
* **purpose**: Tests context pack building and compression through the projection pipeline.

=== RouterReducerTest / RouterProjectorTest
* **kind**: JUnit 5 test classes
* **purpose**: Tests router state projection — tracks router interaction history and state.

=== ArtifactReducerTest
* **kind**: JUnit 5 test class
* **purpose**: Tests artifact metadata reduction from tool execution events.

== event flow

*inbound:* Constructed `StoredEvent` sequences representing the full lifecycle of a session or subsystem.

*outbound:* Assertions on the final projected `*State` object, comparing field-by-field against expected values.

== integration points

* `:core:sessions` — `DefaultSessionReducer`, `SessionProjector`, `SessionState`
* `:core:kernel` — `DefaultOrchestrationReducer`, `OrchestrationProjector`, `OrchestrationState`
* `:core:inference` — `InferenceReducer`, `InferenceProjector`, `InferenceState`
* `:core:context` — `DefaultContextReducer`, `ContextProjector`, context state types
* `:core:artifacts` — `ArtifactReducer`
* `:core:router` — `RouterReducer`, `RouterProjector`
* `:core:events` — `StoredEvent`, all event payload types
* `:testing:fixtures` — `EventFixtures`

== invariants

* Each projector produces the same final state given the same event sequence, regardless of intermediate projections
* Reducers only modify state via `state.copy(...)` — no side effects
* Unknown event types in a reducer return the state unchanged

== PlantUML diagram

[plantuml, test-projections, "png"]
----
include::../../diagrams/test-projections.puml[]
----




== known issues

* Tests may not cover all edge cases (empty event lists, out-of-order events, duplicate events)
* Event sequences are constructed manually and may not reflect real-world ordering guarantees from the event store

== open questions

* Should projection tests verify behavior with interleaved events from multiple sessions?
* Should there be property-based tests (e.g., `kotlinx.kotest.properties`) verifying the projector invariants across random event sequences?
