epic-12: after epic audit and init commit

This commit is contained in:
2026-05-16 11:42:00 +04:00
commit c77277af0b
461 changed files with 28958 additions and 0 deletions
@@ -0,0 +1,71 @@
import com.correx.core.events.types.StageId
import com.correx.core.events.types.TransitionId
import com.correx.core.transitions.graph.StageConfig
import com.correx.core.transitions.graph.TransitionEdge
import com.correx.core.transitions.graph.WorkflowGraph
import com.correx.core.transitions.resolution.TransitionOrdering
import com.correx.core.validation.approval.ApprovalTrigger
import com.correx.core.validation.graph.GraphValidator
import com.correx.core.validation.model.ValidationContext
import com.correx.core.validation.pipeline.ValidationOutcome
import com.correx.core.validation.pipeline.ValidationPipeline
import com.correx.core.validation.semantic.SemanticValidator
import com.correx.core.validation.semantic.rules.CyclePolicyBindingRule
import com.correx.core.validation.transition.TransitionValidator
import com.correx.testing.fixtures.CycleFixtures
import com.correx.testing.fixtures.WorkflowFixtures
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertInstanceOf
import org.junit.jupiter.api.Test
class ValidationPipelineIntegrationTest {
private val pipeline = ValidationPipeline(
validators = listOf(
GraphValidator(),
TransitionValidator(TransitionOrdering.comparator),
SemanticValidator(
rules = listOf(
CyclePolicyBindingRule(requirePolicyForCycles = true),
),
),
),
approvalTrigger = ApprovalTrigger()
)
@Test
fun `full validation pipeline returns NeedsApproval when cycles are unbound`() {
val graph = WorkflowFixtures.simpleGraph()
val cycles = listOf(CycleFixtures.simpleCycle())
val context = ValidationContext(
graph = graph,
detectedCycles = cycles,
cyclePolicies = emptySet(),
)
val outcome = pipeline.validate(context)
assertInstanceOf(ValidationOutcome.NeedsApproval::class.java, outcome)
}
@Test
fun `rejected outcome retryable is false — set by validator, not orchestrator`() {
// A dangling transition triggers GraphValidator ERROR → Rejected(retryable=false).
// Ownership rule: the validator sets retryable; the orchestrator must only read it.
val a = StageId("A")
val ghost = StageId("GHOST")
val graphWithDanglingTransition = WorkflowGraph(
stages = mapOf(a to StageConfig()),
transitions = setOf(TransitionEdge(TransitionId("t1"), from = a, to = ghost) { true }),
start = a,
)
val pipeline = ValidationPipeline(validators = listOf(GraphValidator()), approvalTrigger = null)
val outcome = pipeline.validate(ValidationContext(graph = graphWithDanglingTransition))
assertInstanceOf(ValidationOutcome.Rejected::class.java, outcome)
assertFalse((outcome as ValidationOutcome.Rejected).retryable)
}
}