package com.correx.core.events.events

import com.correx.core.events.types.SessionId
import com.correx.core.events.types.StageId
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

/** The outcome of evaluating one contract assertion against a stage's produced file. */
@Serializable
data class ContractAssertionResult(
    val assertionId: String,
    /** Workspace-relative path the assertion was evaluated against. */
    val target: String,
    /** Contract layer the assertion came from: DERIVED / FRAMEWORK / PLANNER / HUMAN. */
    val layer: String,
    /** Evaluator that produced the verdict: FS / TEXT / COMPILER / AST. */
    val evaluator: String,
    val passed: Boolean,
    /** True when this assertion is intentionally deferred to another authoritative gate. */
    val skipped: Boolean = false,
    /** Concrete reason the assertion failed (or a confirmation when it passed). Kept bounded. */
    val evidence: String,
)

/**
 * Environment observation (invariant #9): the Gate 2 contract assertions evaluated against a
 * stage's produced files — each with the layer it came from, the evaluator, its verdict and
 * evidence — captured at the moment the stage completed. Replay reads these recorded facts and
 * never re-inspects the filesystem.
 *
 * Gate 2 (design §1) answers "did the stage accomplish its objective?" deterministically, over the
 * files the stage declared it `produces`. A failed assertion fails the producing stage retryably,
 * with the failing assertion ids + evidence fed back verbatim — so hand-back feedback is
 * failing-test-name granular, not a vague "review said fix it".
 */
@Serializable
@SerialName("ContractGateEvaluated")
data class ContractGateEvaluatedEvent(
    val sessionId: SessionId,
    val stageId: StageId,
    val results: List<ContractAssertionResult>,
) : EventPayload {
    val passed: Boolean get() = results.all { it.passed }
}
