package com.correx.core.artifacts.kind

/**
 * Which mechanism evaluates an assertion. The *initial* choice is the cheapest that works;
 * `AST`-tagged assertions ship as `TEXT` heuristics and are promoted to a real structured parse
 * only when the benchmark projection shows the heuristic is too noisy (design §3.4). The id is
 * stable across a promotion; only the evaluator strengthens.
 */
enum class AssertionEvaluator {
    /** Filesystem stat/read — existence, non-empty. No parse. */
    FS,

    /** Regex / JSON parse — line-oriented, cheap. */
    TEXT,

    /** Read out of a compiler/linter run the stage already invokes (authoritative, whole-project). */
    COMPILER,

    /** Structured parse. Starts life as a `TEXT` heuristic; promoted on demand. */
    AST,
}

/**
 * The contract layer an assertion came from. Priority increases downward. Monotonicity is scoped
 * to the LLM-authored layers: [DERIVED], [FRAMEWORK] and [PLANNER] may only strengthen the
 * contract (they are concatenated, never edited). [HUMAN] is the single trusted layer with
 * weakening authority (design §3.1). Enforced structurally — the planner emits only its own
 * layer and has no syntax for removal — so weakening is inexpressible, not detected-and-rejected.
 */
enum class AssertionLayer {
    DERIVED,
    FRAMEWORK,
    PLANNER,
    HUMAN,
}

/**
 * One deterministic (or, for [AssertionEvaluator.AST], deterministic-once-promoted) requirement on
 * a stage's produced file. Instantiated from the [KindContractTable] against a concrete path.
 *
 * A contract assertion is Gate 2 (design §1): "did the stage accomplish its objective?" — answered
 * by filesystem/AST inspection over what the stage declared it produces, never by an LLM. The
 * result of evaluating each assertion is recorded in a
 * [com.correx.core.events.events.ContractGateEvaluatedEvent] so hand-back feedback is
 * failing-test-name granular.
 */
data class ContractAssertion(
    val id: String,
    val target: String,
    val evaluator: AssertionEvaluator,
    val layer: AssertionLayer = AssertionLayer.DERIVED,
    val args: Map<String, String> = emptyMap(),
)
