/**
 * ADR-111 miner slice 5b-i — the deterministic LLM record/replay SCAFFOLD.
 *
 * The certifying run (slice 5) introduces the miner's first NON-deterministic,
 * LLM-backed components (the live `DraftExtractor` / `DraftClassifier` adapters,
 * slice 5b-ii). The cohort panel's central answer (consolidated fold A, 4/4) is
 * that those live outputs must be FROZEN into a recorded replay artifact so the
 * scorer + falsification harness can re-run the certifying experiment ZERO-LLM,
 * byte-deterministically, and auditably — "arguably contract-MANDATED" by §6
 * (fail-loud, no degrade) + §8 (every decision ledgered) + Tenet-15.
 *
 * THIS file is the deterministic record/replay scaffold proven in isolation with
 * a STUB orchestrator: NO live LLM, NO network, NO prompts (those are slice
 * 5b-ii, which populates the provenance block from the real adapter). It defines:
 *
 *   - the `llm-replay.v1` Zod artifact (two typed record sections + a provenance
 *     block), CLI-side — the replay artifact is a CLI-layer concern; core stays
 *     unaware of it;
 *   - the deterministic `inputKey` digests for the extractor + classifier ports
 *     (mirroring core's `deriveClaimId` — `sha256("<prefix>" + canonicalJson(...))`
 *     over IDENTITY fields only);
 *   - record/replay decorators (generic over the port) that wrap the core ports;
 *   - the EXTERNAL-expected-hash integrity gate (fold B — a self-hash the artifact
 *     validates against itself is circular; a content+hash co-rewrite would pass).
 *
 * Determinism discipline: this module is `new Date()` / `Math.random()` -free. A
 * recorded `[]` (extractor) or `{behavioral, error-default}` (classifier) is a
 * REAL row — present in the map, distinguishable from a missing key (a replay
 * MISS is a corpus-integrity failure, never a safe-default).
 *
 * Reuse (Tenet-21): the canonical key-sorted serializer (`canonicalStringify`),
 * the full-digest hash (`calculateDeterministicHash` shape), the `deriveClaimId`
 * identity-fields-only pattern, and the wind-tunnel's external-expected-hash
 * integrity discipline (`verifyControlIntegrity`) are all reused, not reinvented.
 */
import { z } from 'zod';
import type { ClassifierResult, DraftResult, ExtractStageResult, ReviewThreadContent } from '@mmnto/totem';
type DraftCandidate = ExtractStageResult['drafts'][number];
/** Discriminates the two record sections for the duplicate-key guard. */
export type AdapterKind = 'extractor' | 'classifier';
/**
 * A replay query hit an `inputKey` absent from the frozen records. This is a
 * CORPUS-INTEGRITY failure, never a recoverable per-PR condition: the frozen
 * experiment's premise is that every input the certifying run will ask for was
 * recorded. A miss means the corpus drifted out from under the replay (a new
 * input appeared, or a recorded one was dropped). Falling back to `[]` /
 * `{behavioral, error-default}` would absorb that drift silently and let the
 * certifying verdict diverge from the frozen one undetected — so we throw.
 */
export declare class ReplayMissError extends Error {
    readonly adapterKind: AdapterKind;
    readonly inputKey: string;
    constructor(adapterKind: AdapterKind, inputKey: string);
}
/**
 * The loaded replay fixture's content-hash does not match the EXTERNAL expected
 * hash injected at construction (fold B). The expected hash is supplied by the
 * caller (5c sources it from a committed lock), NOT embedded in the artifact —
 * an embedded self-hash would be circular (a content+hash co-rewrite passes its
 * own check). A mismatch means the fixture was tampered with or drifted; the
 * replay must NOT proceed, so we throw AT CONSTRUCTION (before any query).
 */
export declare class FixtureIntegrityError extends Error {
    readonly expectedHash: string;
    readonly actualHash: string;
    constructor(expectedHash: string, actualHash: string);
}
/**
 * Recording the same `(adapterKind, inputKey)` twice with (potentially)
 * different outputs. The record sink is APPEND-ONCE: a duplicate is never
 * last-write-wins (that would silently launder a non-deterministic adapter's
 * second answer over its first). The recording run must be deterministic, so a
 * duplicate key is a producer bug → throw.
 */
export declare class DuplicateRecordError extends Error {
    readonly adapterKind: AdapterKind;
    readonly inputKey: string;
    constructor(adapterKind: AdapterKind, inputKey: string);
}
/**
 * Deterministic extractor inputKey (fold D). `sha256(canonicalJson({ keyVersion,
 * pr, mergeCommitSha, threads: <normalized eligible threads> }))`. MUST include
 * `mergeCommitSha` (provenance identity). The eligible set is normalized so
 * provider thread/comment order can't change the key; resolved/outdated threads
 * are excluded (the port never sees them). Mirrors `deriveClaimId`: the version
 * is BOTH a payload field and a digest-input prefix.
 */
export declare function extractorInputKey(content: ReviewThreadContent): string;
/**
 * Deterministic classifier inputKey (fold D). `sha256(canonicalJson({
 * keyVersion, provenance, dslSource, draftRef }))`. The classifier does NOT
 * dedupe drafts — TWO drafts from the SAME provenance must not collide to one
 * key — so `draftRef` (a stable ordinal/ref the caller supplies, e.g. the slice-3
 * per-(pr, ordinal) candidate ref) disambiguates them. Without it, N drafts with
 * an identical body from one PR would map to one record and lose N-1 outputs.
 */
export declare function classifierInputKey(draft: DraftCandidate, draftRef: string): string;
/**
 * Run-level provenance block. In 5b-i these fields are populated by the (stub)
 * caller — the SCHEMA and the integrity gate covering them are what this slice
 * builds; 5b-ii populates them from the live adapter. They pin the exact frozen
 * experiment (prompt + model + adapter + key version + tool version) so a replay
 * is reproducible and a provenance drift is detectable. Provenance lives OUTSIDE
 * the records map (the records block is strictly `inputKey → output`).
 */
export declare const ReplayProvenanceSchema: z.ZodObject<{
    /** sha256 of the frozen draft/classify prompt TEMPLATE (the decaying-prompt pin). */
    promptTemplateHash: z.ZodString;
    /** sha256 of the frozen system prompt. */
    systemPromptHash: z.ZodString;
    /** LLM provider id (e.g. `anthropic` / `gemini` / `openai`). */
    provider: z.ZodString;
    /** Model id (e.g. a pinned model snapshot). */
    model: z.ZodString;
    /** Decode temperature the frozen outputs were produced at. */
    temperature: z.ZodNumber;
    /** The orchestrator build the live adapter ran under. */
    orchestratorVersion: z.ZodString;
    /** Which port adapter produced these records (`extractor` / `classifier` / a combined run). */
    adapterKind: z.ZodString;
    /** The inputKey schema version (so a key-shape change is recorded, not silent). */
    keyVersion: z.ZodString;
    /** The totem/CLI version that froze the artifact. */
    totemVersion: z.ZodString;
}, "strip", z.ZodTypeAny, {
    model: string;
    temperature: number;
    provider: string;
    promptTemplateHash: string;
    systemPromptHash: string;
    orchestratorVersion: string;
    adapterKind: string;
    keyVersion: string;
    totemVersion: string;
}, {
    model: string;
    temperature: number;
    provider: string;
    promptTemplateHash: string;
    systemPromptHash: string;
    orchestratorVersion: string;
    adapterKind: string;
    keyVersion: string;
    totemVersion: string;
}>;
export type ReplayProvenance = z.infer<typeof ReplayProvenanceSchema>;
/**
 * The records block: STRICTLY `inputKey → the port's raw return value`. A
 * recorded `[]` (extractor) / `{behavioral, error-default}` (classifier) is a
 * REAL row, distinct from a missing key. NEVER write `durationMs` / `recordedAt`
 * / local-user / run-id into a record — those are non-deterministic / identifying
 * metadata that would corrupt the content-hash and break the frozen-experiment
 * premise. The maps are plain `Record<inputKey, output>`; record keys are
 * written SORTED by the canonical serializer (clean git diffs).
 */
/**
 * CLI-side validation of a recorded `ClassifierResult` (GCA #2209 + the cohort
 * panel's "replay artifact schema is a CLI-layer concern", gemini): a LOCAL Zod
 * schema rather than a static runtime import of core's `ClassifierResultSchema`
 * (which would pull the heavy `@mmnto/totem` barrel onto the CLI-startup path).
 * Mirrors core's shape AND its refinement (`error-default` ⟹ `behavioral`, the
 * low-privilege safe-default) so a recorded `{structural, error-default}` is
 * rejected. A test asserts parity with core, so this duplication can't silently
 * drift if core's `ClassifierResult` changes.
 */
export declare const ClassifierResultLocalSchema: z.ZodEffects<z.ZodObject<{
    disposition: z.ZodEnum<["structural", "behavioral"]>;
    dispositionSource: z.ZodEnum<["classified", "error-default"]>;
}, "strip", z.ZodTypeAny, {
    disposition: "structural" | "behavioral";
    dispositionSource: "classified" | "error-default";
}, {
    disposition: "structural" | "behavioral";
    dispositionSource: "classified" | "error-default";
}>, {
    disposition: "structural" | "behavioral";
    dispositionSource: "classified" | "error-default";
}, {
    disposition: "structural" | "behavioral";
    dispositionSource: "classified" | "error-default";
}>;
/**
 * CLI-side validation of a recorded `DraftResult` (GCA #2209 + the panel's "replay
 * artifact schema is a CLI-layer concern"): a LOCAL Zod schema rather than a static
 * runtime import of core's `DraftResultSchema` (which would pull the heavy
 * `@mmnto/totem` barrel onto the CLI-startup path). Mirrors core's shape AND its
 * "cause iff empty" refinement LOGIC (the `NoDraftCauseSchema` enum, including the
 * replay-migration-only `legacy-unknown`). Parity is accept/reject EQUIVALENCE,
 * locked by a test — the local ZodError `message`/`path` stay intentionally concise
 * (matching the `ClassifierResultLocalSchema` sibling), not byte-identical to core.
 */
export declare const DraftResultLocalSchema: z.ZodEffects<z.ZodObject<{
    drafts: z.ZodArray<z.ZodString, "many">;
    noDraftCause: z.ZodOptional<z.ZodEnum<["invoke-error", "empty-output", "none-sentinel", "unparseable-shape", "non-array", "all-filtered", "legacy-unknown"]>>;
}, "strip", z.ZodTypeAny, {
    drafts: string[];
    noDraftCause?: "legacy-unknown" | "invoke-error" | "empty-output" | "none-sentinel" | "unparseable-shape" | "non-array" | "all-filtered" | undefined;
}, {
    drafts: string[];
    noDraftCause?: "legacy-unknown" | "invoke-error" | "empty-output" | "none-sentinel" | "unparseable-shape" | "non-array" | "all-filtered" | undefined;
}>, {
    drafts: string[];
    noDraftCause?: "legacy-unknown" | "invoke-error" | "empty-output" | "none-sentinel" | "unparseable-shape" | "non-array" | "all-filtered" | undefined;
}, {
    drafts: string[];
    noDraftCause?: "legacy-unknown" | "invoke-error" | "empty-output" | "none-sentinel" | "unparseable-shape" | "non-array" | "all-filtered" | undefined;
}>;
export declare const ReplayRecordsSchema: z.ZodObject<{
    /**
     * `inputKey → DraftExtractor.draft()` return — a `DraftResult` (`{drafts, noDraftCause?}`);
     * a recorded `{drafts:[], noDraftCause}` is a real row. BACKWARD-COMPAT (the α
     * cause-tag migration): a legacy fixture stored a bare `string[]` (pre-cause-tag),
     * accepted via the union so the committed cert-#1 fixture still parses + hashes
     * IDENTICALLY (the bare-array branch returns it unchanged). `ReplayDraftExtractor`
     * normalizes a legacy row to a `DraftResult` on read (empty → `legacy-unknown`);
     * fresh recordings always write the object form.
     */
    extractor: z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodEffects<z.ZodObject<{
        drafts: z.ZodArray<z.ZodString, "many">;
        noDraftCause: z.ZodOptional<z.ZodEnum<["invoke-error", "empty-output", "none-sentinel", "unparseable-shape", "non-array", "all-filtered", "legacy-unknown"]>>;
    }, "strip", z.ZodTypeAny, {
        drafts: string[];
        noDraftCause?: "legacy-unknown" | "invoke-error" | "empty-output" | "none-sentinel" | "unparseable-shape" | "non-array" | "all-filtered" | undefined;
    }, {
        drafts: string[];
        noDraftCause?: "legacy-unknown" | "invoke-error" | "empty-output" | "none-sentinel" | "unparseable-shape" | "non-array" | "all-filtered" | undefined;
    }>, {
        drafts: string[];
        noDraftCause?: "legacy-unknown" | "invoke-error" | "empty-output" | "none-sentinel" | "unparseable-shape" | "non-array" | "all-filtered" | undefined;
    }, {
        drafts: string[];
        noDraftCause?: "legacy-unknown" | "invoke-error" | "empty-output" | "none-sentinel" | "unparseable-shape" | "non-array" | "all-filtered" | undefined;
    }>]>>;
    /** `inputKey → DraftClassifier.classify()` return (a `ClassifierResult`). */
    classifier: z.ZodRecord<z.ZodString, z.ZodEffects<z.ZodObject<{
        disposition: z.ZodEnum<["structural", "behavioral"]>;
        dispositionSource: z.ZodEnum<["classified", "error-default"]>;
    }, "strip", z.ZodTypeAny, {
        disposition: "structural" | "behavioral";
        dispositionSource: "classified" | "error-default";
    }, {
        disposition: "structural" | "behavioral";
        dispositionSource: "classified" | "error-default";
    }>, {
        disposition: "structural" | "behavioral";
        dispositionSource: "classified" | "error-default";
    }, {
        disposition: "structural" | "behavioral";
        dispositionSource: "classified" | "error-default";
    }>>;
}, "strip", z.ZodTypeAny, {
    extractor: Record<string, string[] | {
        drafts: string[];
        noDraftCause?: "legacy-unknown" | "invoke-error" | "empty-output" | "none-sentinel" | "unparseable-shape" | "non-array" | "all-filtered" | undefined;
    }>;
    classifier: Record<string, {
        disposition: "structural" | "behavioral";
        dispositionSource: "classified" | "error-default";
    }>;
}, {
    extractor: Record<string, string[] | {
        drafts: string[];
        noDraftCause?: "legacy-unknown" | "invoke-error" | "empty-output" | "none-sentinel" | "unparseable-shape" | "non-array" | "all-filtered" | undefined;
    }>;
    classifier: Record<string, {
        disposition: "structural" | "behavioral";
        dispositionSource: "classified" | "error-default";
    }>;
}>;
export type ReplayRecords = z.infer<typeof ReplayRecordsSchema>;
/** Stable artifact-format tag — bumped if the envelope shape changes. */
export declare const REPLAY_ARTIFACT_KIND = "llm-replay.v1";
/** The full `llm-replay.v1` artifact: format tag + provenance + the two record sections. */
export declare const ReplayArtifactSchema: z.ZodObject<{
    kind: z.ZodLiteral<"llm-replay.v1">;
    provenance: z.ZodObject<{
        /** sha256 of the frozen draft/classify prompt TEMPLATE (the decaying-prompt pin). */
        promptTemplateHash: z.ZodString;
        /** sha256 of the frozen system prompt. */
        systemPromptHash: z.ZodString;
        /** LLM provider id (e.g. `anthropic` / `gemini` / `openai`). */
        provider: z.ZodString;
        /** Model id (e.g. a pinned model snapshot). */
        model: z.ZodString;
        /** Decode temperature the frozen outputs were produced at. */
        temperature: z.ZodNumber;
        /** The orchestrator build the live adapter ran under. */
        orchestratorVersion: z.ZodString;
        /** Which port adapter produced these records (`extractor` / `classifier` / a combined run). */
        adapterKind: z.ZodString;
        /** The inputKey schema version (so a key-shape change is recorded, not silent). */
        keyVersion: z.ZodString;
        /** The totem/CLI version that froze the artifact. */
        totemVersion: z.ZodString;
    }, "strip", z.ZodTypeAny, {
        model: string;
        temperature: number;
        provider: string;
        promptTemplateHash: string;
        systemPromptHash: string;
        orchestratorVersion: string;
        adapterKind: string;
        keyVersion: string;
        totemVersion: string;
    }, {
        model: string;
        temperature: number;
        provider: string;
        promptTemplateHash: string;
        systemPromptHash: string;
        orchestratorVersion: string;
        adapterKind: string;
        keyVersion: string;
        totemVersion: string;
    }>;
    records: z.ZodObject<{
        /**
         * `inputKey → DraftExtractor.draft()` return — a `DraftResult` (`{drafts, noDraftCause?}`);
         * a recorded `{drafts:[], noDraftCause}` is a real row. BACKWARD-COMPAT (the α
         * cause-tag migration): a legacy fixture stored a bare `string[]` (pre-cause-tag),
         * accepted via the union so the committed cert-#1 fixture still parses + hashes
         * IDENTICALLY (the bare-array branch returns it unchanged). `ReplayDraftExtractor`
         * normalizes a legacy row to a `DraftResult` on read (empty → `legacy-unknown`);
         * fresh recordings always write the object form.
         */
        extractor: z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodEffects<z.ZodObject<{
            drafts: z.ZodArray<z.ZodString, "many">;
            noDraftCause: z.ZodOptional<z.ZodEnum<["invoke-error", "empty-output", "none-sentinel", "unparseable-shape", "non-array", "all-filtered", "legacy-unknown"]>>;
        }, "strip", z.ZodTypeAny, {
            drafts: string[];
            noDraftCause?: "legacy-unknown" | "invoke-error" | "empty-output" | "none-sentinel" | "unparseable-shape" | "non-array" | "all-filtered" | undefined;
        }, {
            drafts: string[];
            noDraftCause?: "legacy-unknown" | "invoke-error" | "empty-output" | "none-sentinel" | "unparseable-shape" | "non-array" | "all-filtered" | undefined;
        }>, {
            drafts: string[];
            noDraftCause?: "legacy-unknown" | "invoke-error" | "empty-output" | "none-sentinel" | "unparseable-shape" | "non-array" | "all-filtered" | undefined;
        }, {
            drafts: string[];
            noDraftCause?: "legacy-unknown" | "invoke-error" | "empty-output" | "none-sentinel" | "unparseable-shape" | "non-array" | "all-filtered" | undefined;
        }>]>>;
        /** `inputKey → DraftClassifier.classify()` return (a `ClassifierResult`). */
        classifier: z.ZodRecord<z.ZodString, z.ZodEffects<z.ZodObject<{
            disposition: z.ZodEnum<["structural", "behavioral"]>;
            dispositionSource: z.ZodEnum<["classified", "error-default"]>;
        }, "strip", z.ZodTypeAny, {
            disposition: "structural" | "behavioral";
            dispositionSource: "classified" | "error-default";
        }, {
            disposition: "structural" | "behavioral";
            dispositionSource: "classified" | "error-default";
        }>, {
            disposition: "structural" | "behavioral";
            dispositionSource: "classified" | "error-default";
        }, {
            disposition: "structural" | "behavioral";
            dispositionSource: "classified" | "error-default";
        }>>;
    }, "strip", z.ZodTypeAny, {
        extractor: Record<string, string[] | {
            drafts: string[];
            noDraftCause?: "legacy-unknown" | "invoke-error" | "empty-output" | "none-sentinel" | "unparseable-shape" | "non-array" | "all-filtered" | undefined;
        }>;
        classifier: Record<string, {
            disposition: "structural" | "behavioral";
            dispositionSource: "classified" | "error-default";
        }>;
    }, {
        extractor: Record<string, string[] | {
            drafts: string[];
            noDraftCause?: "legacy-unknown" | "invoke-error" | "empty-output" | "none-sentinel" | "unparseable-shape" | "non-array" | "all-filtered" | undefined;
        }>;
        classifier: Record<string, {
            disposition: "structural" | "behavioral";
            dispositionSource: "classified" | "error-default";
        }>;
    }>;
}, "strip", z.ZodTypeAny, {
    kind: "llm-replay.v1";
    provenance: {
        model: string;
        temperature: number;
        provider: string;
        promptTemplateHash: string;
        systemPromptHash: string;
        orchestratorVersion: string;
        adapterKind: string;
        keyVersion: string;
        totemVersion: string;
    };
    records: {
        extractor: Record<string, string[] | {
            drafts: string[];
            noDraftCause?: "legacy-unknown" | "invoke-error" | "empty-output" | "none-sentinel" | "unparseable-shape" | "non-array" | "all-filtered" | undefined;
        }>;
        classifier: Record<string, {
            disposition: "structural" | "behavioral";
            dispositionSource: "classified" | "error-default";
        }>;
    };
}, {
    kind: "llm-replay.v1";
    provenance: {
        model: string;
        temperature: number;
        provider: string;
        promptTemplateHash: string;
        systemPromptHash: string;
        orchestratorVersion: string;
        adapterKind: string;
        keyVersion: string;
        totemVersion: string;
    };
    records: {
        extractor: Record<string, string[] | {
            drafts: string[];
            noDraftCause?: "legacy-unknown" | "invoke-error" | "empty-output" | "none-sentinel" | "unparseable-shape" | "non-array" | "all-filtered" | undefined;
        }>;
        classifier: Record<string, {
            disposition: "structural" | "behavioral";
            dispositionSource: "classified" | "error-default";
        }>;
    };
}>;
export type ReplayArtifact = z.infer<typeof ReplayArtifactSchema>;
/**
 * Serialize an artifact to canonical, key-SORTED JSON, PRETTY-printed for a
 * committable artifact + clean diffs. Record keys land sorted because the
 * canonicalizer recursively sorts object keys — so re-freezing in a different
 * insertion order is a no-op diff.
 *
 * NOTE (greptile/CR #2209): the content-hash (`computeArtifactHash`) is computed
 * over the MINIFIED canonical form (`canonicalJson`), NOT these pretty-printed
 * bytes. Both run through the same `canonicalize` (so they never drift on key
 * order), but they are NOT byte-identical — to verify integrity always call
 * `computeArtifactHash(loadedArtifact)`; never `sha256` the raw file bytes.
 */
export declare function serializeReplayArtifact(artifact: ReplayArtifact): string;
/**
 * The artifact CONTENT-HASH (fold B + fold F): sha256 over the canonically-
 * serialized WHOLE artifact (kind + provenance + records). Deterministic +
 * git-independent (the pure replay path has no git dependency — contrast the
 * wind-tunnel's `git hash-object`, which 5c may switch to for wind-tunnel
 * consistency, out of scope here). Hashing the WHOLE artifact (not records-only)
 * means the integrity gate ALSO COVERS the provenance block — so a prompt / model
 * / key-version edit (e.g. `promptTemplateHash`) WITHOUT a re-record trips the
 * gate (fold F: a prompt change must force a re-record, never silently serve
 * stale outputs under a changed prompt). The expected hash is EXTERNAL (caller-
 * injected; 5c sources it from a committed lock) — never embedded (a self-hash
 * the artifact validates against itself is circular: a content+hash co-rewrite
 * would pass its own check).
 */
export declare function computeArtifactHash(artifact: ReplayArtifact): string;
/**
 * The append-once record sink the `Recording*` decorators write into. Holds the
 * in-progress records map; `freeze()` produces the immutable artifact. A
 * duplicate `(adapterKind, inputKey)` throws `DuplicateRecordError` — never
 * last-write-wins (a second output for the same input is a non-determinism leak
 * the recording run must surface, not absorb).
 */
export declare class ReplayRecordSink {
    private readonly extractor;
    private readonly classifier;
    recordExtractor(inputKey: string, output: DraftResult): void;
    recordClassifier(inputKey: string, output: ClassifierResult): void;
    /** Snapshot the records as a plain (Zod-validated) object — keys land sorted on serialize. */
    records(): ReplayRecords;
    /** Assemble the full `llm-replay.v1` artifact from the recorded sink + a provenance block. */
    freeze(provenance: ReplayProvenance): ReplayArtifact;
}
/**
 * Records every `DraftExtractor.draft()` call's inputKey → raw `DraftResult` output
 * into the sink, then passes the value THROUGH unchanged. The recorded value is the
 * PORT's return (pre-core-funnel) — a recorded `{drafts:[], noDraftCause}` is a real
 * row that freezes the NO-DRAFT cause for the replay. A duplicate inputKey throws
 * (via the sink).
 */
export declare class RecordingDraftExtractor {
    private readonly wrapped;
    private readonly sink;
    constructor(wrapped: {
        draft(content: ReviewThreadContent): Promise<DraftResult>;
    }, sink: ReplayRecordSink);
    draft(content: ReviewThreadContent): Promise<DraftResult>;
}
/**
 * Records every `DraftClassifier.classify()` call's inputKey → raw
 * `ClassifierResult` output into the sink, then passes it through unchanged. The
 * caller supplies a `draftRef` (the disambiguator for multiple drafts from one
 * provenance — fold D). A duplicate inputKey throws (via the sink).
 *
 * `classify` does not take a `draftRef` in the core port signature, so the
 * decorator binds it via a per-draft ref RESOLVER the caller supplies (e.g. the
 * slice-3 per-(pr, ordinal) candidate ref). The resolver is pure + deterministic.
 */
export declare class RecordingDraftClassifier {
    private readonly wrapped;
    private readonly sink;
    private readonly draftRef;
    constructor(wrapped: {
        classify(draft: DraftCandidate): Promise<ClassifierResult>;
    }, sink: ReplayRecordSink, draftRef: (draft: DraftCandidate) => string);
    classify(draft: DraftCandidate): Promise<ClassifierResult>;
}
/**
 * PURE replay of `DraftExtractor` — zero live LLM / network calls. Computes the
 * inputKey for the requested content, looks it up in the frozen records:
 *   - HIT  → return the recorded `DraftResult` (a recorded empty result is a real
 *            row; a legacy bare-`string[]` row is normalized to a `DraftResult`);
 *   - MISS → throw `ReplayMissError` (NEVER fall back to an empty result).
 *
 * Integrity (fold B + F): the constructor takes the EXTERNAL expected content-
 * hash, computes the actual WHOLE-ARTIFACT hash (records + provenance), and throws
 * `FixtureIntegrityError` AT CONSTRUCTION on mismatch — so a tampered/drifted
 * fixture (records OR a prompt-provenance edit) can never serve a single replay.
 */
export declare class ReplayDraftExtractor {
    private readonly records;
    constructor(fixture: ReplayArtifact, expectedHash: string);
    draft(content: ReviewThreadContent): Promise<DraftResult>;
}
/**
 * PURE replay of `DraftClassifier` — zero live calls. Computes the inputKey
 * (using the caller's `draftRef` resolver), looks it up:
 *   - HIT  → return the recorded `ClassifierResult` (including a recorded
 *            `{behavioral, error-default}` — a real row);
 *   - MISS → throw `ReplayMissError` (NEVER fall back to the safe-default).
 *
 * Same external-expected-hash integrity gate at construction (fold B).
 */
export declare class ReplayDraftClassifier {
    private readonly records;
    private readonly draftRef;
    constructor(fixture: ReplayArtifact, expectedHash: string, draftRef: (draft: DraftCandidate) => string);
    classify(draft: DraftCandidate): Promise<ClassifierResult>;
}
export {};
//# sourceMappingURL=spine-llm-replay.d.ts.map