package com.correx.core.kernel.orchestration

import com.correx.core.events.events.SalvageDecision
import com.correx.core.events.types.SessionId
import com.correx.core.events.types.StageId

/** Result of a [SalvageJudge.judge] call. */
data class SalvageJudgment(val decision: SalvageDecision, val rationale: String)

/**
 * Seam for the hybrid-exhaustion salvage judgement (design 2026-07-06-per-gate-retry-budgets.md
 * §3/T7): consulted when the "review" gate exhausts its per-gate retry budget. Like the other gate
 * seams ([SemanticReviewer], [ContractAssertionEvaluator]), the inference-touching implementation is
 * injected so the deterministic core never runs inference itself.
 *
 * The judgement is nondeterministic (LLM-backed), so invariant #9 requires the caller to record the
 * outcome as a [com.correx.core.events.events.RetrySalvageDecidedEvent] — replay reads that event
 * back and never re-invokes this judge. When no judge is wired (`null` in [OrchestratorEngines]),
 * the orchestrator falls back to a deterministic allow-one-reset-then-fail policy so the feature
 * degrades safely without inference (see `DefaultSessionOrchestrator.decideSalvage`).
 */
fun interface SalvageJudge {
    suspend fun judge(sessionId: SessionId, stageId: StageId, reason: String): SalvageJudgment
}
