# task-010

status: done

## goal
Implement RouterProjector as Projection<RouterState> backed by DefaultRouterReducer, providing initial() and apply() methods per the core architecture pattern.

## target artifact
core/router/src/main/kotlin/com/correx/core/router/RouterProjector.kt

## execution steps
- Modify RouterState.kt: change `sessionId: SessionId` to `sessionId: SessionId? = null` (prerequisite — Projection.initial() requires no-arg construction; RouterState previously had a required non-nullable SessionId field that prevented this)
- Create RouterProjector.kt implementing `Projection<RouterState>`
- Inject `RouterReducer` via constructor with `DefaultRouterReducer` default (matching the pattern used by other projectors: ArtifactProjector, ToolProjector, ApprovalProjector)
- Implement `initial()` → `RouterState()` (all fields default to empty/null)
- Implement `apply(state, event)` → delegate to `reducer.reduce(state, event)`
- Write unit tests in `testing/projections` module covering initial state, all event types, determinism, full lifecycle, and unknown event types

## changed artifacts
- `core/router/src/main/kotlin/com/correx/core/router/model/RouterState.kt` — sessionId made nullable with default null
- `core/router/src/main/kotlin/com/correx/core/router/RouterProjector.kt` — new file
- `testing/projections/build.gradle` — added `:core:router` test dependency
- `testing/projections/src/test/kotlin/RouterProjectorTest.kt` — new file (12 tests)

## blockers
- RouterState.sessionId is currently non-nullable `SessionId` with no default, but Projection.initial() has no parameters to supply it. Resolved by making sessionId nullable with default null. All existing code only reads sessionId from events, not from RouterState, so this change is backward-compatible.

## notes
- This task depends on task-009 (RouterReducer) which is already done.
- 12 unit tests written, all passing, covering: initial state, WorkflowStartedEvent, WorkflowCompletedEvent, WorkflowFailedEvent, OrchestrationPausedEvent, OrchestrationResumedEvent, StageCompletedEvent, StageFailedEvent, SteeringNoteAddedEvent, determinism, full lifecycle, and unknown event type.
