import { JudgeVerdict } from '@tangle-network/agent-eval';
export { EnsembleAggregate, JudgeVerdict, RunRecord, aggregateJudgeVerdicts } from '@tangle-network/agent-eval';
import { Scenario, JudgeConfig } from '@tangle-network/agent-eval/campaign';
export { CampaignResult, DispatchContext, Gate, ImprovementDriver, JudgeConfig, JudgeDimension, JudgeScore, LabeledScenarioStore, MutableSurface, Mutator, Scenario, defaultProductionGate, evolutionaryDriver, gepaDriver, paretoSignificanceGate, runCampaign } from '@tangle-network/agent-eval/campaign';
export { SelfImproveBudget, SelfImproveOptions, SelfImproveResult, selfImprove } from '@tangle-network/agent-eval/contract';

/**
 * Trust gate — decides whether an ensemble's scores are allowed to be BELIEVED,
 * one level up from {@link aggregateJudgeVerdicts} (which only reduces ONE
 * artifact's raters to a composite). A composite is a number; this is the check
 * that the number means anything. It is the code "Enforced by" for the
 * measurement-validation skill's after-gate ("is this result allowed to be
 * believed").
 *
 * Three checks, each fail-loud and named in `trustReasons`:
 *   (1) inter-rater reliability over the corpus ≥ `irrFloor` — raters that
 *       disagree no better than chance carry no signal to optimize against.
 *   (2) per-item rater spread ≤ `spreadCeiling` — for EACH item, raters must
 *       converge on THAT item.
 *   (3) surviving raters per item ≥ `minSurvivors` — a mean over one or two
 *       raters is an anecdote, not an ensemble.
 *
 * CRITICAL metric semantics — per-item spread is rater disagreement about the
 * SAME item: `max(score) − min(score)` across the raters that scored THAT item
 * (max over its dimensions), never pooled across different items or across the
 * baseline/candidate sides. Pooling reads a genuine quality gap BETWEEN items as
 * "the raters split" and so trips the gate exactly when the finding is largest —
 * the failure mode the after-gate exists to prevent. The corpus IRR (check 1)
 * leans on the substrate's `interRaterReliability`, whose expected-disagreement
 * denominator already pools across items, so genuine item-to-item variation
 * RAISES reliability rather than lowering it.
 */

/** One item's raters: the per-judge verdicts {@link aggregateJudgeVerdicts}
 *  reduces, tagged with the item they scored so spread stays within-item. */
interface TrustItem<D extends string = string> {
    /** Stable item identifier — surfaces in `perItemSpread` and `trustReasons`. */
    itemId: string;
    /** The raters' verdicts for THIS item (one per judge call). A failed judge
     *  (`perDimension: null`) is dropped before spread/IRR, never folded as 0. */
    verdicts: readonly JudgeVerdict<D>[];
}
/** Thresholds for {@link trustVerdicts}. All overridable; defaults are the
 *  conservative after-gate bar. */
interface TrustThresholds {
    /** Minimum corpus inter-rater reliability (Krippendorff-style α). Below this
     *  the raters agree no better than chance. Default 0.2. */
    irrFloor?: number;
    /** Maximum per-item rater spread (`max − min` over a single item's surviving
     *  raters, across its dimensions). Above this the raters split ON THAT ITEM.
     *  Default 0.5. */
    spreadCeiling?: number;
    /** Minimum surviving (non-failed) raters required per item. Default 3. */
    minSurvivors?: number;
}
/** Result of the trust gate. `trustworthy` iff every check passed; `trustReasons`
 *  is empty iff `trustworthy`. */
interface TrustVerdict {
    /** True iff IRR ≥ floor AND every item's spread ≤ ceiling AND every item has
     *  ≥ `minSurvivors` surviving raters. */
    trustworthy: boolean;
    /** One entry per FAILED check, each naming its number + the offending value.
     *  Empty iff `trustworthy`. */
    trustReasons: string[];
    /** Corpus inter-rater reliability actually measured (the check-1 value). */
    interRaterReliability: number;
    /** Per-item spread (`max − min` over surviving raters, max over dimensions),
     *  keyed by `itemId`. The check-2 input, surfaced for drill-down. */
    perItemSpread: Record<string, number>;
}
/**
 * Decide whether an ensemble's per-item verdicts are trustworthy enough to
 * believe a lift computed from them. Pure: no LLM, no I/O, no clock, no random —
 * the same `items` + `thresholds` always yield the same verdict.
 *
 * Sibling to {@link aggregateJudgeVerdicts}: that reduces ONE item's raters to a
 * composite; this audits the raters ACROSS items and reports whether the
 * composites are believable. Run it on the corpus of held-out items before
 * reporting any lift over their scores.
 *
 * @throws if `items` is empty — an empty corpus has no measurable trust, and a
 *   silent `trustworthy: true` over zero evidence is the exact lie the gate
 *   exists to refuse.
 */
declare function trustVerdicts<D extends string>(items: readonly TrustItem<D>[], thresholds?: TrustThresholds): TrustVerdict;

/**
 * Eval-campaign — the app-shell's curated surface for a product's
 * self-improvement loop, NOT a reimplementation.
 *
 * The loop ENGINE lives in `@tangle-network/agent-eval` (a peer dependency):
 * `selfImprove` already owns the whole cycle — train/holdout split, the GEPA
 * driver, the held-out production gate, durable provenance + hosted ingest, and
 * every default. A product should NOT hand-roll `runImprovementLoop` +
 * `emitLoopProvenance` around it (that is the boilerplate this surface exists to
 * delete). It should call `selfImprove` with three things it actually owns:
 * scenarios, an `agent` dispatch, and a `judge`.
 *
 * This module adds the one piece `selfImprove` does not own and which every
 * multi-model product re-hand-rolls — the ensemble judge:
 *
 *   {@link buildEnsembleJudge} — turn a per-rubric `scoreOne` into a
 *   `JudgeConfig` that fans out N uncorrelated judge calls and reduces them via
 *   the substrate's `aggregateJudgeVerdicts` (survivor-mean, inter-rater spread,
 *   fail-loud on all-failed). A product writes its rubric + one judge call; the
 *   fan-out, partial-failure handling, and composite are the scaffold's.
 *
 * Everything else is a curated re-export so a product has ONE eval import:
 * `selfImprove` + the gates + the drivers + the types. See
 * `.claude/skills/eval-campaign/SKILL.md` for the wiring contract.
 */

/** Config for {@link buildEnsembleJudge}. `D` = the rubric's dimension union. */
interface EnsembleJudgeConfig<TArtifact, TScenario extends Scenario, D extends string> {
    /** Judge name — appears in traces and scorecards. */
    name: string;
    /** Stable-ordered rubric dimensions. Drives the `JudgeDimension` list AND the
     *  reducer keys, so a judge that omits a dimension scores it 0 (never silently
     *  dropped). */
    rubric: readonly D[];
    /**
     * Score ONE artifact on the rubric → a raw per-dimension verdict. Called
     * `judgeReps` times per artifact; vary the model by `rep` for an uncorrelated
     * ensemble (judges that share a base model share its bias). Return
     * `{ model, perDimension: null }` to record a judge failure WITHOUT killing
     * the ensemble; throw only on an unrecoverable error (the whole rep is then
     * treated as a failed judge).
     */
    scoreOne: (input: {
        artifact: TArtifact;
        scenario: TScenario;
        signal: AbortSignal;
        rep: number;
    }) => Promise<JudgeVerdict<D>>;
    /** Independent judge calls per artifact, reduced by `aggregateJudgeVerdicts`.
     *  Default 1. Raise (with model variety in `scoreOne`) for inter-rater bands. */
    judgeReps?: number;
    /** Per-dimension composite weights. Default: uniform over `rubric`. A partial
     *  map selects-and-weights exactly the named dimensions. */
    weights?: Partial<Record<D, number>>;
    /** Optional human-readable dimension descriptions. Default: the key itself. */
    describe?: (dim: D) => string;
}
/**
 * Build a `JudgeConfig` whose `score()` fans out `judgeReps` independent
 * `scoreOne` calls and reduces them with the substrate's
 * `aggregateJudgeVerdicts`. A single judge call failing does NOT fail the cell
 * (it is recorded and dropped); only ALL judges failing throws — which the
 * campaign records as a failed cell, never a silent zero.
 *
 * Pass the result straight to `selfImprove({ judge })` (or `runCampaign`).
 */
declare function buildEnsembleJudge<TArtifact, TScenario extends Scenario, D extends string>(cfg: EnsembleJudgeConfig<TArtifact, TScenario, D>): JudgeConfig<TArtifact, TScenario>;

export { type EnsembleJudgeConfig, type TrustItem, type TrustThresholds, type TrustVerdict, buildEnsembleJudge, trustVerdicts };
