import type { RunRecord } from './run-record';
/**
 * DescriptionLengthGate — a Minimum-Description-Length promotion gate, the
 * Builder/Breaker acceptance rule from Wang & Buehler, "Self-Revising Discovery
 * Systems for Science" (arXiv:2606.01444, MIT LAMM), eq. 5:
 *
 *     L(M, D) = L_model(M) + L_data(D | M)
 *     accept M' over M  iff  L(M', D∪E) < L(M, D∪E)
 *
 * Both candidate and baseline are scored on the SAME enlarged evidence set
 * (every accumulated task — NOT just the held-out split), and the candidate is
 * accepted only if it lowers the TOTAL bit cost. This is the gate's whole
 * point and what distinguishes it from a monotone held-out delta:
 *
 *   - L_model(M)  — the candidate's own description length: the compressed size
 *     of its model text (a prompt, skill, profile, or symbolic model). A bigger
 *     model pays more bits.
 *   - L_data(D|M) — the residual: bits of "surprise" that the model did not
 *     simply succeed, −Σ_i log2(s_i) over the model's per-task score s_i.
 *     Perfect scores cost 0 bits; failure costs a lot (capped, not infinite).
 *
 * A candidate that merely memorizes new counterexamples grows L_model faster
 * than it shrinks L_data and LOSES — a principled, complexity-penalized
 * alternative to HeldOutGate's held-out paired delta. Use this gate
 * when the model text whose size you want to penalize is available; use
 * HeldOutGate when promotion should turn on held-out generalization with an
 * overfit-gap check instead.
 *
 * Scale / calibration: a gzip'd prose model is hundreds–thousands of bits;
 * a single task contributes at most −log2(scoreFloor) data bits (≈10). So with
 * little evidence the model term dominates and the gate is conservative about
 * model GROWTH — it promotes a larger model only once accumulated evidence
 * genuinely pays for the added bits (exactly the paper's regime, where D∪E
 * grows). `lambda` is the lever: λ<1 discounts model bits (more permissive),
 * λ>1 is stricter. A shrinking-or-equal model that does no worse always wins.
 *
 * Stateless: construct once with the description-length budget, call
 * `evaluate` per (candidate, baseline) pair.
 */
export type DescriptionLengthRejectionCode = 'few_tasks' | 'no_total_gain' | 'model_bloat';
export interface DescriptionLengthConfig {
    /** Stable label of the baseline. Required — paper-grade evaluation never
     *  compares two unlabelled candidates. */
    baselineKey: string;
    /** Weight on model bits relative to data bits (the description-length
     *  budget λ). 1 = bits are bits. >1 = more complexity-averse. Default 1. */
    lambda?: number;
    /** The candidate must beat the baseline by at least this many bits to
     *  promote — a robustness margin against measurement noise. Default 0
     *  (strict `<`, as the paper). */
    marginBits?: number;
    /** Per-task score floor for the residual code: −log2(max(s, floor)). Caps a
     *  total-failure task's surprise instead of letting it diverge. Default
     *  2^-10 (a failed task costs 10 bits, not ∞). */
    scoreFloor?: number;
    /** Minimum number of shared (candidate, baseline) tasks before the gate will
     *  consider promoting. Default 3. */
    minTasks?: number;
}
export interface DescriptionLengthEvidence {
    /** Shared tasks scored on both sides (the enlarged evidence D∪E). */
    tasks: number;
    /** Compressed-model bits — L_model. */
    modelBits: {
        candidate: number;
        baseline: number;
    };
    /** Residual surprise bits — L_data(D|M). */
    dataBits: {
        candidate: number;
        baseline: number;
    };
    /** λ·L_model + L_data — the quantity the gate minimizes. */
    totalBits: {
        candidate: number;
        baseline: number;
    };
    /** candidate − baseline total. Negative = candidate compresses better. */
    deltaBits: number;
    /** Per-component deltas, for audit: did the win come from a smaller model,
     *  better outcomes, or both? */
    modelBitsDelta: number;
    dataBitsDelta: number;
}
export interface DescriptionLengthDecision {
    promote: boolean;
    candidateId: string;
    baselineId: string;
    evidence: DescriptionLengthEvidence;
    reason: string;
    rejectionCode: DescriptionLengthRejectionCode | null;
}
export interface DescriptionLengthCandidate {
    /** The model text whose size is L_model (a prompt, skill, profile, or
     *  symbolic model; concatenated if several files). */
    content: string;
    /** Runs whose per-task scores form L_data. */
    runs: RunRecord[];
}
/** Compressed-model bits — the model's description length L_model. gzip is a
 *  deterministic, dependency-free stand-in for Kolmogorov complexity; it
 *  rewards genuine compactness and penalizes boilerplate padding. */
export declare function modelDescriptionBits(content: string): number;
/** Residual surprise L_data(D|M) = −Σ_i log2(max(s_i, floor)) over the given
 *  per-task scores. Lower = the model more reliably succeeds. */
export declare function dataDescriptionBits(scoreByTask: Map<string, number>, keys: Iterable<string>, scoreFloor: number): number;
export declare class DescriptionLengthGate {
    private readonly baselineKey;
    private readonly lambda;
    private readonly marginBits;
    private readonly scoreFloor;
    private readonly minTasks;
    constructor(config: DescriptionLengthConfig);
    /** Decide whether `candidate` should replace `baseline`. Both are scored on
     *  the shared task set (the enlarged evidence); the candidate promotes only
     *  if λ·L_model + L_data is strictly lower by at least `marginBits`. */
    evaluate(candidate: DescriptionLengthCandidate, baseline: DescriptionLengthCandidate): DescriptionLengthDecision;
}
//# sourceMappingURL=description-length-gate.d.ts.map