/**
 * OFFLINE TOOL. NOT a centerpiece. Use for ex-post analysis only —
 * never wire into live runtime.
 *
 * replayCounterfactual — counterfactual replay primitive.
 *
 * Given an original runId, replays the same cycle with an alternative compute
 * strategy (or verifier / temperature override). The original run's
 * clock/random/cache are kept fixed — only the compute strategy is swapped.
 *
 * Purpose: offline "what-if" analysis. E.g. "what if this cycle had used
 * best-of-n instead of single-shot?"
 *
 * Design invariants:
 *   - Does NOT mutate the original trace or any live execution path.
 *   - ReplayRunner.run() receives a ReplayContext augmented with strategyOverride
 *     injected into the runner's compute config.
 *   - "outputsCoherent" = same runtime type AND same top-level keys (for objects).
 *   - "outputsIdentical" = deep structural equality via JSON serialisation.
 *
 * @module counterfactual/replay-with-alt
 */
import type { ReplayLoader, ReplayRunner, ReplayContext } from "../replay/replay.js";
import type { Verifier } from "../compute/verifier.js";
/**
 * Canonical strategy names accepted by the runner's strategyOverride field.
 * Callers passing an unknown name will get an InvalidStrategyNameError.
 */
export type ComputeStrategyName = "single-shot" | "best-of-n" | "bon-mav";
/**
 * Options for replayCounterfactual.
 * At least one of alt_strategy, alt_verifier, or alt_temperature should differ
 * from the original run to produce a meaningful counterfactual.
 */
export interface CounterfactualOptions {
    /** Swap the compute strategy (e.g. "best-of-n" instead of "single-shot"). */
    alt_strategy?: ComputeStrategyName;
    /** Replace the verifier used by the strategy (e.g. swap to a stricter judge). */
    alt_verifier?: Verifier;
    /** Replace the generation temperature (0–2 range; host-interpreted). */
    alt_temperature?: number;
}
/**
 * Result of a counterfactual replay run.
 *
 * outputsCoherent:
 *   true when both outputs have the same runtime type AND, if both are plain
 *   objects, the same set of top-level keys. This is a structural compatibility
 *   check — not a value comparison.
 *
 * outputsIdentical:
 *   true when JSON.stringify(original) === JSON.stringify(counterfactual).
 *   Guarantees deep value equality for JSON-serialisable outputs.
 */
export interface CounterfactualResult {
    /** runId of the original run that was replayed. */
    originalRunId: string;
    /** runId assigned to the counterfactual replay run. */
    counterfactualRunId: string;
    /** Output produced by replaying with the original strategy / settings. */
    originalOutput: unknown;
    /** Output produced by replaying with the altered strategy / settings. */
    counterfactualOutput: unknown;
    /**
     * true iff both outputs are structurally compatible:
     *   - Same typeof (or both null).
     *   - If both are plain objects: same set of top-level keys (order-independent).
     */
    outputsCoherent: boolean;
    /**
     * true iff both outputs are byte-identical under JSON serialisation.
     * Implies outputsCoherent === true.
     */
    outputsIdentical: boolean;
    metadata: {
        /** Strategy swap details, present when alt_strategy was supplied. */
        strategySwapped?: {
            from: string;
            to: ComputeStrategyName;
        };
        /**
         * Difference in reported cost_usd between the two runs.
         * Positive = counterfactual was more expensive.
         * undefined when the runner does not populate cost_usd.
         */
        cost_delta_usd?: number;
        /**
         * Difference in wall-clock latency in milliseconds.
         * Positive = counterfactual was slower.
         */
        latency_delta_ms?: number;
        /** Number of LLM cache hits during the counterfactual run. */
        cacheHits: number;
        /** Number of LLM cache misses during the counterfactual run. */
        cacheMisses: number;
    };
}
/**
 * Thrown when alt_strategy is not one of the known ComputeStrategyName values.
 */
export declare class InvalidStrategyNameError extends Error {
    readonly name: string;
    constructor(name: string);
}
/**
 * Internal extension of ReplayContext carrying counterfactual overrides.
 * Passed to ReplayRunner.run() — the runner inspects these fields to swap
 * its compute configuration for the counterfactual execution.
 */
export interface CounterfactualReplayContext extends ReplayContext {
    /** When present, the runner MUST override its compute strategy with this name. */
    readonly strategyOverride?: ComputeStrategyName;
    /** When present, the runner SHOULD swap its verifier with this instance. */
    readonly verifierOverride?: Verifier;
    /** When present, the runner SHOULD apply this temperature value. */
    readonly temperatureOverride?: number;
}
/**
 * Replay the original cycle twice — once with its original config, once with
 * the alt overrides — and compare outputs.
 *
 * Both runs use the SAME virtualized clock, random, and LLM cache derived from
 * the original run's recorded artifacts. Only the compute strategy (and optional
 * verifier / temperature) differs.
 *
 * OFFLINE TOOL. Do NOT call from any live execution path.
 *
 * @param originalRunId  runId of the run to analyse counterfactually.
 * @param loader         Loader for the original trace + recorded artifacts.
 * @param runner         Runner that accepts CounterfactualReplayContext.
 *                       Contract: runner.run() MUST honour ctx.strategyOverride
 *                       when present.
 * @param opts           Counterfactual overrides (at least one should differ
 *                       from the original to be meaningful).
 */
export declare function replayCounterfactual(originalRunId: string, loader: ReplayLoader, runner: ReplayRunner, opts: CounterfactualOptions): Promise<CounterfactualResult>;
//# sourceMappingURL=replay-with-alt.d.ts.map