/**
 * EvalTraceStore — JSONL save / query / compare over the analysis-time
 * `RunRecord` row.
 *
 * `FileSystemTraceStore` (in `./trace/store`) persists the rich TraceSchema-v1
 * span corpus — runs, spans, events, artifacts — the runtime emits live. That
 * is NOT the thing three consumers hand-roll in `tests/eval/lib/trace-store.ts`.
 * What they hand-roll is the *analysis* layer: append each finished run as one
 * JSONL line keyed by scenario/candidate, then query it ("every run where score
 * < 50"), pick the best run for a scenario (few-shot seeding), and compare two
 * candidates on matched scenarios.
 *
 * The substrate already has the canonical analysis-time row — `RunRecord` — so
 * this is that query/compare API expressed over `RunRecord[]`, with a
 * JSONL-backed store. It does NOT fork `FileSystemTraceStore`; it sits beside it
 * for the analysis projection.
 */
import { type RunRecord, type RunSplitTag } from './run-record';
/** The score the query/compare layer ranks on: holdout when present (the
 *  gated number), else search. Throws when a record carries neither — a
 *  RunRecord is invalid without at least one, but a hand-built object might. */
export declare function runScore(record: RunRecord): number;
export interface RunRecordFilter {
    experimentId?: string;
    candidateId?: string;
    scenarioId?: string;
    model?: string;
    splitTag?: RunSplitTag;
    /** Inclusive lower bound on `runScore`. */
    minScore?: number;
    /** Inclusive upper bound on `runScore`. */
    maxScore?: number;
    /** Match a single tag in `outcome.raw` by exact numeric value. */
    rawEquals?: {
        key: string;
        value: number;
    };
    /** Custom predicate, ANDed with the structured filters. */
    where?: (record: RunRecord) => boolean;
}
export interface CandidateComparison {
    a: string;
    b: string;
    /** Scenario ids present for BOTH candidates — the paired comparison set. */
    pairedScenarioIds: string[];
    /** Mean `runScore` for candidate a over the paired scenarios. */
    meanA: number;
    /** Mean `runScore` for candidate b over the paired scenarios. */
    meanB: number;
    /** meanB − meanA. Positive ⇒ b scored higher on the matched scenarios. */
    meanDelta: number;
    /** Scenarios where b beat a (strictly), tied, and a beat b. */
    bWins: number;
    ties: number;
    aWins: number;
}
/**
 * Backing persistence for `EvalTraceStore`. The in-memory store is the default;
 * the JSONL file store appends one validated `RunRecord` per line. Both keep an
 * append order so `getBest` / `compareRuns` are reproducible.
 */
export interface RunRecordBackend {
    append(record: RunRecord): Promise<void>;
    load(): Promise<RunRecord[]>;
}
export declare function inMemoryRunRecordBackend(initial?: RunRecord[]): RunRecordBackend;
/**
 * JSONL-backed store at `path`, one `RunRecord` per line. Malformed lines fail
 * loud on load (a corrupt corpus must not silently shrink the analysis set);
 * pass `skipInvalid` only for forensics on a known-bad file.
 */
export declare function jsonlRunRecordBackend(path: string, opts?: {
    skipInvalid?: boolean;
}): RunRecordBackend;
/**
 * Query / compare layer over a `RunRecord` corpus. Append finished runs, query
 * with a structured filter, take the best run for a scenario, and compare two
 * candidates on their matched scenarios. Persistence is injected via
 * `RunRecordBackend` (in-memory by default, JSONL file via
 * `jsonlRunRecordBackend`).
 */
export declare class EvalTraceStore {
    private readonly backend;
    constructor(backend?: RunRecordBackend);
    /** Validate and append one run. Throws on an invalid record — the corpus
     *  stays paper-grade. */
    append(record: RunRecord): Promise<void>;
    all(): Promise<RunRecord[]>;
    query(filter?: RunRecordFilter): Promise<RunRecord[]>;
    /**
     * Highest-scoring run for a scenario (optionally restricted to a candidate).
     * Returns null when no run matches. Ties resolve to the earliest-appended run
     * so the result is stable.
     */
    getBest(scenarioId: string, opts?: {
        candidateId?: string;
        splitTag?: RunSplitTag;
    }): Promise<RunRecord | null>;
    /**
     * Compare two candidates on the scenarios they BOTH ran. When a candidate
     * ran a scenario more than once, its best `runScore` for that scenario is
     * used. Throws when there is no paired scenario — an unpaired "comparison" is
     * not one.
     */
    compareRuns(candidateA: string, candidateB: string): Promise<CandidateComparison>;
}
//# sourceMappingURL=eval-trace-store.d.ts.map