# task-013 status: done ## goal 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. ## target artifact core/router/src/main/kotlin/com/correx/core/router/RouterFacade.kt ## execution steps 1. **Create `RouterFacade` interface** in `RouterFacade.kt` at `core/router/src/main/kotlin/com/correx/core/router/RouterFacade.kt` - Interface signature: `suspend fun handleChat(sessionId: SessionId, text: String, mode: ChatMode = ChatMode.CHAT, stageId: StageId? = null, requiredCapabilities: Set = setOf(ModelCapability.General)): RouterResponse` - Package: `com.correx.core.router` - Imports: `SessionId`, `StageId` from `com.correx.core.events.types`; `ChatMode` enum (CHAT, STEERING) declared locally in this file; `ModelCapability` from `com.correx.core.inference`; `RouterResponse` from `com.correx.core.router.model` 2. **Create `DefaultRouterFacade` class** implementing `RouterFacade` - Constructor injects: `RouterRepository`, `RouterContextBuilder`, `InferenceRouter`, `EventStore`, `RouterConfig` - All constructor params are interfaces or data classes — never instantiate concrete dependencies inside the class - `handleChat()` implementation: a. Load `RouterState` from `routerRepository.getRouterState(sessionId)` b. Determine `effectiveStageId`: use provided `stageId` parameter, or fall back to `state.currentStageId`, or create `StageId("none")` as final default c. Build `ContextPack` via `contextBuilder.build(state, config.tokenBudget)` d. Route provider via `inferenceRouter.route(effectiveStageId, requiredCapabilities)` e. Call `provider.infer(InferenceRequest(...))` with: - `requestId` = new `InferenceRequestId(java.util.UUID.randomUUID().toString())` - `sessionId` = from parameter - `stageId` = effectiveStageId - `contextPack` = built ContextPack - `generationConfig` = `GenerationConfig(temperature = 0.7, topP = 0.9, maxTokens = 512)` - `responseFormat` = `ResponseFormat.Text` f. Extract `text` from `InferenceResponse` g. If `mode == ChatMode.STEERING`: create `NewEvent` with `SteeringNoteAddedEvent(sessionId = sessionId, content = text, stageId = stageId)` and `EventMetadata` (eventId, sessionId, timestamp = Clock.System.now(), schemaVersion = 1, causationId = null, correlationId = null); call `eventStore.append(newEvent)` h. Return `RouterResponse(content = text, steeringEmitted = (mode == ChatMode.STEERING))` 3. **Add `ChatMode` enum** in the same file - `enum class ChatMode { CHAT, STEERING }` 4. **Verify no raw event payloads, artifacts, or tool outputs** leak into the context pack — the RouterFacade only delegates to RouterContextBuilder for context assembly 5. **Verify compilation** with `./gradlew :core:router:compileKotlin` ## changed artifacts - `core/router/src/main/kotlin/com/correx/core/router/RouterFacade.kt` — new file (interface + implementation + ChatMode enum) ## blockers - None — task-011 (RouterRepository) and task-012 (RouterContextBuilder) are complete and the artifact files exist ## notes - The RouterFacade does NOT implement protocol types, WebSocket handlers, or infrastructure wiring — those are separate tasks (014-018) - `ChatMode` is declared locally in this file because it is a router-specific concept (not shared with the server protocol layer, which will define its own types in task-014) - The `GenerationConfig` defaults (temperature=0.7, topP=0.9, maxTokens=512) are reasonable router defaults — infrastructure wiring can override if needed - The `requiredCapabilities` defaults to `General` — this is a reasonable default for a routing assistant - The `SteeringNoteAddedEvent` content is the inference response text, not the original user input — this allows the steering note to carry the router's synthesized guidance - Exception handling: `InferenceRouter.route()` and `InferenceProvider.infer()` may throw; these propagate up to the caller (WebSocket handler in task-016) - The `EventDispatcher` class from `:core:events` is available but RouterFacade writes events directly to `EventStore.append()` to maintain clear ownership boundaries