refactor: decomposition WIP (orchestrator/server/execution-plan)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DhFXmKe4WisSSPf9LrmmTg
This commit is contained in:
2026-07-15 13:17:01 +04:00
parent 9b925e141d
commit d69cb12ce9
17 changed files with 209 additions and 20 deletions
@@ -53,6 +53,7 @@ import com.correx.core.sessions.projections.replay.DefaultEventReplayer
import com.correx.testing.fixtures.EventFixtures
import com.correx.testing.fixtures.inference.MockTokenizer
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.runBlocking
import kotlinx.datetime.Instant
import kotlinx.serialization.decodeFromString
@@ -694,7 +695,9 @@ class TalkieFacadeTest {
payload = com.correx.core.events.events.IdeaDiscardedEvent(ideaId = drop.id, sessionId = SessionId("chat-2")),
),
)
val after = reader.activeIdeas()
// IdeaReader folds post-construction events via subscribeAll on a background dispatcher, so
// the discard lands asynchronously — poll briefly instead of reading on the same tick.
val after = eventually { reader.activeIdeas().takeIf { it.size == 1 } }
assertEquals(listOf("cache the repo map"), after.map { it.text })
}
@@ -1468,10 +1471,22 @@ class TalkieFacadeTest {
budgetLimit = 5000,
)
private suspend fun <T> eventually(timeoutMs: Long = 2_000L, block: () -> T?): T {
val deadline = System.currentTimeMillis() + timeoutMs
while (System.currentTimeMillis() < deadline) {
block()?.let { return it }
kotlinx.coroutines.delay(10)
}
return requireNotNull(block()) { "condition not met within ${timeoutMs}ms" }
}
private class MapBackedEventStore : EventStore {
val appendedEvents = mutableListOf<NewEvent>()
private val storedEvents: MutableMap<EventId, StoredEvent> = mutableMapOf()
private var nextSequence = 1L
// replay (not just extraBufferCapacity) so a collector that registers after an emit still
// receives it — otherwise there's a subscribe-vs-emit race with IdeaReader's launched collect.
private val liveEvents = MutableSharedFlow<StoredEvent>(replay = 1024)
override suspend fun append(event: NewEvent): StoredEvent {
appendedEvents.add(event)
@@ -1482,6 +1497,7 @@ class TalkieFacadeTest {
payload = event.payload,
)
storedEvents[event.metadata.eventId] = stored
liveEvents.tryEmit(stored)
return stored
}
@@ -1508,7 +1524,7 @@ class TalkieFacadeTest {
override fun allSessionIds(): Set<SessionId> = storedEvents.values.map { it.metadata.sessionId }.toSet()
override fun subscribeAll(): Flow<StoredEvent> = TODO("Not needed in this test context")
override fun subscribeAll(): Flow<StoredEvent> = liveEvents
override suspend fun lastGlobalSequence(): Long = TODO("Not needed in this test context")
}
@@ -45,6 +45,7 @@ class DecisionJournalReplayTest {
assertEquals(a, b)
assertTrue(a.contains("use jwt"))
assertTrue(a.contains("a → b"))
// TRANSITION records are bookkeeping — deliberately excluded from the render (see
// DecisionJournalRenderer.AGENT_RELEVANT_KINDS), so "a → b" is intentionally absent.
}
}