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
+15
View File
@@ -0,0 +1,15 @@
plugins {
id 'java-library'
id 'org.jetbrains.kotlin.jvm'
id 'org.jetbrains.kotlin.plugin.serialization'
}
dependencies {
testImplementation(project(":core:events"))
testImplementation(project(":core:sessions"))
testImplementation(project(":core:transitions"))
testImplementation(project(":core:validation"))
testImplementation(project(":core:approvals"))
testImplementation(project(":infrastructure:persistence"))
testImplementation(project(":testing:fixtures"))
}
@@ -0,0 +1,3 @@
package com.correx.testing.approvals
object Module
@@ -0,0 +1,88 @@
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.ApprovalScopeIdentity
import com.correx.core.approvals.ApprovalStatus
import com.correx.core.approvals.GrantScope
import com.correx.core.events.types.GrantId
import com.correx.core.events.types.ProjectId
import com.correx.core.events.types.SessionId
import com.correx.core.events.types.StageId
import com.correx.core.sessions.ApprovalMode
import com.correx.testing.fixtures.request
import kotlinx.datetime.Instant
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
class ApprovalEngineEdgeCasesTest {
private val engine = DefaultApprovalEngine()
private val now = Instant.parse("2026-01-01T00:00:01Z")
private fun context(mode: ApprovalMode) = ApprovalContext(
ApprovalScopeIdentity(SessionId("s1"), StageId("st1"), ProjectId("p1")),
mode
)
@Test
fun `grants from different scopes apply only to matching identity`() {
val sessionGrant = ApprovalGrant(
id = GrantId("g1"),
scope = GrantScope.SESSION,
permittedTiers = setOf(Tier.T3),
reason = "",
timestamp = Instant.parse("2026-01-01T00:00:00Z")
)
val stageGrant = ApprovalGrant(
id = GrantId("g2"),
scope = GrantScope.STAGE(StageId("st2")),
permittedTiers = setOf(Tier.T4),
reason = "",
timestamp = Instant.parse("2026-01-01T00:00:00Z")
)
val decision = engine.evaluate(
request("r1", Tier.T4),
context(ApprovalMode.DENY),
listOf(sessionGrant, stageGrant),
now
)
assertEquals(
ApprovalStatus.PENDING, decision.state,
"Stage grant for different stage should not apply"
)
}
@Test
fun `expired grant is ignored`() {
val past = Instant.parse("2025-12-31T23:59:59Z")
val expiredGrant = ApprovalGrant(
id = GrantId("g1"),
scope = GrantScope.SESSION,
permittedTiers = setOf(Tier.T2),
reason = "",
timestamp = past,
expiresAt = past // expired before 'now'
)
val decision = engine.evaluate(
request("r1", Tier.T2),
context(ApprovalMode.DENY),
listOf(expiredGrant),
now
)
assertEquals(ApprovalStatus.PENDING, decision.state)
}
@Test
fun `timestamp passed to evaluate is used as resolution timestamp`() {
val myNow = Instant.parse("2026-07-01T12:00:00Z")
val decision = engine.evaluate(
request("r1", Tier.T0),
context(ApprovalMode.YOLO),
emptyList(),
myNow
)
assertEquals(myNow, decision.resolutionTimestamp)
}
}
@@ -0,0 +1,50 @@
import com.correx.core.validation.approval.ApprovalTrigger
import com.correx.core.validation.model.ValidationIssue
import com.correx.core.validation.model.ValidationReport
import com.correx.core.validation.model.ValidationSection
import com.correx.core.validation.model.ValidationSeverity
import org.junit.jupiter.api.Assertions.assertNotNull
import org.junit.jupiter.api.Assertions.assertNull
import org.junit.jupiter.api.Test
class ApprovalTriggerTest {
private val trigger = ApprovalTrigger()
@Test
fun `should trigger approval on error`() {
val report = ValidationReport(
sections = listOf(
ValidationSection(
name = "graph",
issues = listOf(
ValidationIssue(
code = "GRAPH_DANGLING_TRANSITION",
message = "error",
severity = ValidationSeverity.ERROR,
),
),
),
),
)
val result = trigger.evaluate(report)
assertNotNull(result)
}
@Test
fun `should not trigger approval on clean report`() {
val report = ValidationReport(
sections = listOf(
ValidationSection("graph", emptyList()),
),
)
val result = trigger.evaluate(report)
assertNull(result)
}
}
@@ -0,0 +1,92 @@
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.ApprovalOutcome
import com.correx.core.approvals.model.ApprovalScopeIdentity
import com.correx.core.approvals.ApprovalStatus
import com.correx.core.approvals.GrantScope
import com.correx.core.events.types.GrantId
import com.correx.core.events.types.SessionId
import com.correx.core.sessions.ApprovalMode
import com.correx.testing.fixtures.request
import kotlinx.datetime.Instant
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNull
import org.junit.jupiter.api.Test
class GrantSemanticsTest {
private val engine = DefaultApprovalEngine()
@Test
fun `grant permits exact tier - auto_approved`() {
val req = request("r1", Tier.T2)
val grant = ApprovalGrant(
id = GrantId("g1"),
scope = GrantScope.SESSION,
permittedTiers = setOf(Tier.T2),
reason = "test",
timestamp = Instant.parse("2026-01-01T00:00:00Z")
)
val ctx = ApprovalContext(
ApprovalScopeIdentity(SessionId("s1"), null, null),
ApprovalMode.DENY
)
val now = Instant.parse("2026-01-01T00:00:01Z")
val decision = engine.evaluate(req, ctx, listOf(grant), now)
assertEquals(ApprovalOutcome.AUTO_APPROVED, decision.outcome)
assertEquals(ApprovalStatus.COMPLETED, decision.state)
}
@Test
fun `grant does not permit other tiers`() {
val req = request("r1", Tier.T3)
val grant = ApprovalGrant(
id = GrantId("g1"),
scope = GrantScope.SESSION,
permittedTiers = setOf(Tier.T2),
reason = "test",
timestamp = Instant.parse("2026-01-01T00:00:00Z")
)
val ctx = ApprovalContext(
ApprovalScopeIdentity(SessionId("s1"), null, null),
ApprovalMode.DENY
)
val now = Instant.parse("2026-01-01T00:00:01Z")
val decision = engine.evaluate(req, ctx, listOf(grant), now)
assertEquals(ApprovalStatus.PENDING, decision.state)
assertNull(decision.outcome)
}
@Test
fun `multiple grants - any match is enough`() {
val req = request("r1", Tier.T4)
val grants = listOf(
ApprovalGrant(
GrantId("g1"),
GrantScope.SESSION,
setOf(Tier.T3),
"",
Instant.parse("2026-01-01T00:00:00Z")
),
ApprovalGrant(
GrantId("g2"),
GrantScope.SESSION,
setOf(Tier.T4),
"",
Instant.parse("2026-01-01T00:00:00Z")
)
)
val ctx = ApprovalContext(
ApprovalScopeIdentity(SessionId("s1"), null, null),
ApprovalMode.DENY
)
val now = Instant.parse("2026-01-01T00:00:01Z")
val decision = engine.evaluate(req, ctx, grants, now)
assertEquals(ApprovalOutcome.AUTO_APPROVED, decision.outcome)
}
}
@@ -0,0 +1,88 @@
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.ApprovalOutcome
import com.correx.core.approvals.model.ApprovalScopeIdentity
import com.correx.core.approvals.ApprovalStatus
import com.correx.core.events.types.SessionId
import com.correx.core.sessions.ApprovalMode
import com.correx.testing.fixtures.request
import kotlinx.datetime.Instant
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
class ModeApprovalTest {
private val engine = DefaultApprovalEngine()
private fun contextForMode(mode: ApprovalMode) = ApprovalContext(
ApprovalScopeIdentity(SessionId("s1"), null, null),
mode
)
private val now = Instant.parse("2026-01-01T00:00:01Z")
@Test
fun `DENY mode allows only T0`() {
val ctx = contextForMode(ApprovalMode.DENY)
assertEquals(
ApprovalOutcome.AUTO_APPROVED,
engine.evaluate(request("r1", Tier.T0), ctx, emptyList(), now).outcome
)
assertEquals(
ApprovalStatus.PENDING,
engine.evaluate(request("r2", Tier.T1), ctx, emptyList(), now).state
)
assertEquals(
ApprovalStatus.PENDING,
engine.evaluate(request("r3", Tier.T4), ctx, emptyList(), now).state
)
}
@Test
fun `PROMPT mode allows T0-T1`() {
val ctx = contextForMode(ApprovalMode.PROMPT)
assertEquals(
ApprovalOutcome.AUTO_APPROVED,
engine.evaluate(request("r1", Tier.T0), ctx, emptyList(), now).outcome
)
assertEquals(
ApprovalOutcome.AUTO_APPROVED,
engine.evaluate(request("r2", Tier.T1), ctx, emptyList(), now).outcome
)
assertEquals(
ApprovalStatus.PENDING,
engine.evaluate(request("r3", Tier.T2), ctx, emptyList(), now).state
)
}
@Test
fun `AUTO mode allows T0-T2`() {
val ctx = contextForMode(ApprovalMode.AUTO)
assertEquals(
ApprovalOutcome.AUTO_APPROVED,
engine.evaluate(request("r1", Tier.T0), ctx, emptyList(), now).outcome
)
assertEquals(
ApprovalOutcome.AUTO_APPROVED,
engine.evaluate(request("r2", Tier.T2), ctx, emptyList(), now).outcome
)
assertEquals(
ApprovalStatus.PENDING,
engine.evaluate(request("r3", Tier.T3), ctx, emptyList(), now).state
)
}
@Test
fun `YOLO mode allows all tiers, including T4`() {
val ctx = contextForMode(ApprovalMode.YOLO)
assertEquals(
ApprovalOutcome.AUTO_APPROVED,
engine.evaluate(request("r1", Tier.T0), ctx, emptyList(), now).outcome
)
assertEquals(
ApprovalOutcome.AUTO_APPROVED,
engine.evaluate(request("r2", Tier.T4), ctx, emptyList(), now).outcome
)
}
}
@@ -0,0 +1,58 @@
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.ApprovalScopeIdentity
import com.correx.core.approvals.GrantScope
import com.correx.core.events.types.GrantId
import com.correx.core.events.types.SessionId
import com.correx.core.sessions.ApprovalMode
import com.correx.testing.fixtures.request
import kotlinx.datetime.Instant
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertDoesNotThrow
class NoExecutionCouplingTest {
@Test
fun `engine does not mutate grants or context`() {
val engine = DefaultApprovalEngine()
val grants = mutableListOf(
ApprovalGrant(
GrantId("g1"),
GrantScope.SESSION,
setOf(Tier.T2),
"",
Instant.parse("2026-01-01T00:00:00Z")
)
)
val originalGrants = grants.toList()
val ctx = ApprovalContext(
ApprovalScopeIdentity(SessionId("s1"), null, null),
ApprovalMode.DENY
)
val now = Instant.parse("2026-01-01T00:00:01Z")
engine.evaluate(request("r1", Tier.T2), ctx, grants, now)
assertEquals(originalGrants, grants, "Grants list must not be mutated")
assertEquals(ApprovalMode.DENY, ctx.mode, "Context must not be mutated")
}
@Test
fun `engine does not throw for valid input`() {
val engine = DefaultApprovalEngine()
assertDoesNotThrow {
engine.evaluate(
request("r1", Tier.T0),
ApprovalContext(
ApprovalScopeIdentity(SessionId("s1"), null, null),
ApprovalMode.YOLO
),
emptyList(),
Instant.parse("2026-01-01T00:00:01Z")
)
}
}
}
@@ -0,0 +1,55 @@
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.ApprovalScopeIdentity
import com.correx.core.approvals.GrantScope
import com.correx.core.sessions.ApprovalMode
import com.correx.core.events.types.GrantId
import com.correx.core.events.types.SessionId
import com.correx.testing.fixtures.request
import kotlinx.datetime.Instant
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.Test
class TierImmutabilityTest {
private val engine = DefaultApprovalEngine()
@Test
fun `engine never modifies tier - always returns original`() {
val tiers = listOf(Tier.T0, Tier.T1, Tier.T2, Tier.T3, Tier.T4)
val ctx = ApprovalContext(
ApprovalScopeIdentity(SessionId("s1"), null, null),
ApprovalMode.YOLO
)
val now = Instant.parse("2026-01-01T00:00:01Z")
tiers.forEach { tier ->
val req = request("r1", tier)
val decision = engine.evaluate(req, ctx, emptyList(), now)
Assertions.assertEquals(tier, decision.tier, "Tier must remain unchanged")
}
}
@Test
fun `grant does not change tier in decision`() {
val tier = Tier.T3
val req = request("r1", tier)
val grant = ApprovalGrant(
id = GrantId("g1"),
scope = GrantScope.SESSION,
permittedTiers = setOf(tier),
reason = "test",
timestamp = Instant.parse("2026-01-01T00:00:00Z")
)
val ctx = ApprovalContext(
ApprovalScopeIdentity(SessionId("s1"), null, null),
ApprovalMode.DENY
)
val now = Instant.parse("2026-01-01T00:00:01Z")
val decision = engine.evaluate(req, ctx, listOf(grant), now)
Assertions.assertEquals(tier, decision.tier)
}
}