# review-001-007

## result
- approved

## findings

### Build dependency tasks (001-003)
- `infrastructure/build.gradle`: `implementation project(":core:router")` added correctly. Dependency ordering is clean — router is added before inference and approvals in the dependency block.
- `apps/server/build.gradle`: `implementation project(':core:router')` added correctly. Placed between inference and tools dependencies, which is a reasonable ordering.
- `core/router/build.gradle`: All four spec-required dependencies declared (`:core:events`, `:core:context`, `:core:inference`, `:core:sessions`). The task notes correctly observe that `:core:inference` transitively depends on `:core:events` and `:core:context`, but `implementation` deps do not propagate, so explicit declarations are necessary. No cross-core dependency violations detected — `:core:router` does not depend on any sibling core modules.

### Event definition task (004)
- `SteeringNoteAddedEvent` correctly defined in `ContextEvents.kt` with fields `sessionId: SessionId`, `content: String`, `stageId: StageId? = null` matching the task spec.
- `@Serializable` annotation added — this is a sensible addition for round-trip serialization and follows the pattern of other events in the file.
- Event is an `EventPayload` subclass, consistent with the existing pattern.

### Serialization registration task (005)
- Import added in alphabetical order among event imports (`SteeringNoteAddedEvent` after `SessionStartedEvent`).
- `subclass(SteeringNoteAddedEvent::class)` registered after `SessionFailedEvent` and before `StageStartedEvent` in the `eventModule` polymorphic block.
- All 8 pre-existing `:core:events` tests pass.
- Detekt passes on `:core:router` and `:core:context`; pre-existing `NewLineAtEndOfFile` warnings in `:core:events` are unrelated to this change (noted in task-005).

### RouterState model task (006)
- `RouterState` correctly defined as `@Serializable` data class with all spec-required fields: `sessionId`, `workflowStatus`, `currentStageId`, `l2Memory`, `conversationHistory`.
- Supporting enums correctly defined: `WorkflowStatus` (IDLE, RUNNING, PAUSED, COMPLETED, FAILED), `StageOutcomeKind` (SUCCESS, FAILURE, CANCELLED), `TurnRole` (USER, ROUTER).
- All fields use sensible empty defaults (`IDLE`, `null`, `emptyList()`).
- `RouterL2Entry` and `RouterTurn` defined with `Instant` timestamps (imported from `kotlinx.datetime`).
- `WorkflowStatus`, `StageOutcomeKind`, and `TurnRole` are locally defined in the router module (not imported from `:core:events`), keeping router types self-contained per task notes.
- No reducer logic implemented (per task non-goals).

### RouterConfig model task (007)
- `RouterConfig` correctly defined as `@Serializable` data class with `keepLast: Int = 10` and `tokenBudget: TokenBudget = TokenBudget(limit = 5000)` matching spec defaults.
- `TokenBudget` (pre-existing in `:core:context`) correctly annotated with `@Serializable` to enable its use as a field type in `RouterConfig`. The annotation is minimal and safe — `TokenBudget` only has `Int` properties.
- No unused imports in any new file.

### Compilation & static analysis
- All affected modules compile: `:infrastructure`, `:apps:server`, `:core:router`, `:core:events`, `:core:context` — BUILD SUCCESSFUL.
- Detekt passes on `:core:router` and `:core:context`; no new warnings introduced.
- All 8 `:core:events` tests pass.

## missing requirements

The following spec requirements are explicitly deferred to later tasks (per task non-goals) and are **not** missing — they are intentionally out of scope for tasks 001-007:
- `RouterReducer`, `RouterProjector`, `RouterRepository` (Tasks 009-011 in plan)
- `RouterContextBuilder` (Task 012 in plan)
- `RouterFacade` (Task 013 in plan)
- `ChatMode`, `ChatInput`, `RouterResponseMessage` protocol types (Tasks 014-015 in plan)
- WebSocket handler wiring (Task 016 in plan)
- `InfrastructureModule` wiring for `RouterFacade` (Task 018 in plan)
- Deterministic tests (Tasks 020-023 in plan)
- `SteeringNote` domain data class (deferred per task-004 notes)

No unplanned gaps detected in the implemented scope.

## edge cases

- **TokenBudget serialization tests**: No pre-existing serialization test exists for `TokenBudget` in `:core:events` tests or `testing/` submodules. The `@Serializable` annotation was added but not verified with an explicit round-trip test. This is low risk given `TokenBudget` has only `Int` properties, but a serialization test would be advisable before `TokenBudget` is used in more complex serializable types.
- **SteeringNoteAddedEvent serialization test**: The task notes correctly identify that no serialization round-trip test exists for `SteeringNoteAddedEvent`. The registration in `eventModule` prevents silent runtime deserialization failure (the primary safety concern), but an explicit round-trip test would provide higher confidence.
- **`NewLineAtEndOfFile` detekt warnings**: 15 files in `:core:events` have this warning. None are new (confirmed pre-existing per task-005). The `Serialization.kt` file that was modified is among them. This is a known cosmetic issue that does not affect correctness.
- **Dependency declaration completeness**: `:core:router` declares `:core:inference` and `:core:sessions` as dependencies, but the current source files (`RouterState.kt`, `RouterConfig.kt`) do not directly import from these modules. This is correct for the current phase (types are needed for subsequent tasks) but will produce unused-import warnings once source files are added and the unused deps are still present.

## suggested follow-up

1. **Add serialization round-trip test for `TokenBudget`** — low effort, high confidence gain. Add to `:core:context` or `testing/deterministic` once that test module is set up (depends on Task 019).
2. **Add serialization round-trip test for `SteeringNoteAddedEvent`** — should be paired with the first test that actually exercises the event in the event store pipeline.
3. **Proceed with Tasks 008-010** (RouterResponse, RouterReducer, RouterProjector) as the natural next phase — the foundational types from tasks 001-007 are correctly in place and ready to be consumed.
