# plan ## tasks ### task-001 artifact: `infrastructure/build.gradle` purpose: Add `:core:router` as an implementation dependency so InfrastructureModule can access RouterFacade. depends_on: none non_goals: Creating RouterFacade implementation, wiring RouterFacade into ServerModule done_when: `./gradlew :infrastructure:compileKotlin` succeeds and no detekt errors are introduced ### task-002 artifact: `apps/server/build.gradle` purpose: Add `:core:router` as an implementation dependency so ServerModule can inject RouterFacade. depends_on: none non_goals: Creating RouterFacade implementation, adding WebSocket handler logic done_when: `./gradlew :apps:server:compileKotlin` succeeds and no detekt errors are introduced ### task-003 artifact: `core/router/build.gradle` purpose: Declare `:core:router` module dependencies on `:core:events`, `:core:context`, `:core:inference`, and `:core:sessions` so the source code can compile. depends_on: none non_goals: Creating source files — only the build file is modified done_when: `./gradlew :core:router:compileKotlin` succeeds and no detekt errors are introduced ### task-004 artifact: `core/events/src/main/kotlin/com/correx/core/events/events/ContextEvents.kt` purpose: Add `SteeringNoteAddedEvent` data class implementing `EventPayload` — the only event type the router writes to the event store. depends_on: none non_goals: Adding `SteeringNote` as a separate domain type in `:core:context` (spec defers this decision), implementing reducer logic done_when: `SteeringNoteAddedEvent` compiles as a subclass of `EventPayload` and serializes correctly ### task-005 artifact: `core/events/src/main/kotlin/com/correx/core/events/serialization/Serialization.kt` purpose: Register `SteeringNoteAddedEvent` in the `eventModule` polymorphic block via `subclass(SteeringNoteAddedEvent::class)` to prevent silent runtime deserialization failure. depends_on: task-004 non_goals: Modifying any other serialization blocks, adding new serializers done_when: `./gradlew check` passes — specifically the serialization round-trip test for `SteeringNoteAddedEvent` ### task-006 artifact: `core/router/src/main/kotlin/com/correx/core/router/model/RouterState.kt` purpose: Define `RouterState` as a serializable data class holding L2 memory, workflow status, and conversation history — the foundational domain type for all router projections. depends_on: task-005 non_goals: Implementing reducer logic, defining config types done_when: `RouterState` compiles as `@Serializable` with sensible empty defaults and is accessible from all dependent modules ### task-007 artifact: `core/router/src/main/kotlin/com/correx/core/router/model/RouterConfig.kt` purpose: Define `RouterConfig` as a serializable data class holding conversation keep-last count and token budget parameters. depends_on: task-006 non_goals: Implementing context building logic, defining response types done_when: `RouterConfig` compiles as `@Serializable` with default values and is accessible from infrastructure wiring ### task-008 artifact: `core/router/src/main/kotlin/com/correx/core/router/model/RouterResponse.kt` purpose: Define `RouterResponse` as a serializable data class holding the inference output content and a `steeringEmitted` flag for the server protocol. depends_on: task-007 non_goals: Implementing facade logic, defining protocol message types done_when: `RouterResponse` compiles as `@Serializable` and is accessible from the server protocol layer ### task-009 artifact: `core/router/src/main/kotlin/com/correx/core/router/RouterReducer.kt` purpose: Implement `RouterReducer` — reduces `RouterState` from `SteeringNoteAddedEvent` and workflow lifecycle events (started, completed, failed, paused, resumed, stage completed, stage failed). depends_on: task-006 non_goals: Implementing projector, repository, context builder, or facade logic done_when: `DefaultRouterReducer.reduce()` correctly updates `RouterState` fields for every known event type and returns unchanged state for unknown events ### task-010 artifact: `core/router/src/main/kotlin/com/correx/core/router/RouterProjector.kt` purpose: Implement `RouterProjector` as `Projection` backed by `DefaultRouterReducer`, providing `initial()` and `apply()` methods per the core architecture pattern. depends_on: task-009 non_goals: Implementing repository, context builder, or facade logic done_when: `RouterProjector` produces correct `RouterState` from an empty event list and from a sequence of events ### task-011 artifact: `core/router/src/main/kotlin/com/correx/core/router/RouterRepository.kt` purpose: Implement `DefaultRouterRepository` using `EventReplayer` to rebuild `RouterState` from the event store for a given session. depends_on: task-010 non_goals: Implementing context builder, facade logic, or infrastructure wiring done_when: `DefaultRouterRepository.getRouterState(sessionId)` delegates to `EventReplayer.rebuild(sessionId)` and returns the projected state ### task-012 artifact: `core/router/src/main/kotlin/com/correx/core/router/RouterContextBuilder.kt` purpose: Implement `RouterContextBuilder` — assembles a budget-constrained `ContextPack` from L2 memory (stage summaries), workflow status events, and conversation history, respecting L0 immutability and L2 eviction ordering. depends_on: task-006, task-007 non_goals: Implementing inference routing, facade orchestration, or event writing done_when: `RouterContextBuilder.build()` produces a `ContextPack` with correct layer assignments, budget enforcement, and L0 entries preserved under all conditions ### task-013 artifact: `core/router/src/main/kotlin/com/correx/core/router/RouterFacade.kt` purpose: Implement `RouterFacade` — the orchestrating entry point that loads state via `RouterRepository`, builds context via `RouterContextBuilder`, routes inference via `InferenceRouter`, and conditionally emits `SteeringNoteAddedEvent` via `EventStore`. depends_on: task-011, task-012 non_goals: Implementing protocol types, WebSocket handler, or infrastructure wiring done_when: `RouterFacade.handleChat()` returns `RouterResponse` with correct `content` and `steeringEmitted` flag for both `CHAT` and `STEERING` modes ### task-014 artifact: `apps/server/src/main/kotlin/com/correx/apps/server/protocol/ClientMessage.kt` purpose: Add `ChatInput` data class (`sessionId: SessionId`, `text: String`, `mode: ChatMode`) and `ChatMode` enum (`CHAT`, `STEERING`) as protocol types for user-router interaction. depends_on: none non_goals: Implementing WebSocket handler logic, adding server response types done_when: `ChatInput` serializes and deserializes through `ProtocolSerializer` without errors ### task-015 artifact: `apps/server/src/main/kotlin/com/correx/apps/server/protocol/ServerMessage.kt` purpose: Add `RouterResponseMessage` data class (`sessionId: SessionId`, `content: String`, `steeringEmitted: Boolean`) as the egress protocol type for router responses. depends_on: task-008 non_goals: Implementing WebSocket handler logic, adding client message types done_when: `RouterResponseMessage` serializes and deserializes through `ProtocolSerializer` without errors ### task-016 artifact: `apps/server/src/main/kotlin/com/correx/apps/server/ws/SessionStreamHandler.kt` purpose: Add a `when` branch for `ClientMessage.ChatInput` in `handleClientMessage()` that dispatches to `module.routerFacade` and sends `RouterResponseMessage` back over WebSocket. depends_on: task-014, task-015 non_goals: Creating `RouterFacade`, adding new protocol types, modifying infrastructure wiring done_when: Chat and steering messages route to `RouterFacade` correctly and responses are sent back over WebSocket ### task-017 artifact: `apps/server/src/main/kotlin/com/correx/apps/server/ServerModule.kt` purpose: Add `routerFacade: RouterFacade` field to `ServerModule` data class so `SessionStreamHandler` can access the router facade. depends_on: task-013 non_goals: Creating `RouterFacade`, wiring the facade in InfrastructureModule done_when: `ServerModule` compiles with the new `routerFacade` parameter and is referenced by `SessionStreamHandler` ### task-018 artifact: `infrastructure/src/main/kotlin/com/correx/infrastructure/InfrastructureModule.kt` purpose: Add `createRouterFacade()` factory that assembles `RouterFacade` from `RouterRepository`, `RouterContextBuilder`, `InferenceRouter`, `EventStore`, and `RouterConfig`. depends_on: task-013, task-002 non_goals: Creating router types (all done in earlier tasks), modifying ServerModule done_when: `createRouterFacade()` returns a fully wired `RouterFacade` and `./gradlew check` passes ### task-019 artifact: `testing/deterministic/build.gradle` purpose: Add `testImplementation(project(":core:router"))` and `testImplementation(project(":core:events"))` so deterministic tests can access router and event types. depends_on: task-003 non_goals: Writing test code done_when: `./gradlew :testing:deterministic:compileTestKotlin` compiles with the new dependencies ### task-020 artifact: `testing/deterministic/src/test/kotlin/RouterReducerTest.kt` purpose: Test `DefaultRouterReducer` — verify state transitions for `SteeringNoteAddedEvent` and each workflow lifecycle event. depends_on: task-009, task-019 non_goals: Testing projector, context builder, or facade logic done_when: All reducer state transition tests pass with `./gradlew :testing:deterministic:test --tests RouterReducerTest` ### task-021 artifact: `testing/deterministic/src/test/kotlin/RouterProjectorTest.kt` purpose: Test `RouterProjector` — verify `initial()` returns empty defaults and `apply()` correctly chains reducer output. depends_on: task-010, task-019 non_goals: Testing reducer logic independently, testing repository done_when: All projector tests pass with `./gradlew :testing:deterministic:test --tests RouterProjectorTest` ### task-022 artifact: `testing/deterministic/src/test/kotlin/RouterContextBuilderTest.kt` purpose: Test `RouterContextBuilder` — verify budget enforcement, L0 immutability, L2 oldest-first eviction, and layer classification. depends_on: task-012, task-019 non_goals: Testing facade orchestration, testing inference routing done_when: All context builder tests pass with `./gradlew :testing:deterministic:test --tests RouterContextBuilderTest` ### task-023 artifact: `testing/deterministic/src/test/kotlin/RouterFacadeTest.kt` purpose: Test `RouterFacade` — verify end-to-end orchestration for both `CHAT` and `STEERING` modes using faked dependencies. depends_on: task-013, task-019 non_goals: Testing individual components, testing WebSocket protocol done_when: All facade tests pass with `./gradlew :testing:deterministic:test --tests RouterFacadeTest`