/**
 * Experiment tracker — git-provenanced experiment log with N-rep stats and a
 * KEEP / REGRESSION / NOISE verdict against a parent.
 *
 * Every loop the fleet runs reduces to the same question: "I ran the candidate
 * N times — is the median measurably better than the parent, or is the delta
 * inside the noise band?" The hand-rolled copies bake a fixed score scale
 * (percentage points), a fixed store path (`.evolve/experiments-v2.json`), and
 * `execSync('git …')` straight into the module. This is the canonical version:
 * provenance and persistence are injected, thresholds are configurable, and the
 * stats + verdict are pure functions you can unit-test without a git repo or a
 * filesystem.
 *
 * Stats per experiment: median / mean / min / max / iqr / stddev / passRate /
 * n, plus a `stable` flag (`iqr < iqrUnstableAbove && stddev < stddevUnstableAbove`).
 *
 * Verdict against a parent (both must have `n >= minRepsForVerdict`):
 *   - NOISE       — the candidate is too unstable to judge (`!stable`)
 *   - KEEP        — `medianDelta >  keepThreshold`
 *   - REGRESSION  — `medianDelta < -regressionThreshold`
 *   - NOISE       — otherwise (delta inside the band)
 * With no parent (or insufficient reps) the verdict is the neutral ITERATE.
 */
/** Verdict for one experiment relative to its parent. ITERATE is the neutral
 *  "keep collecting reps / no parent to compare against" state. */
export type ExperimentVerdict = 'KEEP' | 'ITERATE' | 'NOISE' | 'REGRESSION';
/** Git provenance for the working tree an experiment was run from. */
export interface ExperimentProvenance {
    /** Commit sha (short or full — the tracker does not interpret it). */
    commit: string;
    /** First line of the commit message. */
    message: string;
    /** Files changed vs the parent commit, or a marker like 'uncommitted'. */
    changedFiles: string[];
}
/** A single repetition of an experiment, carrying the score the verdict is
 *  computed on plus any free-form per-rep metrics the consumer wants kept. */
export interface ExperimentRep {
    /** 0-indexed repetition number within the experiment. */
    rep: number;
    /** The score this rep is judged on (same scale as the thresholds). */
    score: number;
    /** ISO timestamp the rep completed. */
    timestamp: string;
    /** Whether this rep passed the consumer's own gate — folded into `passRate`. */
    passed?: boolean;
    /** Free-form numeric metrics retained for later analysis. */
    metrics?: Record<string, number>;
}
export interface ExperimentStats {
    median: number;
    mean: number;
    min: number;
    max: number;
    /** Inter-quartile range of the rep scores. */
    iqr: number;
    /** Population standard deviation of the rep scores. */
    stddev: number;
    /** Fraction of reps with `passed === true`, over reps that set `passed`.
     *  null when no rep declared a pass/fail outcome. */
    passRate: number | null;
    /** Number of reps. */
    n: number;
    /** True when the sample is tight enough to trust for a verdict. */
    stable: boolean;
}
export interface Experiment {
    /** Stable id for the experiment. */
    id: string;
    /** Free-form label / config descriptor. */
    label: string;
    /** Git provenance captured when the experiment was created. */
    provenance: ExperimentProvenance;
    /** Parent experiment id this candidate is compared against, if any. */
    parentId?: string;
    /** One-line summary of what changed from the parent. */
    changeSummary: string;
    reps: ExperimentRep[];
    stats: ExperimentStats;
    verdict: ExperimentVerdict;
    /** ISO timestamp the experiment was created. */
    createdAt: string;
}
export interface ImprovementThresholds {
    /** medianDelta strictly above this ⇒ KEEP. Default 5. */
    keepThreshold?: number;
    /** medianDelta strictly below the negative of this ⇒ REGRESSION. Default 5. */
    regressionThreshold?: number;
    /** iqr at or above this ⇒ unstable. Default 10. */
    iqrUnstableAbove?: number;
    /** stddev at or above this ⇒ unstable. Default Infinity (iqr-only stability). */
    stddevUnstableAbove?: number;
    /** Reps required on BOTH candidate and parent before a verdict is rendered.
     *  Default 3. */
    minRepsForVerdict?: number;
}
export interface ImprovementVerdictResult {
    verdict: ExperimentVerdict;
    /** candidate.median − parent.median; null when no parent or insufficient reps. */
    medianDelta: number | null;
    /** Human-readable reason for the verdict — for dashboards and logs. */
    reason: string;
}
/**
 * Compute the N-rep statistics for a set of reps. Pure — no I/O. The `stable`
 * flag is the trust gate the verdict depends on: a sample whose spread exceeds
 * the configured bounds can't distinguish a real delta from run-to-run noise.
 */
export declare function computeExperimentStats(reps: ExperimentRep[], thresholds?: ImprovementThresholds): ExperimentStats;
/**
 * Verdict for a candidate against its parent. Pure — operates on already-computed
 * stats. KEEP/REGRESSION require both sides to have `>= minRepsForVerdict` reps
 * AND the candidate to be `stable`; otherwise the result is NOISE (unstable) or
 * ITERATE (not enough reps / no parent).
 */
export declare function improvementVerdict(candidate: ExperimentStats, parent: ExperimentStats | null, thresholds?: ImprovementThresholds): ImprovementVerdictResult;
/** Reads git provenance for the working tree. Inject a fake in tests; the
 *  default implementation shells out to `git`. */
export type ProvenanceReader = () => ExperimentProvenance | Promise<ExperimentProvenance>;
/** Persistence seam for the experiment log. Inject in-memory in tests; the
 *  filesystem implementation is `fileExperimentStore`. */
export interface ExperimentStore {
    load(): Promise<Experiment[]>;
    save(experiments: Experiment[]): Promise<void>;
}
/**
 * Default provenance reader: `git rev-parse HEAD`, the subject line, and the
 * files changed vs `HEAD~1`. Fail-loud — a tracker that silently logs
 * `commit: 'unknown'` corrupts the provenance the whole point of the log is to
 * carry. When the working tree genuinely has no parent commit, pass an override.
 */
export declare const gitProvenanceReader: ProvenanceReader;
/** In-memory store — the default when no persistence is wanted (tests, ephemeral
 *  runs). State lives on the instance. */
export declare function inMemoryExperimentStore(initial?: Experiment[]): ExperimentStore;
/** Filesystem store — a single JSON array at `path`, created on first save. */
export declare function fileExperimentStore(path: string): ExperimentStore;
export interface ExperimentTrackerOptions {
    store?: ExperimentStore;
    provenanceReader?: ProvenanceReader;
    thresholds?: ImprovementThresholds;
    /** Clock seam for deterministic timestamps in tests. Default `Date.now`. */
    now?: () => number;
}
export interface CreateExperimentInput {
    id: string;
    label: string;
    changeSummary: string;
    parentId?: string;
    /** Override provenance instead of reading from git (e.g. CI metadata). */
    provenance?: ExperimentProvenance;
}
/**
 * Stateful tracker over an `ExperimentStore`. Create an experiment (provenance
 * is captured once), append reps as they complete (stats + verdict recompute on
 * every append), and read the log back for a dashboard. All persistence and git
 * access flow through the injected seams, so the tracker is fully testable
 * without a repo or disk.
 */
export declare class ExperimentTracker {
    private readonly store;
    private readonly provenanceReader;
    private readonly thresholds;
    private readonly now;
    constructor(options?: ExperimentTrackerOptions);
    create(input: CreateExperimentInput): Promise<Experiment>;
    /** Append a rep (its `rep` index defaults to the current rep count) and
     *  recompute stats + verdict. Returns the updated experiment. */
    addRep(experimentId: string, rep: Omit<ExperimentRep, 'rep' | 'timestamp'> & {
        rep?: number;
        timestamp?: string;
    }): Promise<Experiment>;
    get(experimentId: string): Promise<Experiment | undefined>;
    list(): Promise<Experiment[]>;
    /** Full verdict (not just the enum) for an experiment vs its parent. */
    verdictFor(experimentId: string): Promise<ImprovementVerdictResult>;
}
//# sourceMappingURL=experiment-tracker.d.ts.map