debt(pre-router): resolved most of the technical debt that was noted while finishing epic-12 and epic-13.

This commit is contained in:
2026-05-16 14:55:45 +04:00
parent 2207a37549
commit f77efce10b
10 changed files with 107 additions and 43 deletions
@@ -1,8 +1,11 @@
import com.correx.core.approvals.domain.ApprovalEngine
import com.correx.core.approvals.ApprovalOutcome
import com.correx.core.approvals.ApprovalStatus
import com.correx.core.approvals.Tier
import com.correx.core.approvals.domain.DefaultApprovalEngine
import com.correx.core.approvals.model.ApprovalContext
import com.correx.core.approvals.model.ApprovalGrant
import com.correx.core.approvals.model.DomainApprovalRequest
import com.correx.core.approvals.model.ApprovalDecision
import com.correx.core.approvals.model.ApprovalScopeIdentity
import com.correx.core.events.events.ApprovalRequestedEvent
import com.correx.core.events.events.OrchestrationPausedEvent
import com.correx.core.events.events.OrchestrationResumedEvent
import com.correx.core.events.events.WorkflowCompletedEvent
@@ -40,8 +43,11 @@ import com.correx.testing.fixtures.inference.MockInferenceProvider
import com.correx.testing.fixtures.transitions.TransitionFixtures
import com.correx.testing.fixtures.transitions.TransitionFixtures.threeStageGraph
import com.correx.testing.kernel.MockSessionEventReplayer
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.datetime.Instant
import kotlinx.coroutines.withTimeout
import kotlinx.coroutines.yield
import kotlinx.datetime.Clock
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNotNull
import org.junit.jupiter.api.Assertions.assertTrue
@@ -166,52 +172,71 @@ class SessionOrchestratorIntegrationTest {
retryCoordinator = retryCoordinator,
)
orchestrator.run(sessionId, graph, config)
val runJob = launch { orchestrator.run(sessionId, graph, config) }
withTimeout(5_000) {
while (eventStore.read(sessionId).none { it.payload is OrchestrationPausedEvent }) {
yield()
}
}
val events = eventStore.read(sessionId)
val orPause = events.find { it.payload is OrchestrationPausedEvent }
assertNotNull(orPause)
val paused = orPause?.let { it.payload as? OrchestrationPausedEvent }
assertEquals("APPROVAL_PENDING", paused?.reason)
runJob.cancel()
runJob.join()
}
@Test
fun `workflow resumes after approval`(): Unit = runBlocking {
val sessionId = SessionId("s4")
val config = OrchestrationConfig(
retryPolicy = RetryPolicy(maxAttempts = 3, backoffMs = 0),
)
val config = OrchestrationConfig(retryPolicy = RetryPolicy(maxAttempts = 3, backoffMs = 0))
val graph = threeStageGraph()
val yoloApprovalEngine = object : ApprovalEngine {
val inner = DefaultApprovalEngine()
override fun evaluate(
request: DomainApprovalRequest,
context: ApprovalContext,
grants: List<ApprovalGrant>,
now: Instant,
) =
inner.evaluate(request, ApprovalContext(context.identity, ApprovalMode.YOLO), grants, now)
}
val approvingPipeline = ValidationPipeline(
validators = listOf(cyclePolicyMissingValidator()),
approvalTrigger = ApprovalTrigger(),
)
val orchestrator = DefaultSessionOrchestrator(
val approvalOrchestrator = DefaultSessionOrchestrator(
repositories = repositories,
engines = engines.copy(
validationPipeline = approvingPipeline,
approvalEngine = yoloApprovalEngine,
),
engines = engines.copy(validationPipeline = approvingPipeline),
retryCoordinator = retryCoordinator,
)
orchestrator.run(sessionId, graph, config)
val runJob = launch { approvalOrchestrator.run(sessionId, graph, config) }
val requestId = withTimeout(5_000) {
var id: com.correx.core.events.types.ApprovalRequestId? = null
while (id == null) {
id = eventStore.read(sessionId)
.firstNotNullOfOrNull { it.payload as? ApprovalRequestedEvent }
?.requestId
if (id == null) yield()
}
id
}
val identity = ApprovalScopeIdentity(sessionId = sessionId, stageId = null, projectId = null)
val context = ApprovalContext(identity = identity, mode = ApprovalMode.PROMPT)
val decision = ApprovalDecision(
id = null,
requestId = requestId,
outcome = ApprovalOutcome.APPROVED,
state = ApprovalStatus.COMPLETED,
tier = Tier.T2,
contextSnapshot = context,
resolutionTimestamp = Clock.System.now(),
reason = null,
)
approvalOrchestrator.submitApprovalDecision(requestId, decision)
runJob.join()
val events = eventStore.read(sessionId)
val resumeCount = events.count { it.payload is OrchestrationResumedEvent }
assertEquals(1, resumeCount)
assertEquals(1, events.count { it.payload is OrchestrationResumedEvent })
assertNotNull(events.find { it.payload is WorkflowCompletedEvent })
}
@Test
@@ -297,4 +322,5 @@ class SessionOrchestratorIntegrationTest {
val state = orchestrationRepository.getState(sessionId)
assertEquals(7, state.retryPolicy?.maxAttempts)
}
}