import com.correx.core.approvals.ApprovalStatus import com.correx.core.approvals.GrantScope 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.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) } }