fix: complete P4 audit findings — steering wiring, generation config

P4-1: Wire steering to actually work (advisory-only):
  - RouterFacade emits SteeringNoteAddedEvent via event store in STEERING mode
  - SessionOrchestrator reads steering notes from event store and includes them
    as ContextEntry objects (sourceType=steeringNote) in stage context packs
  - Delete dead SteeringNote data class; single vocabulary = SteeringNoteAddedEvent
  - Add optional validateSteering callback to DefaultRouterFacade for future
    ValidationPipeline wiring (avoids cross-core dependency)
  - Update RouterFacadeTest to assert event emission

P4-2: Router FACE — move hardcoded generation config:
  - Add GenerationConfig field to RouterConfig with same defaults
  - RouterFacade uses config.generationConfig instead of inline literals
  - (Remaining P4-2 items: conversation persistence and coordination
    semantics are design decisions requiring ADRs, deferred)
This commit is contained in:
2026-05-29 01:19:18 +04:00
parent f7f237e29f
commit 3981d8443d
5 changed files with 69 additions and 37 deletions
@@ -81,17 +81,18 @@ class RouterFacadeTest {
}
@Test
fun `STEERING mode does not append events to store`(): Unit = runBlocking {
// SteeringNoteAddedEvent emission is deferred to P4-1 (see P0-6).
// The steeringEmitted flag still informs the TUI that steering mode was used.
fun `STEERING mode appends SteeringNoteAddedEvent to store`(): Unit = runBlocking {
val mockStore = mockEventStore()
val facade = facadeWithMocks(eventStore = mockStore, chatMode = ChatMode.STEERING)
facade.onUserInput(sessionId = SessionId("session-xyz"), input = "steer this way")
assertTrue(mockStore.appendedEvents.isEmpty())
assertEquals(1, mockStore.appendedEvents.size)
val payload = mockStore.appendedEvents.single().payload
assertTrue(payload is com.correx.core.events.events.SteeringNoteAddedEvent)
assertEquals("inference response", (payload as com.correx.core.events.events.SteeringNoteAddedEvent).content)
}
@Test
fun `STEERING mode does not append events regardless of state stageId`(): Unit = runBlocking {
fun `STEERING mode appends SteeringNoteAddedEvent with current stageId`(): Unit = runBlocking {
val mockStore = mockEventStore()
val stageId = StageId("stage-A")
val facade = DefaultRouterFacade(
@@ -106,12 +107,15 @@ class RouterFacadeTest {
routerContextBuilder = object : RouterContextBuilder {
override suspend fun build(state: RouterState, budget: TokenBudget): ContextPack = emptyContextPack()
},
inferenceRouter = mockInferenceRouter("response"),
inferenceRouter = mockInferenceRouter("steering response"),
eventStore = mockStore,
config = RouterConfig(tokenBudget = TokenBudget(limit = 5000)),
)
facade.onUserInput(sessionId = SessionId("test-session"), input = "Hello!", mode = ChatMode.STEERING)
assertTrue(mockStore.appendedEvents.isEmpty())
assertEquals(1, mockStore.appendedEvents.size)
val payload = mockStore.appendedEvents.single().payload
assertTrue(payload is com.correx.core.events.events.SteeringNoteAddedEvent)
assertEquals("steering response", (payload as com.correx.core.events.events.SteeringNoteAddedEvent).content)
}
// --------------------------------------------------------------------------
@@ -449,8 +453,7 @@ class RouterFacadeTest {
assertNotNull(response)
assertEquals("inference response", response.content)
assertTrue(response.steeringEmitted)
// Steering events are deferred to P4-1; no events appended yet.
assertTrue(mockStore.appendedEvents.isEmpty())
assertEquals(1, mockStore.appendedEvents.size)
}
// --------------------------------------------------------------------------