chore(damn): detekt, build, tests, formatting

fixed detekt issues where possible.
fixed disttar failing build because tools is added twice in the server module.
added workflowId where required.
fixed some tests not being recognized because of runBlocking without explicit return type.
formatting + imports.
This commit is contained in:
2026-05-22 00:10:05 +04:00
parent 2c459da009
commit f827685ed0
185 changed files with 1134 additions and 832 deletions
@@ -103,6 +103,7 @@ class GraphValidatorTest {
)
val graph = WorkflowGraph(
id = "workflow-test",
stages = mapOf(a to StageConfig(), b to StageConfig()),
transitions = setOf(edge1, edge2),
start = a
@@ -1,6 +1,7 @@
import com.correx.core.context.model.CompressionMetadata
import com.correx.core.context.model.ContextLayer
import com.correx.core.context.model.TokenBudget
import com.correx.core.events.types.SessionId
import com.correx.core.events.types.StageId
import com.correx.core.router.DefaultRouterContextBuilder
import com.correx.core.router.model.RouterConfig
import com.correx.core.router.model.RouterL2Entry
@@ -9,10 +10,6 @@ import com.correx.core.router.model.RouterTurn
import com.correx.core.router.model.StageOutcomeKind
import com.correx.core.router.model.TurnRole
import com.correx.core.router.model.WorkflowStatus
import com.correx.core.events.types.ContextEntryId
import com.correx.core.events.types.ContextPackId
import com.correx.core.events.types.SessionId
import com.correx.core.events.types.StageId
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
import org.junit.jupiter.api.Assertions.assertEquals
@@ -537,8 +534,18 @@ class RouterContextBuilderTest {
RouterTurn(TurnRole.ROUTER, "second reply", Instant.parse("2026-01-04T00:00:00Z")),
),
l2Memory = listOf(
RouterL2Entry(StageId("s1"), "stage one done", StageOutcomeKind.SUCCESS, Instant.parse("2026-01-01T10:00:00Z")),
RouterL2Entry(StageId("s2"), "stage two failed", StageOutcomeKind.FAILURE, Instant.parse("2026-01-02T10:00:00Z")),
RouterL2Entry(
StageId("s1"),
"stage one done",
StageOutcomeKind.SUCCESS,
Instant.parse("2026-01-01T10:00:00Z"),
),
RouterL2Entry(
StageId("s2"),
"stage two failed",
StageOutcomeKind.FAILURE,
Instant.parse("2026-01-02T10:00:00Z"),
),
),
)
val pack = builder.build(state, TokenBudget(limit = 10000))
@@ -1,12 +1,13 @@
import com.correx.core.context.model.ContextPack
import com.correx.core.context.model.TokenBudget
import com.correx.core.events.events.NewEvent
import com.correx.core.events.events.SteeringNoteAddedEvent
import com.correx.core.events.events.StoredEvent
import com.correx.core.events.stores.EventStore
import com.correx.core.events.types.ContextPackId
import com.correx.core.events.types.InferenceRequestId
import com.correx.core.events.types.SessionId
import com.correx.core.events.types.StageId
import com.correx.core.inference.GenerationConfig
import com.correx.core.inference.InferenceProvider
import com.correx.core.inference.InferenceRequest
import com.correx.core.inference.InferenceResponse
@@ -14,7 +15,6 @@ import com.correx.core.inference.InferenceRouter
import com.correx.core.inference.ModelCapability
import com.correx.core.inference.TokenUsage
import com.correx.core.router.ChatMode
import com.correx.core.router.DefaultRouterContextBuilder
import com.correx.core.router.DefaultRouterFacade
import com.correx.core.router.RouterContextBuilder
import com.correx.core.router.RouterFacade
@@ -24,18 +24,13 @@ import com.correx.core.router.model.RouterResponse
import com.correx.core.router.model.RouterState
import com.correx.core.router.model.TurnRole
import com.correx.core.router.model.WorkflowStatus
import com.correx.core.context.model.ContextPack
import com.correx.core.events.types.ContextPackId
import com.correx.core.events.types.ContextEntryId
import com.correx.core.context.model.ContextEntry
import com.correx.core.context.model.ContextLayer
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertNotNull
import org.junit.jupiter.api.Assertions.assertNull
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
import kotlinx.coroutines.runBlocking
class RouterFacadeTest {
@@ -44,7 +39,7 @@ class RouterFacadeTest {
// --------------------------------------------------------------------------
@Test
fun `CHAT mode returns inference response content`() = runBlocking {
fun `CHAT mode returns inference response content`(): Unit = runBlocking {
val mockStore = mockEventStore()
val facade = facadeWithMocks(eventStore = mockStore, chatMode = ChatMode.CHAT)
val response = facade.onUserInput(sessionId = SessionId("test-session"), input = "Hello, world!")
@@ -52,7 +47,7 @@ class RouterFacadeTest {
}
@Test
fun `CHAT mode sets steeringEmitted to false`() = runBlocking {
fun `CHAT mode sets steeringEmitted to false`(): Unit = runBlocking {
val mockStore = mockEventStore()
val facade = facadeWithMocks(eventStore = mockStore, chatMode = ChatMode.CHAT)
val response = facade.onUserInput(sessionId = SessionId("test-session"), input = "Hello!")
@@ -60,7 +55,7 @@ class RouterFacadeTest {
}
@Test
fun `CHAT mode does not append to EventStore`() = runBlocking {
fun `CHAT mode does not append to EventStore`(): Unit = runBlocking {
val mockStore = mockEventStore()
val facade = facadeWithMocks(eventStore = mockStore, chatMode = ChatMode.CHAT)
facade.onUserInput(sessionId = SessionId("test-session"), input = "Hello!")
@@ -72,7 +67,7 @@ class RouterFacadeTest {
// --------------------------------------------------------------------------
@Test
fun `STEERING mode sets steeringEmitted to true`() = runBlocking {
fun `STEERING mode sets steeringEmitted to true`(): Unit = runBlocking {
val mockStore = mockEventStore()
val facade = facadeWithMocks(eventStore = mockStore, chatMode = ChatMode.STEERING)
val response = facade.onUserInput(sessionId = SessionId("test-session"), input = "Hello!")
@@ -80,7 +75,7 @@ class RouterFacadeTest {
}
@Test
fun `STEERING mode appends SteeringNoteAddedEvent with correct session id and user input`() = runBlocking {
fun `STEERING mode appends SteeringNoteAddedEvent with correct session id and user input`(): Unit = runBlocking {
val mockStore = mockEventStore()
val facade = facadeWithMocks(eventStore = mockStore, chatMode = ChatMode.STEERING)
facade.onUserInput(sessionId = SessionId("session-xyz"), input = "steer this way")
@@ -93,13 +88,17 @@ class RouterFacadeTest {
}
@Test
fun `STEERING mode appends SteeringNoteAddedEvent with stageId from state`() = runBlocking {
fun `STEERING mode appends SteeringNoteAddedEvent with stageId from state`(): Unit = runBlocking {
val mockStore = mockEventStore()
val stageId = StageId("stage-A")
val facade = DefaultRouterFacade(
routerRepository = object : RouterRepository {
override suspend fun getRouterState(sessionId: SessionId): RouterState =
RouterState(sessionId = sessionId, workflowStatus = WorkflowStatus.RUNNING, currentStageId = stageId)
RouterState(
sessionId = sessionId,
workflowStatus = WorkflowStatus.RUNNING,
currentStageId = stageId,
)
},
routerContextBuilder = object : RouterContextBuilder {
override fun build(state: RouterState, budget: TokenBudget): ContextPack = emptyContextPack()
@@ -114,7 +113,7 @@ class RouterFacadeTest {
}
@Test
fun `STEERING mode appends SteeringNoteAddedEvent with null stageId when state has none`() = runBlocking {
fun `STEERING mode appends SteeringNoteAddedEvent with null stageId when state has none`(): Unit = runBlocking {
val mockStore = mockEventStore()
val facade = DefaultRouterFacade(
routerRepository = object : RouterRepository {
@@ -138,12 +137,16 @@ class RouterFacadeTest {
// --------------------------------------------------------------------------
@Test
fun `conversation history grows per call user and router turns appended`() = runBlocking {
fun `conversation history grows per call - user and router turns appended`(): Unit = runBlocking {
val capturedStates = mutableListOf<RouterState>()
val facade = DefaultRouterFacade(
routerRepository = object : RouterRepository {
override suspend fun getRouterState(sessionId: SessionId): RouterState =
RouterState(sessionId = sessionId, workflowStatus = WorkflowStatus.RUNNING, currentStageId = StageId("s1"))
RouterState(
sessionId = sessionId,
workflowStatus = WorkflowStatus.RUNNING,
currentStageId = StageId("s1"),
)
},
routerContextBuilder = object : RouterContextBuilder {
override fun build(state: RouterState, budget: TokenBudget): ContextPack {
@@ -171,7 +174,7 @@ class RouterFacadeTest {
}
@Test
fun `conversation history is session-scoped different sessions do not share history`() = runBlocking {
fun `conversation history is session-scoped - different sessions do not share history`(): Unit = runBlocking {
val capturedStates = mutableListOf<RouterState>()
val facade = DefaultRouterFacade(
routerRepository = object : RouterRepository {
@@ -204,7 +207,7 @@ class RouterFacadeTest {
// --------------------------------------------------------------------------
@Test
fun `state is passed through to context builder`() = runBlocking {
fun `state is passed through to context builder`(): Unit = runBlocking {
val capturedState = mutableListOf<RouterState>()
val mockContextBuilder = object : RouterContextBuilder {
override fun build(state: RouterState, budget: TokenBudget): ContextPack {
@@ -215,7 +218,11 @@ class RouterFacadeTest {
val facade = DefaultRouterFacade(
routerRepository = object : RouterRepository {
override suspend fun getRouterState(sessionId: SessionId): RouterState =
RouterState(sessionId = sessionId, workflowStatus = WorkflowStatus.RUNNING, currentStageId = StageId("s1"))
RouterState(
sessionId = sessionId,
workflowStatus = WorkflowStatus.RUNNING,
currentStageId = StageId("s1"),
)
},
routerContextBuilder = mockContextBuilder,
inferenceRouter = mockInferenceRouter("inference response"),
@@ -229,7 +236,7 @@ class RouterFacadeTest {
}
@Test
fun `budget is passed through to context builder`() = runBlocking {
fun `budget is passed through to context builder`(): Unit = runBlocking {
val capturedBudget = mutableListOf<TokenBudget>()
val mockContextBuilder = object : RouterContextBuilder {
override fun build(state: RouterState, budget: TokenBudget): ContextPack {
@@ -252,10 +259,13 @@ class RouterFacadeTest {
}
@Test
fun `stage ID uses state currentStageId`() = runBlocking {
fun `stage ID uses state currentStageId`(): Unit = runBlocking {
val capturedStageId = mutableListOf<StageId>()
val mockInferenceRouter = object : InferenceRouter {
override suspend fun route(stageId: StageId, requiredCapabilities: Set<ModelCapability>): InferenceProvider {
override suspend fun route(
stageId: StageId,
requiredCapabilities: Set<ModelCapability>,
): InferenceProvider {
capturedStageId.add(stageId)
return mockProvider("response")
}
@@ -281,10 +291,13 @@ class RouterFacadeTest {
}
@Test
fun `stage ID falls back to StageId("none") when state has no currentStageId`() = runBlocking {
fun `stage ID falls back to StageId none when state has no currentStageId`(): Unit = runBlocking {
val capturedStageId = mutableListOf<StageId>()
val mockInferenceRouter = object : InferenceRouter {
override suspend fun route(stageId: StageId, requiredCapabilities: Set<ModelCapability>): InferenceProvider {
override suspend fun route(
stageId: StageId,
requiredCapabilities: Set<ModelCapability>,
): InferenceProvider {
capturedStageId.add(stageId)
return mockProvider("response")
}
@@ -309,10 +322,13 @@ class RouterFacadeTest {
}
@Test
fun `new InferenceRequestId per call`() = runBlocking {
fun `new InferenceRequestId per call`(): Unit = runBlocking {
val capturedRequestIds = mutableListOf<InferenceRequestId>()
val mockInferenceRouter = object : InferenceRouter {
override suspend fun route(stageId: StageId, requiredCapabilities: Set<ModelCapability>): InferenceProvider {
override suspend fun route(
stageId: StageId,
requiredCapabilities: Set<ModelCapability>,
): InferenceProvider {
return mockProviderWithCapture("response", capturedRequestIds)
}
}
@@ -334,10 +350,13 @@ class RouterFacadeTest {
}
@Test
fun `GenerationConfig defaults temperature 0 7 topP 0 9 maxTokens 512`() = runBlocking {
fun `GenerationConfig defaults temperature 0 7 topP 0 9 maxTokens 512`(): Unit = runBlocking {
val capturedRequests = mutableListOf<InferenceRequest>()
val mockInferenceRouter = object : InferenceRouter {
override suspend fun route(stageId: StageId, requiredCapabilities: Set<ModelCapability>): InferenceProvider {
override suspend fun route(
stageId: StageId,
requiredCapabilities: Set<ModelCapability>,
): InferenceProvider {
return mockProviderWithRequestCapture("response", capturedRequests)
}
}
@@ -360,7 +379,7 @@ class RouterFacadeTest {
}
@Test
fun `context pack is passed to inference provider`() = runBlocking {
fun `context pack is passed to inference provider`(): Unit = runBlocking {
val capturedContextPacks = mutableListOf<ContextPack>()
val facade = DefaultRouterFacade(
routerRepository = object : RouterRepository {
@@ -381,7 +400,10 @@ class RouterFacadeTest {
}
},
inferenceRouter = object : InferenceRouter {
override suspend fun route(stageId: StageId, requiredCapabilities: Set<ModelCapability>): InferenceProvider {
override suspend fun route(
stageId: StageId,
requiredCapabilities: Set<ModelCapability>,
): InferenceProvider {
return object : InferenceProvider {
override val id = com.correx.core.events.types.ProviderId("mock")
override val name = "Mock"
@@ -397,8 +419,10 @@ class RouterFacadeTest {
latencyMs = 0,
)
}
override suspend fun healthCheck(): com.correx.core.inference.ProviderHealth =
com.correx.core.inference.ProviderHealth.Healthy
override fun capabilities(): Set<com.correx.core.inference.CapabilityScore> = emptySet()
}
}
@@ -410,7 +434,7 @@ class RouterFacadeTest {
}
@Test
fun `responseFormat defaults to Text`() = runBlocking {
fun `responseFormat defaults to Text`(): Unit = runBlocking {
val capturedRequests = mutableListOf<InferenceRequest>()
val facade = DefaultRouterFacade(
routerRepository = object : RouterRepository {
@@ -420,7 +444,10 @@ class RouterFacadeTest {
override fun build(state: RouterState, budget: TokenBudget): ContextPack = emptyContextPack()
},
inferenceRouter = object : InferenceRouter {
override suspend fun route(stageId: StageId, requiredCapabilities: Set<ModelCapability>): InferenceProvider {
override suspend fun route(
stageId: StageId,
requiredCapabilities: Set<ModelCapability>,
): InferenceProvider {
return mockProviderWithRequestCapture("response", capturedRequests)
}
},
@@ -433,7 +460,7 @@ class RouterFacadeTest {
}
@Test
fun `onUserInput returns RouterResponse with content and mode flag`() = runBlocking {
fun `onUserInput returns RouterResponse with content and mode flag`(): Unit = runBlocking {
val mockStore = mockEventStore()
val facade = facadeWithMocks(eventStore = mockStore, chatMode = ChatMode.STEERING)
val response = facade.onUserInput(sessionId = SessionId("test-session"), input = "Hello!")
@@ -455,7 +482,11 @@ class RouterFacadeTest {
): RouterFacade = DefaultRouterFacade(
routerRepository = object : RouterRepository {
override suspend fun getRouterState(sessionId: SessionId): RouterState =
RouterState(sessionId = sessionId, workflowStatus = WorkflowStatus.RUNNING, currentStageId = StageId("s1"))
RouterState(
sessionId = sessionId,
workflowStatus = WorkflowStatus.RUNNING,
currentStageId = StageId("s1"),
)
},
routerContextBuilder = object : RouterContextBuilder {
override fun build(state: RouterState, budget: TokenBudget): ContextPack = emptyContextPack()
@@ -472,7 +503,10 @@ class RouterFacadeTest {
private fun mockInferenceRouter(responseText: String): InferenceRouter =
object : InferenceRouter {
override suspend fun route(stageId: StageId, requiredCapabilities: Set<ModelCapability>): InferenceProvider =
override suspend fun route(
stageId: StageId,
requiredCapabilities: Set<ModelCapability>,
): InferenceProvider =
mockProvider(responseText)
}
@@ -488,8 +522,10 @@ class RouterFacadeTest {
tokensUsed = TokenUsage(promptTokens = 10, completionTokens = 5),
latencyMs = 0,
)
override suspend fun healthCheck(): com.correx.core.inference.ProviderHealth =
com.correx.core.inference.ProviderHealth.Healthy
override fun capabilities(): Set<com.correx.core.inference.CapabilityScore> =
setOf(com.correx.core.inference.CapabilityScore(ModelCapability.General, 1.0))
}
@@ -512,8 +548,10 @@ class RouterFacadeTest {
latencyMs = 0,
)
}
override suspend fun healthCheck(): com.correx.core.inference.ProviderHealth =
com.correx.core.inference.ProviderHealth.Healthy
override fun capabilities(): Set<com.correx.core.inference.CapabilityScore> = emptySet()
}
@@ -535,8 +573,10 @@ class RouterFacadeTest {
latencyMs = 0,
)
}
override suspend fun healthCheck(): com.correx.core.inference.ProviderHealth =
com.correx.core.inference.ProviderHealth.Healthy
override fun capabilities(): Set<com.correx.core.inference.CapabilityScore> = emptySet()
}
@@ -568,16 +608,19 @@ class RouterFacadeTest {
override suspend fun appendAll(events: List<NewEvent>): List<StoredEvent> =
events.map { append(it) }
override fun read(sessionId: com.correx.core.events.types.SessionId): List<StoredEvent> =
override fun read(sessionId: SessionId): List<StoredEvent> =
storedEvents.values.filter { it.metadata.sessionId == sessionId }.toList()
override fun readFrom(sessionId: com.correx.core.events.types.SessionId, fromSequence: Long): List<StoredEvent> =
override fun readFrom(
sessionId: SessionId,
fromSequence: Long,
): List<StoredEvent> =
read(sessionId).filter { it.sequence >= fromSequence }
override fun lastSequence(sessionId: com.correx.core.events.types.SessionId): Long? =
override fun lastSequence(sessionId: SessionId): Long? =
read(sessionId).maxOfOrNull { it.sequence }
override fun subscribe(sessionId: com.correx.core.events.types.SessionId): kotlinx.coroutines.flow.Flow<StoredEvent> =
override fun subscribe(sessionId: SessionId): kotlinx.coroutines.flow.Flow<StoredEvent> =
throw UnsupportedOperationException("subscribe not implemented for mock")
override fun allEvents(): Sequence<StoredEvent> =
@@ -7,13 +7,13 @@ import com.correx.core.events.events.ToolInvokedEvent
import com.correx.core.events.events.WorkflowCompletedEvent
import com.correx.core.events.events.WorkflowFailedEvent
import com.correx.core.events.events.WorkflowStartedEvent
import com.correx.core.events.types.SessionId
import com.correx.core.events.types.StageId
import com.correx.core.router.DefaultRouterReducer
import com.correx.core.router.RouterProjector
import com.correx.core.router.model.RouterState
import com.correx.core.router.model.StageOutcomeKind
import com.correx.core.router.model.WorkflowStatus
import com.correx.core.events.types.SessionId
import com.correx.core.events.types.StageId
import com.correx.testing.fixtures.EventFixtures.stored
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNull
@@ -26,6 +26,7 @@ class RouterProjectorTest {
private val projector = RouterProjector(reducer)
private val sessionId = SessionId("s1")
private val stageId = StageId("stage-1")
private val workflowId = "workflow-test"
@Test
fun `initial() returns RouterState with IDLE status and empty collections`() {
@@ -49,7 +50,7 @@ class RouterProjectorTest {
val state = projector.initial()
val updated = projector.apply(
state,
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
)
assertEquals(sessionId, updated.sessionId)
assertEquals(WorkflowStatus.RUNNING, updated.workflowStatus)
@@ -60,11 +61,11 @@ class RouterProjectorTest {
fun `apply(WorkflowCompletedEvent) delegates to reducer and sets COMPLETED`() {
val started = projector.apply(
projector.initial(),
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
)
val updated = projector.apply(
started,
stored(payload = WorkflowCompletedEvent(sessionId, stageId, 3)),
stored(payload = WorkflowCompletedEvent(sessionId, stageId, 3, workflowId)),
)
assertEquals(WorkflowStatus.COMPLETED, updated.workflowStatus)
assertNull(updated.currentStageId)
@@ -75,7 +76,7 @@ class RouterProjectorTest {
fun `apply(WorkflowFailedEvent) delegates to reducer and sets FAILED`() {
val started = projector.apply(
projector.initial(),
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
)
val updated = projector.apply(
started,
@@ -89,7 +90,7 @@ class RouterProjectorTest {
fun `apply(OrchestrationPausedEvent) delegates to reducer and sets PAUSED`() {
val started = projector.apply(
projector.initial(),
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
)
val updated = projector.apply(
started,
@@ -103,7 +104,7 @@ class RouterProjectorTest {
fun `apply(OrchestrationResumedEvent) delegates to reducer and sets RUNNING`() {
val started = projector.apply(
projector.initial(),
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
)
val paused = projector.apply(
started,
@@ -133,7 +134,7 @@ class RouterProjectorTest {
fun `apply(StageFailedEvent) delegates to reducer and appends FAILURE entry`() {
val state = projector.apply(
projector.initial(),
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
)
val updated = projector.apply(
state,
@@ -169,13 +170,13 @@ class RouterProjectorTest {
fun `apply produces same result as reducer reduce for every handled event`() {
val state = projector.initial()
val events = listOf(
stored(payload = WorkflowStartedEvent(sessionId, StageId("a"))),
stored(payload = WorkflowStartedEvent(sessionId, workflowId, StageId("a"))),
stored(payload = StageCompletedEvent(sessionId, StageId("a"), StageId("t1"))),
stored(payload = OrchestrationPausedEvent(sessionId, StageId("a"), "hold")),
stored(payload = OrchestrationResumedEvent(sessionId, StageId("a"))),
stored(payload = StageCompletedEvent(sessionId, StageId("b"), StageId("t2"))),
stored(payload = StageFailedEvent(sessionId, StageId("b"), StageId("t3"), "error")),
stored(payload = WorkflowCompletedEvent(sessionId, StageId("c"), 3)),
stored(payload = WorkflowCompletedEvent(sessionId, StageId("c"), 3, workflowId)),
)
var projected = state
@@ -193,7 +194,7 @@ class RouterProjectorTest {
state = projector.apply(
state,
stored(payload = WorkflowStartedEvent(sessionId, StageId("stage-A"))),
stored(payload = WorkflowStartedEvent(sessionId, workflowId, StageId("stage-A"))),
)
assertEquals(WorkflowStatus.RUNNING, state.workflowStatus)
@@ -205,7 +206,7 @@ class RouterProjectorTest {
state = projector.apply(
state,
stored(payload = WorkflowCompletedEvent(sessionId, StageId("stage-A"), 1)),
stored(payload = WorkflowCompletedEvent(sessionId, StageId("stage-A"), 1, workflowId)),
)
assertEquals(WorkflowStatus.COMPLETED, state.workflowStatus)
assertNull(state.currentStageId)
@@ -1,17 +1,17 @@
import com.correx.core.events.events.OrchestrationPausedEvent
import com.correx.core.events.events.OrchestrationResumedEvent
import com.correx.core.events.events.SteeringNoteAddedEvent
import com.correx.core.events.events.StageCompletedEvent
import com.correx.core.events.events.StageFailedEvent
import com.correx.core.events.events.SteeringNoteAddedEvent
import com.correx.core.events.events.ToolInvokedEvent
import com.correx.core.events.events.WorkflowCompletedEvent
import com.correx.core.events.events.WorkflowFailedEvent
import com.correx.core.events.events.WorkflowStartedEvent
import com.correx.core.events.types.SessionId
import com.correx.core.events.types.StageId
import com.correx.core.router.DefaultRouterReducer
import com.correx.core.router.model.StageOutcomeKind
import com.correx.core.router.model.WorkflowStatus
import com.correx.core.events.types.SessionId
import com.correx.core.events.types.StageId
import com.correx.testing.fixtures.EventFixtures.stored
import kotlinx.datetime.Instant
import org.junit.jupiter.api.Assertions.assertEquals
@@ -25,6 +25,7 @@ class RouterReducerTest {
private val reducer = DefaultRouterReducer()
private val sessionId = SessionId("s1")
private val stageId = StageId("stage-1")
private val workflowId = "workflow-test"
@Test
fun `initial state has IDLE status and empty collections`() {
@@ -41,7 +42,7 @@ class RouterReducerTest {
val state = reducer.initial
val updated = reducer.reduce(
state,
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
)
assertEquals(sessionId, updated.sessionId)
assertEquals(WorkflowStatus.RUNNING, updated.workflowStatus)
@@ -53,11 +54,11 @@ class RouterReducerTest {
val initial = reducer.initial
val started = reducer.reduce(
initial,
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
)
val completed = reducer.reduce(
started,
stored(payload = WorkflowCompletedEvent(sessionId, stageId, 3)),
stored(payload = WorkflowCompletedEvent(sessionId, stageId, 3, workflowId)),
)
assertEquals(WorkflowStatus.COMPLETED, completed.workflowStatus)
assertNull(completed.currentStageId)
@@ -69,7 +70,7 @@ class RouterReducerTest {
val initial = reducer.initial
val started = reducer.reduce(
initial,
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
)
val failed = reducer.reduce(
started,
@@ -84,7 +85,7 @@ class RouterReducerTest {
val initial = reducer.initial
val started = reducer.reduce(
initial,
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
)
val paused = reducer.reduce(
started,
@@ -99,7 +100,7 @@ class RouterReducerTest {
val initial = reducer.initial
val started = reducer.reduce(
initial,
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
)
val paused = reducer.reduce(
started,
@@ -130,7 +131,7 @@ class RouterReducerTest {
val initial = reducer.initial
val started = reducer.reduce(
initial,
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
)
val updated = reducer.reduce(
started,
@@ -146,7 +147,7 @@ class RouterReducerTest {
val initial = reducer.initial
val started = reducer.reduce(
initial,
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
)
val storedEvent = stored(payload = StageFailedEvent(sessionId, stageId, StageId("t1"), "timeout"))
val updated = reducer.reduce(started, storedEvent)
@@ -189,7 +190,7 @@ class RouterReducerTest {
val initial = reducer.initial
val started = reducer.reduce(
initial,
stored(payload = WorkflowStartedEvent(sessionId, stageId)),
stored(payload = WorkflowStartedEvent(sessionId, workflowId, stageId)),
)
val withNote = reducer.reduce(
started,
@@ -223,7 +224,7 @@ class RouterReducerTest {
val s0 = reducer.initial
assertEquals(WorkflowStatus.IDLE, s0.workflowStatus)
val s1 = reducer.reduce(s0, stored(payload = WorkflowStartedEvent(sessionId, StageId("stage-A"))))
val s1 = reducer.reduce(s0, stored(payload = WorkflowStartedEvent(sessionId, workflowId, StageId("stage-A"))))
assertEquals(WorkflowStatus.RUNNING, s1.workflowStatus)
assertEquals(StageId("stage-A"), s1.currentStageId)
@@ -231,11 +232,15 @@ class RouterReducerTest {
assertEquals(1, s2.l2Memory.size)
assertEquals(StageOutcomeKind.SUCCESS, s2.l2Memory[0].outcome)
val s3 = reducer.reduce(s2, stored(payload = WorkflowCompletedEvent(sessionId, StageId("stage-A"), 1)))
val s3 =
reducer.reduce(s2, stored(payload = WorkflowCompletedEvent(sessionId, StageId("stage-A"), 1, workflowId)))
assertEquals(WorkflowStatus.COMPLETED, s3.workflowStatus)
assertNull(s3.currentStageId)
val s4 = reducer.reduce(s3, stored(payload = OrchestrationPausedEvent(sessionId, StageId("stage-A"), "manual pause")))
val s4 = reducer.reduce(
s3,
stored(payload = OrchestrationPausedEvent(sessionId, StageId("stage-A"), "manual pause")),
)
assertEquals(WorkflowStatus.PAUSED, s4.workflowStatus)
val s5 = reducer.reduce(s4, stored(payload = OrchestrationResumedEvent(sessionId, StageId("stage-A"))))
@@ -55,4 +55,4 @@ class SessionReplayDeterminismTest {
assertEquals(state1, state2)
}
}
}