package com.correx.core.events.events

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

/**
 * One deterministic plan-lint finding. [code] is a stable machine code (e.g. "unproduced_need",
 * "trap_state", "fan_out"); [stageId] is the offending stage, or null for a plan-level finding.
 */
@Serializable
data class PlanLintFinding(
    val code: String,
    val stageId: String?,
    val detail: String,
)

/**
 * The deterministic lint of a compiled ExecutionPlan candidate (plan-pipeline-spec §5). Pure: a
 * function of the recorded plan artifact alone (no environment observation in v1 — graph-structural
 * checks only), so it is recomputable on replay without re-reading anything. Recorded so the operator
 * and downstream selection see why a candidate was discarded or down-ranked.
 *
 * A non-empty [hardFailures] means the candidate is unfit and is rejected (it must not be locked/run);
 * [softFindings] are scored, not blocking. [score] is the weighted soft-finding penalty (lower is
 * better) used by the future tournament ranking (§9).
 */
@Serializable
@SerialName("PlanLintCompleted")
data class PlanLintCompletedEvent(
    val sessionId: SessionId,
    val candidateId: String,
    val hardFailures: List<PlanLintFinding>,
    val softFindings: List<PlanLintFinding>,
    val score: Int,
) : EventPayload
