refactor(detekt): extract magic-number constants, wrap long lines, drop legit suppressions

Mechanical detekt cleanup across apps/core/infrastructure (behavior-preserving):
- MagicNumber 62->10: named constants + removed 'legit' MagicNumber suppressions
  (Tier level from ordinal, ReplayInferenceProvider CHARS_PER_TOKEN, ConfigLoader
  DEFAULT_* consts, capability scores, HTTP ranges, column widths, etc.)
- MaxLineLength cut to ~0 in production modules (line wraps, no logic change)
- Dropped one dead parameter (ConfigLoader.parseArray lineNum)

Structural findings (ReturnCount/LongMethod/Complexity/LargeClass) left for a
deliberate decomposition pass. Full build + detekt gate green.
This commit is contained in:
2026-07-12 23:12:28 +04:00
parent 135a34eb2f
commit aee2e67c66
70 changed files with 1034 additions and 236 deletions
@@ -212,7 +212,12 @@ class ServerModule(
// Live-only: subscribeAll() replays nothing and ServerModule is never built under
// ReplayOrchestrator, so narration never re-fires on restart/replay (invariant #8).
NarrationSubscriber(eventStore = eventStore, routerFacade = routerFacade, scope = moduleScope, maxPerRun = narrationMaxPerRun).start()
NarrationSubscriber(
eventStore = eventStore,
routerFacade = routerFacade,
scope = moduleScope,
maxPerRun = narrationMaxPerRun,
).start()
// Continuous, edge-triggered health watch (observability-spec §4). Live-only like narration:
// probes read the environment and record degraded/restored events; replay reads those facts.
@@ -449,7 +454,10 @@ class ServerModule(
* TOML registry, so the resume route cannot find them there. Rehydrates the artifact
* cache first because the plan content lives in it after a restart.
*/
suspend fun freestyleResumeGraph(sessionId: SessionId, workflowId: String): com.correx.core.transitions.graph.WorkflowGraph? {
suspend fun freestyleResumeGraph(
sessionId: SessionId,
workflowId: String,
): com.correx.core.transitions.graph.WorkflowGraph? {
if (!workflowId.startsWith("freestyle-")) return null
orchestrator.rehydrate(sessionId)
return freestyleDriver?.compiledGraph(sessionId)
@@ -614,7 +622,11 @@ class ServerModule(
return@forEach
}
val graph = workflowRegistry.find(orchState.workflowId) ?: run {
log.warn("resumeAbandoned: no graph for session={} workflowId={}", sessionId.value, orchState.workflowId)
log.warn(
"resumeAbandoned: no graph for session={} workflowId={}",
sessionId.value,
orchState.workflowId,
)
return@forEach
}
log.info("resumeAbandoned: launching session={} workflow={}", sessionId.value, orchState.workflowId)
@@ -60,7 +60,8 @@ class LoggingEventStore(private val delegate: EventStore) : EventStore {
override fun subscribe(sessionId: SessionId): Flow<StoredEvent> = delegate.subscribe(sessionId)
override fun allEvents(): Sequence<StoredEvent> = delegate.allEvents()
override fun allSessionIds(): Set<SessionId> = delegate.allSessionIds().also { log.debug("got session ids from store: {}", it) }
override fun allSessionIds(): Set<SessionId> =
delegate.allSessionIds().also { log.debug("got session ids from store: {}", it) }
override fun subscribeAll(): Flow<StoredEvent> = delegate.subscribeAll()
@@ -143,14 +143,28 @@ class RepoMapIndexer(
// Top-level declarations only — best-effort per language. Bodies/locals are never matched.
val SYMBOL_PATTERNS: Map<String, Regex> = mapOf(
"kt" to Regex("""(?m)^\s*(?:public |internal |open |abstract |sealed |data )*(?:class|interface|object|fun)\s+(?<name>[A-Za-z_][A-Za-z0-9_]*)"""),
"java" to Regex("""(?m)^\s*(?:public |private |protected |final |abstract |static )*(?:class|interface|enum|record)\s+(?<name>[A-Za-z_][A-Za-z0-9_]*)"""),
"kt" to Regex(
"""(?m)^\s*(?:public |internal |open |abstract |sealed |data )*""" +
"""(?:class|interface|object|fun)\s+(?<name>[A-Za-z_][A-Za-z0-9_]*)""",
),
"java" to Regex(
"""(?m)^\s*(?:public |private |protected |final |abstract |static )*""" +
"""(?:class|interface|enum|record)\s+(?<name>[A-Za-z_][A-Za-z0-9_]*)""",
),
"py" to Regex("""(?m)^(?:def|class)\s+(?<name>[A-Za-z_][A-Za-z0-9_]*)"""),
"go" to Regex("""(?m)^\s*(?:func\s+(?:\([^)]*\)\s*)?|type\s+)(?<name>[A-Za-z_][A-Za-z0-9_]*)"""),
"js" to Regex("""(?m)^\s*(?:export\s+)?(?:default\s+)?(?:async\s+)?(?:function|class)\s+(?<name>[A-Za-z_$][A-Za-z0-9_$]*)"""),
"ts" to Regex("""(?m)^\s*(?:export\s+)?(?:default\s+)?(?:async\s+)?(?:function|class|interface|type|enum)\s+(?<name>[A-Za-z_$][A-Za-z0-9_$]*)"""),
"js" to Regex(
"""(?m)^\s*(?:export\s+)?(?:default\s+)?(?:async\s+)?(?:function|class)\s+""" +
"""(?<name>[A-Za-z_$][A-Za-z0-9_$]*)""",
),
"ts" to Regex(
"""(?m)^\s*(?:export\s+)?(?:default\s+)?(?:async\s+)?(?:function|class|interface|type|enum)\s+""" +
"""(?<name>[A-Za-z_$][A-Za-z0-9_$]*)""",
),
// GDScript: column-0 declarations only, so indented inner-class members never match.
"gd" to Regex("""(?m)^(?:static\s+)?(?:func|class_name|class|signal|enum)\s+(?<name>[A-Za-z_][A-Za-z0-9_]*)"""),
"gd" to Regex(
"""(?m)^(?:static\s+)?(?:func|class_name|class|signal|enum)\s+(?<name>[A-Za-z_][A-Za-z0-9_]*)""",
),
// C# / Godot Mono: top-level type declarations with leading modifiers, kept conservative
// (no method capture — return-type heuristics there are noisy and risk false positives).
"cs" to Regex(
@@ -116,11 +116,13 @@ class NarrationSubscriber(
closeLane(sid)
}
is WorkflowFailedEvent -> {
val instruction = "The workflow failed in stage ${p.stageId.value}: ${p.reason}. " +
"Explain the failure to the user."
enqueue(
sid,
NarrationTrigger(
kind = "workflow_failed",
instruction = "The workflow failed in stage ${p.stageId.value}: ${p.reason}. Explain the failure to the user.",
instruction = instruction,
stageId = p.stageId.value,
),
)
@@ -139,21 +141,27 @@ class NarrationSubscriber(
),
)
}
is ExecutionPlanRejectedEvent -> enqueue(
sid,
NarrationTrigger(
kind = "plan_rejected",
instruction = "The execution plan was rejected (${p.source}): ${p.reason}. Explain to the user what happened and what they can do next.",
),
)
is ExecutionPlanRejectedEvent -> {
val instruction = "The execution plan was rejected (${p.source}): ${p.reason}. " +
"Explain to the user what happened and what they can do next."
enqueue(
sid,
NarrationTrigger(
kind = "plan_rejected",
instruction = instruction,
),
)
}
is OrchestrationPausedEvent -> {
// Approval pauses are narrated from ApprovalRequestedEvent above.
if (!p.reason.contains("APPROVAL", ignoreCase = true)) {
val instruction = "Orchestration paused in stage ${p.stageId.value}: ${p.reason}. " +
"Inform the user."
enqueue(
sid,
NarrationTrigger(
kind = "paused",
instruction = "Orchestration paused in stage ${p.stageId.value}: ${p.reason}. Inform the user.",
instruction = instruction,
stageId = p.stageId.value,
),
pauseKey = SESSION_PAUSE_KEY,
@@ -63,20 +63,49 @@ class ReplayInspectionService(private val eventStore: EventStore) {
private fun toTimelineEntry(sequence: Long, payload: EventPayload, type: String): TimelineEntry =
when (payload) {
is WorkflowStartedEvent -> TimelineEntry(sequence, type, payload.startStageId.value, "Workflow started: ${payload.workflowId}")
is StageCompletedEvent -> TimelineEntry(sequence, type, payload.stageId.value, "Stage completed: ${payload.stageId.value}")
is StageFailedEvent -> TimelineEntry(sequence, type, payload.stageId.value, "Stage failed: ${payload.stageId.value}${payload.reason}")
is WorkflowStartedEvent ->
TimelineEntry(sequence, type, payload.startStageId.value, "Workflow started: ${payload.workflowId}")
is StageCompletedEvent ->
TimelineEntry(sequence, type, payload.stageId.value, "Stage completed: ${payload.stageId.value}")
is StageFailedEvent -> TimelineEntry(
sequence, type, payload.stageId.value, "Stage failed: ${payload.stageId.value}${payload.reason}",
)
is ToolExecutionCompletedEvent -> TimelineEntry(sequence, type, null, "Tool executed: ${payload.toolName}")
is ToolExecutionFailedEvent -> TimelineEntry(sequence, type, null, "Tool failed: ${payload.toolName}${payload.reason}")
is ToolExecutionRejectedEvent -> TimelineEntry(sequence, type, null, "Tool rejected: ${payload.toolName}${payload.reason}")
is ApprovalRequestedEvent -> TimelineEntry(sequence, type, payload.stageId?.value, "Approval requested: tier ${payload.tier}")
is ApprovalDecisionResolvedEvent -> TimelineEntry(sequence, type, null, "Approval resolved: ${payload.outcome}")
is OrchestrationPausedEvent -> TimelineEntry(sequence, type, payload.stageId.value, "Orchestration paused at ${payload.stageId.value}: ${payload.reason}")
is OrchestrationResumedEvent -> TimelineEntry(sequence, type, payload.stageId.value, "Orchestration resumed at ${payload.stageId.value}")
is RetryAttemptedEvent -> TimelineEntry(sequence, type, payload.stageId.value, "Retry attempt ${payload.attemptNumber}/${payload.maxAttempts} at ${payload.stageId.value}: ${payload.failureReason}")
is TransitionExecutedEvent -> TimelineEntry(sequence, type, payload.from.value, "Transition ${payload.from.value} ${payload.to.value}")
is WorkflowCompletedEvent -> TimelineEntry(sequence, type, payload.terminalStageId.value, "Workflow completed after ${payload.totalStages} stages")
is WorkflowFailedEvent -> TimelineEntry(sequence, type, payload.stageId.value, "Workflow failed: ${payload.reason}")
is ToolExecutionFailedEvent ->
TimelineEntry(sequence, type, null, "Tool failed: ${payload.toolName}${payload.reason}")
is ToolExecutionRejectedEvent ->
TimelineEntry(sequence, type, null, "Tool rejected: ${payload.toolName}${payload.reason}")
is ApprovalRequestedEvent ->
TimelineEntry(sequence, type, payload.stageId?.value, "Approval requested: tier ${payload.tier}")
is ApprovalDecisionResolvedEvent ->
TimelineEntry(sequence, type, null, "Approval resolved: ${payload.outcome}")
is OrchestrationPausedEvent -> TimelineEntry(
sequence,
type,
payload.stageId.value,
"Orchestration paused at ${payload.stageId.value}: ${payload.reason}",
)
is OrchestrationResumedEvent -> TimelineEntry(
sequence, type, payload.stageId.value, "Orchestration resumed at ${payload.stageId.value}",
)
is RetryAttemptedEvent -> TimelineEntry(
sequence,
type,
payload.stageId.value,
"Retry attempt ${payload.attemptNumber}/${payload.maxAttempts} at " +
"${payload.stageId.value}: ${payload.failureReason}",
)
is TransitionExecutedEvent -> TimelineEntry(
sequence, type, payload.from.value, "Transition ${payload.from.value}${payload.to.value}",
)
is WorkflowCompletedEvent -> TimelineEntry(
sequence,
type,
payload.terminalStageId.value,
"Workflow completed after ${payload.totalStages} stages",
)
is WorkflowFailedEvent ->
TimelineEntry(sequence, type, payload.stageId.value, "Workflow failed: ${payload.reason}")
else -> TimelineEntry(sequence, type, null, type)
}
@@ -566,7 +566,8 @@ class GlobalStreamHandler(private val module: ServerModule) {
suspend fun requireToolName(scopeLabel: String): String? =
msg.toolName?.takeIf { it.isNotBlank() }
?: run {
sendFrame(errorResponse("CreateGrant: $scopeLabel scope requires toolName to prevent blanket approval"))
val errMsg = "CreateGrant: $scopeLabel scope requires toolName to prevent blanket approval"
sendFrame(errorResponse(errMsg))
null
}
@@ -683,7 +684,9 @@ class GlobalStreamHandler(private val module: ServerModule) {
// Bind the per-repo project profile so router triage can cite conventions/commands.
// Parity with launchSessionRun — chat sessions previously never bound a profile.
runCatching { module.bindProjectProfile(sessionId) }
.onFailure { log.warn("project profile binding failed for chat session={}: {}", sessionId.value, it.message) }
.onFailure {
log.warn("project profile binding failed for chat session={}: {}", sessionId.value, it.message)
}
withSessionContext(sessionId) {
runCatching {
@@ -102,7 +102,12 @@ class SessionStreamHandler(private val module: ServerModule) {
),
)
}.onFailure {
log.error("routerFacade.onUserInput failed for session={}: {}", msg.sessionId.value, it.message, it)
log.error(
"routerFacade.onUserInput failed for session={}: {}",
msg.sessionId.value,
it.message,
it,
)
val error = ServerMessage.ProtocolError("Router error: ${it.message}")
session.send(Frame.Text(ProtocolSerializer.encodeServerMessage(error)))
}
@@ -325,7 +325,9 @@ class DomainEventMapperTest {
)
val result = domainEventToServerMessage(event, noopStore, sessionSequence = 0L)
assertEquals(
ServerMessage.ToolStarted(sessionId, "file_write", Tier.T2, sequence = event.sequence, sessionSequence = 0L),
ServerMessage.ToolStarted(
sessionId, "file_write", Tier.T2, sequence = event.sequence, sessionSequence = 0L,
),
result,
)
}
@@ -436,7 +438,8 @@ class DomainEventMapperTest {
projectId = null,
),
)
val result = domainEventToServerMessage(event, noopStore, sessionSequence = 0L) as ServerMessage.ApprovalRequired
val result =
domainEventToServerMessage(event, noopStore, sessionSequence = 0L) as ServerMessage.ApprovalRequired
assertEquals(requestId, result.requestId)
assertEquals(Tier.T3, result.tier)
assertNull(result.toolName)
@@ -470,11 +473,15 @@ class DomainEventMapperTest {
projectId = null,
),
)
val result = domainEventToServerMessage(event, noopStore, sessionSequence = 0L) as ServerMessage.ApprovalRequired
val result =
domainEventToServerMessage(event, noopStore, sessionSequence = 0L) as ServerMessage.ApprovalRequired
assertEquals(requestId, result.requestId)
assertEquals("HIGH", result.riskSummary.level)
assertEquals("PROMPT_USER", result.riskSummary.recommendedAction)
assertEquals(listOf("[ERR001] Schema mismatch", "[ERR002] Missing required field"), result.riskSummary.rationale)
assertEquals(
listOf("[ERR001] Schema mismatch", "[ERR002] Missing required field"),
result.riskSummary.rationale,
)
assertEquals(2, result.riskSummary.factors.size)
assertTrue(result.riskSummary.factors[0].contains("Validation errors"))
assertTrue(result.riskSummary.factors[1].contains("Repeated failure"))
@@ -495,7 +502,8 @@ class DomainEventMapperTest {
userSteering = null,
),
)
val result = domainEventToServerMessage(event, noopStore, sessionSequence = 5L) as ServerMessage.ApprovalResolved
val result =
domainEventToServerMessage(event, noopStore, sessionSequence = 5L) as ServerMessage.ApprovalResolved
assertEquals(sessionId, result.sessionId)
assertEquals(requestId, result.requestId)
assertEquals("APPROVED", result.outcome)
@@ -519,7 +527,8 @@ class DomainEventMapperTest {
userSteering = null,
),
)
val result = domainEventToServerMessage(event, noopStore, sessionSequence = 0L) as ServerMessage.ApprovalResolved
val result =
domainEventToServerMessage(event, noopStore, sessionSequence = 0L) as ServerMessage.ApprovalResolved
assertEquals("REJECTED", result.outcome)
assertNull(result.reason)
}
@@ -325,8 +325,14 @@ class SessionEventBridgeTest {
val snapshot = sent[0] as ServerMessage.SessionSnapshot
// WorkflowStartedEvent is filtered out by eventToEntry (maps to null)
assertEquals(3, snapshot.recentEvents.size)
assertEquals(EventEntryDto(timestamp.toEpochMilliseconds(), "StageStarted", "stage-2"), snapshot.recentEvents[0])
assertEquals(EventEntryDto(timestamp.toEpochMilliseconds(), "StageCompleted", stageId.value), snapshot.recentEvents[1])
assertEquals(
EventEntryDto(timestamp.toEpochMilliseconds(), "StageStarted", "stage-2"),
snapshot.recentEvents[0],
)
assertEquals(
EventEntryDto(timestamp.toEpochMilliseconds(), "StageCompleted", stageId.value),
snapshot.recentEvents[1],
)
assertEquals(EventEntryDto(timestamp.toEpochMilliseconds(), "SessionCompleted", ""), snapshot.recentEvents[2])
}
@@ -359,7 +365,13 @@ class SessionEventBridgeTest {
fun `replaySnapshot with no sessions emits only SnapshotComplete`() = runTest {
val store = fakeEventStore(allEventsList = emptyList())
val sent = mutableListOf<ServerMessage>()
val bridge = SessionEventBridge(store, noopArtifactStore, activeOrchestrationRepository(), noopWorkflowRegistry, noopToolRegistry) { sent.add(it) }
val bridge = SessionEventBridge(
store,
noopArtifactStore,
activeOrchestrationRepository(),
noopWorkflowRegistry,
noopToolRegistry,
) { sent.add(it) }
bridge.replaySnapshot()
assertEquals(1, sent.size)
assertEquals(ServerMessage.SnapshotComplete, sent[0])
@@ -370,7 +382,13 @@ class SessionEventBridgeTest {
val events = listOf(storedEvent(WorkflowStartedEvent(sessionId, workflowId, stageId), seq = 1L))
val store = fakeEventStore(allEventsList = events)
val sent = mutableListOf<ServerMessage>()
val bridge = SessionEventBridge(store, noopArtifactStore, activeOrchestrationRepository(), noopWorkflowRegistry, noopToolRegistry) { sent.add(it) }
val bridge = SessionEventBridge(
store,
noopArtifactStore,
activeOrchestrationRepository(),
noopWorkflowRegistry,
noopToolRegistry,
) { sent.add(it) }
bridge.replaySnapshot()
assertEquals(ServerMessage.SnapshotComplete, sent.last())
}
@@ -385,7 +403,13 @@ class SessionEventBridgeTest {
override suspend fun lastGlobalSequence(): Long = 5L
}
val sent = mutableListOf<ServerMessage>()
val bridge = SessionEventBridge(store, noopArtifactStore, activeOrchestrationRepository(), noopWorkflowRegistry, noopToolRegistry) { sent.add(it) }
val bridge = SessionEventBridge(
store,
noopArtifactStore,
activeOrchestrationRepository(),
noopWorkflowRegistry,
noopToolRegistry,
) { sent.add(it) }
bridge.replaySnapshot()
val snapshot = sent[0] as ServerMessage.SessionSnapshot
assertEquals(5L, snapshot.lastSequence)
@@ -399,7 +423,13 @@ class SessionEventBridgeTest {
)
val store = fakeEventStore(allEventsList = events)
val sent = mutableListOf<ServerMessage>()
val bridge = SessionEventBridge(store, noopArtifactStore, activeOrchestrationRepository(), noopWorkflowRegistry, noopToolRegistry) { sent.add(it) }
val bridge = SessionEventBridge(
store,
noopArtifactStore,
activeOrchestrationRepository(),
noopWorkflowRegistry,
noopToolRegistry,
) { sent.add(it) }
bridge.replaySnapshot()
val snapshot = sent[0] as ServerMessage.SessionSnapshot
assertEquals(3L, snapshot.lastSessionSequence)
@@ -257,7 +257,10 @@ class FreestyleDriverTest {
assertFalse(approvalRequested, "operator must not be asked to approve a plan that already failed lint")
val lint = payloads.filterIsInstance<PlanLintCompletedEvent>().single()
assertTrue(lint.hardFailures.any { it.code == "unproduced_need" }, "expected unproduced_need: ${lint.hardFailures}")
assertTrue(
lint.hardFailures.any { it.code == "unproduced_need" },
"expected unproduced_need: ${lint.hardFailures}",
)
val rejected = payloads.filterIsInstance<ExecutionPlanRejectedEvent>().single()
assertEquals("lint", rejected.source)
@@ -175,7 +175,8 @@ class ModelLifecycleLiveTest {
val raw = frame.readText()
when (val msg = decodeServerMessage(raw)) {
is ServerMessage.ModelChanged -> modelChanged = msg
is ServerMessage.ProtocolError -> error("Unexpected protocol error during swap: ${msg.message}")
is ServerMessage.ProtocolError ->
error("Unexpected protocol error during swap: ${msg.message}")
else -> Unit
}
}
@@ -29,7 +29,11 @@ private class OnesEmbedder(override val dimension: Int = 8) : Embedder {
class ProjectMemoryServiceTest {
private fun store(sessionId: SessionId, payload: com.correx.core.events.events.EventPayload, es: InMemoryEventStore) =
private fun store(
sessionId: SessionId,
payload: com.correx.core.events.events.EventPayload,
es: InMemoryEventStore,
) =
runBlocking {
es.append(
NewEvent(
@@ -58,7 +62,11 @@ class ProjectMemoryServiceTest {
val sessionA = SessionId("A")
store(sessionA, SteeringNoteAddedEvent(sessionA, "use jwt for auth"), eventStore)
store(sessionA, TransitionExecutedEvent(sessionA, StageId("plan"), StageId("impl"), TransitionId("t1")), eventStore)
store(
sessionA,
TransitionExecutedEvent(sessionA, StageId("plan"), StageId("impl"), TransitionId("t1")),
eventStore,
)
service(config, eventStore, l3).persist(sessionA, "/repo")
@@ -67,7 +75,10 @@ class ProjectMemoryServiceTest {
assertTrue(seeded.any { it.contains("use jwt for auth") }, "expected prior decision retrieved")
val note = eventStore.read(sessionB).mapNotNull { it.payload as? SteeringNoteAddedEvent }.firstOrNull()
assertTrue(note != null && note.content.contains("Project memory"), "expected seeded steering note in session B")
assertTrue(
note != null && note.content.contains("Project memory"),
"expected seeded steering note in session B",
)
}
@Test
@@ -109,7 +109,9 @@ class NarrationSubscriberTest {
liveFlow.emit(storedEvent(WorkflowStartedEvent(sessionId, "wf", StageId("s0")), seq = 1L))
liveFlow.emit(storedEvent(StageCompletedEvent(sessionId, StageId("a"), TransitionId("t1")), seq = 2L))
liveFlow.emit(storedEvent(StageFailedEvent(sessionId, StageId("b"), TransitionId("t2"), reason = "x"), seq = 3L))
liveFlow.emit(
storedEvent(StageFailedEvent(sessionId, StageId("b"), TransitionId("t2"), reason = "x"), seq = 3L),
)
liveFlow.emit(storedEvent(WorkflowCompletedEvent(sessionId, StageId("c"), totalStages = 2), seq = 4L))
withTimeout(2_000L) {
@@ -282,7 +282,9 @@ class ServerMessageSerializationTest {
val jsonStr = ProtocolSerializer.encodeServerMessage(msg)
assert(jsonStr.contains("\"type\":\"workflow.proposed\"")) { "expected type=workflow.proposed" }
assert(jsonStr.contains("\"workflowId\":\"research\"")) { "expected candidate id" }
assert(jsonStr.contains("\"originalRequest\":\"find papers on event sourcing\"")) { "expected original request" }
assert(
jsonStr.contains("\"originalRequest\":\"find papers on event sourcing\""),
) { "expected original request" }
val decoded = json.decodeFromString<ServerMessage.WorkflowProposed>(jsonStr)
assertEquals(2, decoded.candidates.size)
@@ -56,8 +56,10 @@ class FileSystemWorkflowRegistryTest {
@Test
fun `listAll falls back to workflowId when description absent`() {
dir.resolve("healthcheck.toml").writeText(validToml.replace("description = \"Runs the health check pipeline\"\n", ""))
assertEquals("healthcheck", FileSystemWorkflowRegistry(TomlWorkflowLoader(), dir).listAll().single().description)
val noDescToml = validToml.replace("description = \"Runs the health check pipeline\"\n", "")
dir.resolve("healthcheck.toml").writeText(noDescToml)
val registry = FileSystemWorkflowRegistry(TomlWorkflowLoader(), dir)
assertEquals("healthcheck", registry.listAll().single().description)
}
@Test
@@ -87,10 +87,12 @@ class ReplayInspectionServiceTest {
private class SeededEventStore(private val events: List<StoredEvent>) : EventStore {
override suspend fun append(event: NewEvent): StoredEvent = error("unused")
override suspend fun appendAll(events: List<NewEvent>): List<StoredEvent> = error("unused")
override fun read(sessionId: SessionId): List<StoredEvent> = events.filter { it.metadata.sessionId == sessionId }
override fun read(sessionId: SessionId): List<StoredEvent> =
events.filter { it.metadata.sessionId == sessionId }
override fun readFrom(sessionId: SessionId, fromSequence: Long): List<StoredEvent> =
events.filter { it.metadata.sessionId == sessionId && it.sequence >= fromSequence }
override fun lastSequence(sessionId: SessionId): Long? = events.filter { it.metadata.sessionId == sessionId }.lastOrNull()?.sequence
override fun lastSequence(sessionId: SessionId): Long? =
events.filter { it.metadata.sessionId == sessionId }.lastOrNull()?.sequence
override fun subscribe(sessionId: SessionId): Flow<StoredEvent> = emptyFlow()
override fun subscribeAll(): Flow<StoredEvent> = emptyFlow()
override suspend fun lastGlobalSequence(): Long = 0L
@@ -86,18 +86,26 @@ class EventInspectRoutesTest {
)
private val seedEvents = listOf(
storedEvent(WorkspaceStateObservedEvent(sessionId = s1, workspaceRoot = "/repo", stateKey = "git:abc", source = "git"), 1L),
storedEvent(WorkspaceStateObservedEvent(sessionId = s1, workspaceRoot = "/repo", stateKey = "git:def", source = "git"), 2L),
storedEvent(
WorkspaceStateObservedEvent(sessionId = s1, workspaceRoot = "/repo", stateKey = "git:abc", source = "git"),
1L,
),
storedEvent(
WorkspaceStateObservedEvent(sessionId = s1, workspaceRoot = "/repo", stateKey = "git:def", source = "git"),
2L,
),
storedEvent(InitialIntentEvent(sessionId = s1, intent = "build the thing"), 3L),
)
private class SeededEventStore(private val events: List<StoredEvent>) : EventStore {
override suspend fun append(event: NewEvent): StoredEvent = error("unused")
override suspend fun appendAll(events: List<NewEvent>): List<StoredEvent> = error("unused")
override fun read(sessionId: SessionId): List<StoredEvent> = events.filter { it.metadata.sessionId == sessionId }
override fun read(sessionId: SessionId): List<StoredEvent> =
events.filter { it.metadata.sessionId == sessionId }
override fun readFrom(sessionId: SessionId, fromSequence: Long): List<StoredEvent> =
events.filter { it.metadata.sessionId == sessionId && it.sequence >= fromSequence }
override fun lastSequence(sessionId: SessionId): Long? = events.filter { it.metadata.sessionId == sessionId }.lastOrNull()?.sequence
override fun lastSequence(sessionId: SessionId): Long? =
events.filter { it.metadata.sessionId == sessionId }.lastOrNull()?.sequence
override fun subscribe(sessionId: SessionId): Flow<StoredEvent> = emptyFlow()
override fun subscribeAll(): Flow<StoredEvent> = emptyFlow()
override suspend fun lastGlobalSequence(): Long = 0L
@@ -180,7 +180,11 @@ class SessionUndoServiceTest {
val noWorkspaceEventStore = FakeEventStore(listOf(storedEvent(fileWritten, sessionId, 1L)))
val serviceBootOnly = SessionUndoService(noWorkspaceEventStore, storeNoWorkspace, setOf(bootDir))
val summaryBootOnly = serviceBootOnly.undo(sessionId)
assertEquals(1, summaryBootOnly.rejected, "boot-only roots must jail the workspace-dir file when no bound event exists")
assertEquals(
1,
summaryBootOnly.rejected,
"boot-only roots must jail the workspace-dir file when no bound event exists",
)
}
/**
@@ -121,7 +121,13 @@ class GlobalStreamHandlerTest {
orchRepo: OrchestrationRepository,
): Pair<SessionEventBridge, Channel<ServerMessage>> {
val received = Channel<ServerMessage>(Channel.UNLIMITED)
val bridge = SessionEventBridge(store, noopArtifactStore, orchRepo, noopWorkflowRegistry, noopToolRegistry) { received.send(it) }
val bridge = SessionEventBridge(
store,
noopArtifactStore,
orchRepo,
noopWorkflowRegistry,
noopToolRegistry,
) { received.send(it) }
return bridge to received
}
@@ -167,7 +173,13 @@ class GlobalStreamHandlerTest {
val liveFlow = MutableSharedFlow<StoredEvent>(extraBufferCapacity = 64)
val store = fakeEventStore(liveFlow, emptySet(), lastGlobal = 5L)
val received = Channel<ServerMessage>(Channel.UNLIMITED)
val bridge = SessionEventBridge(store, noopArtifactStore, idleOrchestrationRepository(), noopWorkflowRegistry, noopToolRegistry) {
val bridge = SessionEventBridge(
store,
noopArtifactStore,
idleOrchestrationRepository(),
noopWorkflowRegistry,
noopToolRegistry,
) {
received.send(it)
}
val mapper = DomainEventMapper(noopArtifactStore)
@@ -209,7 +221,13 @@ class GlobalStreamHandlerTest {
val liveFlow = MutableSharedFlow<StoredEvent>(extraBufferCapacity = 16)
val store = fakeEventStore(liveFlow, emptySet(), lastGlobal = 0L)
val received = Channel<ServerMessage>(Channel.UNLIMITED)
val bridge = SessionEventBridge(store, noopArtifactStore, idleOrchestrationRepository(), noopWorkflowRegistry, noopToolRegistry) {
val bridge = SessionEventBridge(
store,
noopArtifactStore,
idleOrchestrationRepository(),
noopWorkflowRegistry,
noopToolRegistry,
) {
received.send(it)
}
val mapper = DomainEventMapper(noopArtifactStore)
@@ -257,7 +275,13 @@ class GlobalStreamHandlerTest {
return 0L
}
}
val bridge = SessionEventBridge(store, noopArtifactStore, idleOrchestrationRepository(), noopWorkflowRegistry, noopToolRegistry) { }
val bridge = SessionEventBridge(
store,
noopArtifactStore,
idleOrchestrationRepository(),
noopWorkflowRegistry,
noopToolRegistry,
) { }
val mapper = DomainEventMapper(noopArtifactStore)
val job = launch {
@@ -274,7 +298,13 @@ class GlobalStreamHandlerTest {
fun `shutdown - cancel outer scope ends subscription with no leaks`() = runTest {
val liveFlow = MutableSharedFlow<StoredEvent>()
val store = fakeEventStore(liveFlow, emptySet(), lastGlobal = 0L)
val bridge = SessionEventBridge(store, noopArtifactStore, idleOrchestrationRepository(), noopWorkflowRegistry, noopToolRegistry) { }
val bridge = SessionEventBridge(
store,
noopArtifactStore,
idleOrchestrationRepository(),
noopWorkflowRegistry,
noopToolRegistry,
) { }
val mapper = DomainEventMapper(noopArtifactStore)
val job = launch {
@@ -250,7 +250,8 @@ class WorkspaceHandshakeTest {
delay(50)
// Phase 2: start a session
send(Frame.Text(encode(ClientMessage.StartSession(workflowId = "handshake-test-workflow", config = null))))
val startMsg = ClientMessage.StartSession(workflowId = "handshake-test-workflow", config = null)
send(Frame.Text(encode(startMsg)))
// Give the server time to process the event emission (before orchestrator runs)
delay(200)
@@ -298,7 +299,8 @@ class WorkspaceHandshakeTest {
delay(50)
// StartSession — this closes the Hello window
send(Frame.Text(encode(ClientMessage.StartSession(workflowId = "handshake-test-workflow", config = null))))
val startMsg = ClientMessage.StartSession(workflowId = "handshake-test-workflow", config = null)
send(Frame.Text(encode(startMsg)))
delay(100)
// Late Hello with a different path — must be ignored
@@ -334,7 +336,8 @@ class WorkspaceHandshakeTest {
delay(100)
// No Hello — send StartSession directly
send(Frame.Text(encode(ClientMessage.StartSession(workflowId = "handshake-test-workflow", config = null))))
val startMsg = ClientMessage.StartSession(workflowId = "handshake-test-workflow", config = null)
send(Frame.Text(encode(startMsg)))
delay(200)
}
}