import type { ToolFingerprintInput } from "../core/cache-break-detector.js";
/** Every prefix-shaping input a request carries — the CLASSIFICATION DOMAIN. Adding a field here
 *  without classifying it in {@link PREFIX_INPUT_CLASSIFICATION} is a compile error. */
export interface RawPrefixInputs {
    /** Provider namespace (cache namespaces never span providers). */
    provider: string;
    /** Model id (a switch is a new cache namespace). */
    modelId: string;
    /** The session's pinned prompt-epoch artifact digest (bundled+declarations identity). */
    artifactDigest: string;
    /** Presentation/policy axis: promptProfile + fable mitigations (prose forks on these). */
    promptProfile: string;
    fableMitigations: boolean;
    /** Physical block layout as SERVED (derived from the composed system blocks; single-block default). */
    layoutGroups: ReadonlyArray<{
        groupId: string;
        cacheControlBoundary: boolean;
    }>;
    /** The composed stable system text (digested — text never enters the snapshot object).
     *  UNSALTED by design, same rule as the tool wireSchemaDigest ("schemas are code"): a full-text
     *  sha of a LONG composed prompt is an equality oracle only for someone who already possesses the
     *  exact bytes — unlike the SHORT guessable manifest blocks (env facts, one-line memory) whose
     *  dictionary-preimage risk is why block hashes are salted. Cross-run comparability is the whole
     *  point of this identity; salting would destroy it. */
    stableSystemText: string;
    /** Wire-face tool projections (name/description/schema — the mounted set, post-defer). */
    toolWire: ReadonlyArray<ToolFingerprintInput>;
    /** Request-shaping controls that alter the wire body. `thinkingLevel: null` = no level declared (the
     *  request carries no thinking key — provider default), which is NOT the same request as an explicit
     *  `"off"` (the disable key) and so must not share its identity. */
    thinkingLevel: string | null;
    maxTokens: number | undefined;
    hasOutputSchema: boolean;
    /** Routing/audit fields — provably NOT part of the cacheable prefix. */
    sessionId: string;
    taskId: string | undefined;
    /** Per-call variables — never reusable, never identity. */
    turn: number;
    cacheRead: number;
}
export type PrefixInputClass = "cache-identity" | "volatile-no-reuse" | "proven-irrelevant";
/** The EXHAUSTIVE classification (§10.2). The `satisfies` bound is the CI gate: a new
 *  {@link RawPrefixInputs} field fails typecheck until classified here; the runtime pin
 *  (`test/turn-snapshot.test.ts`) asserts totality survives refactors. Reasons ride inline. */
export declare const PREFIX_INPUT_CLASSIFICATION: {
    readonly provider: "cache-identity";
    readonly modelId: "cache-identity";
    readonly artifactDigest: "cache-identity";
    readonly promptProfile: "cache-identity";
    readonly fableMitigations: "cache-identity";
    readonly layoutGroups: "cache-identity";
    readonly stableSystemText: "cache-identity";
    readonly toolWire: "cache-identity";
    readonly thinkingLevel: "cache-identity";
    readonly maxTokens: "cache-identity";
    readonly hasOutputSchema: "cache-identity";
    readonly sessionId: "proven-irrelevant";
    readonly taskId: "proven-irrelevant";
    readonly turn: "volatile-no-reuse";
    readonly cacheRead: "volatile-no-reuse";
};
/** The lowering face (§10.1): version + wire form + that form's KNOWN intentional divergences. */
export interface LoweringRecord {
    version: string;
    form: "openai-merged" | "anthropic-blocks" | "other";
    intentionalDivergences: readonly string[];
}
export declare const LOWERING_VERSION = "sema-lowering@1";
export declare function loweringRecordFor(api: string): LoweringRecord;
/** The nine identity elements, individually digested (observable without shipping prompt text). */
export interface CacheIdentityElements {
    provider: string;
    modelId: string;
    artifactDigest: string;
    policyDigest: string;
    layoutDigest: string;
    stableSystemDigest: string;
    toolWireDigest: string;
    requestPolicyDigest: string;
    loweringVersion: string;
}
export interface TurnPromptSnapshot {
    elements: CacheIdentityElements;
    /** sha256(canonical(elements)) — the ONE nine-element identity value. */
    cacheIdentity: string;
    lowering: LoweringRecord;
    /** invoked after EVERY refresh so the run loop can emit the changed identity
     *  (`prompt.snapshot_changed` trace); traces must never keep claiming a superseded prefix. */
    onChange?: (snapshot: TurnPromptSnapshot) => void;
    /** Refresh the tool half (design/36 rematerialize follows the declared mid-run change). */
    refreshTools(toolWire: RawPrefixInputs["toolWire"]): void;
    /** Refresh the stable-system half (RB-31 adoption swap — pass the COMMITTED epoch digest so the
     *  identity never mixes old-artifact/new-prompt). */
    refreshStableSystem(stableSystemText: string, artifactDigest?: string): void;
    /** request-policy element follows mid-run wire changes (finalize lanes flip the
     *  thinking level; a served-model swap re-namespaces the cache). */
    refreshRequestPolicy(p: {
        thinkingLevel?: string;
        maxTokens?: number | null;
    }): void;
    refreshModel(m: {
        provider: string;
        modelId: string;
    }): void;
}
/** Build the run's snapshot from classified raw inputs. Volatile/irrelevant fields are accepted so
 *  the CLASSIFICATION stays total over everything callers hold, but only identity-class fields can
 *  reach the digest — enforced structurally (this function reads exactly the identity fields).
 *
 *  `promptHasher`: the digest applied to COMPOSED PROMPT TEXT — callers inject a
 *  KEYED/salted hasher (the run loop uses the per-process manifest salt): a fixed public prefix +
 *  short unknown suffix (an env fact, a memory note, a tenant string) makes an unsalted full-text
 *  sha ENUMERABLE, recreating exactly the disclosure the salted block hashes prevent. Consequence,
 *  documented: `stableSystemDigest` (and thus `cacheIdentity`) compares within one process only;
 *  cross-process reconciliation rides the CODE-class digests (artifact/toolWire — unsalted). */
export declare function buildTurnPromptSnapshot(raw: Omit<RawPrefixInputs, "turn" | "cacheRead">, api: string, promptHasher?: (text: string) => string): TurnPromptSnapshot;
