/**
 * canary/drift.ts — Pure drift-statistic computation for the Tier 3
 * framework-tests-framework loop.
 *
 * Consumes the projection shape returned by Studio's `latestReportsQuery`
 * (we accept a slim subset so the function stays a pure-domain dependency
 * with no Studio-package import). Computes per-area Δscore between the
 * most-recent canary run and the trailing-N median, plus an overall
 * Δscore for the run as a whole. Output classifies each delta as `ok`,
 * `warn`, or `regression` against caller-provided thresholds.
 *
 * The function is total — it never throws. Edge cases (empty trailing
 * window, missing scores) surface as `verdict: "no-baseline"` so the
 * caller can decide whether to treat the missing baseline as a fail.
 *
 * @see docs/design-docs/testing-strategy.md — "Tier 3 — Live LLMs"
 * @see packages/studio/src/queries.ts — `latestReportsQuery`
 */
/** Slim projection of a canary run report — subset of `ReportListItem`. */
export interface CanaryReportSlim {
    reportId: string;
    completedAt: string;
    overall: number;
    scores: {
        feature: string;
        totalScore: number;
    }[];
}
/** Verdict for a single Δ computation. */
export type DriftVerdict = "ok" | "warn" | "regression" | "no-baseline";
/** Δ between the most-recent run and the trailing-N median. */
export interface DriftEntry {
    /** "overall" for the run-level avg, or the area slug for a per-area Δ. */
    feature: string;
    /** Score in the most-recent run. */
    current: number;
    /** Median of trailing-N runs (excluding the most-recent). Null when no baseline. */
    trailingMedian: number | null;
    /** current − trailingMedian. Null when no baseline. */
    delta: number | null;
    verdict: DriftVerdict;
}
/** Tunable thresholds — caller decides what counts as warn vs regression. */
export interface DriftThresholds {
    /**
     * How many prior runs (excluding the most-recent) form the trailing
     * baseline. Sensible defaults sit between 5 and 10 for a daily canary.
     */
    trailingN: number;
    /** Drop ≥ this magnitude (and < failDelta) → `warn`. */
    warnDelta: number;
    /** Drop ≥ this magnitude → `regression`. */
    failDelta: number;
    /**
     * Minimum trailing-window size required to compute a delta. When the
     * window is smaller, the entry's verdict is `no-baseline`. Defaults to
     * 1 — a single prior run is enough to detect *some* movement.
     */
    minBaselineRuns?: number;
}
/** Aggregate result of `computeCanaryDrift`. */
export interface CanaryDriftReport {
    /** ID + timestamp of the most-recent run. */
    reportId: string;
    completedAt: string;
    /** Run-level Δscore (overall avg). */
    overall: DriftEntry;
    /** Per-area Δscores. One entry per area present in the most-recent run. */
    byArea: DriftEntry[];
    /** True when any verdict is `regression`. */
    hasRegression: boolean;
    /** True when any verdict is `warn` or `regression`. */
    hasMovement: boolean;
}
/**
 * Compute per-area + overall drift for a sequence of canary runs.
 *
 * `reports` must be ordered **newest-first** (matching `latestReportsQuery`'s
 * `order(completedAt desc)`). The most-recent run is `reports[0]`; the
 * trailing window is `reports.slice(1, 1 + trailingN)`.
 *
 * @throws never — all error states surface as `no-baseline` verdicts.
 */
export declare function computeCanaryDrift(reports: CanaryReportSlim[], thresholds: DriftThresholds): CanaryDriftReport | null;
