import type { PromptCatalog } from "./catalog/schema.js";
/** Deterministic canonical JSON (sorted keys) — the one identity encoding (the catalog digest, the identity, the
 *  center artifact digest). */
export declare function canonical(node: unknown): string;
/** `sha256:<hex>` over a canonical encoding. */
export declare function digestOf(node: unknown): string;
/** The bundled catalog's digest. Array positions that carry no meaning are normalized (sections by rank, messages and
 *  bands by id), so the digest does not depend on how a module lays out its arrays; variant order is meaning (first
 *  match wins) and stays. */
export declare function catalogDigestOf(catalog: PromptCatalog): string;
/** The inputs of a run's prompt identity. Only `center` is pinned (resolved by digest on resume); the rest are what
 *  the run computed, kept so a later run can say what changed. Absent `center` / `deploy` / `task` = that layer
 *  contributed nothing. */
export interface PromptIdentityLayers {
    readonly catalog: string;
    readonly renderers: Readonly<Record<string, number>>;
    /** The adopted center artifact's digest. */
    readonly center?: string;
    readonly deploy?: string;
    readonly task?: string;
    /** H(the run's selector values). */
    readonly binding: string;
}
/** A run's prompt identity inputs plus its pinned center layer's provenance — what the epoch record carries. */
export interface RunPromptIdentity {
    readonly layers: PromptIdentityLayers;
    readonly sourceRevision?: string;
}
/** The one identity digest over the four inputs. */
export declare function promptIdentityOf(layers: PromptIdentityLayers): string;
/** How a recorded epoch came to be: a legal boundary (`session_start`, `compaction`), or a record that code or
 *  inputs moved (`code_change`, naming the changed layers when they are known) or that only the selector values
 *  did (`selection_change`). */
export declare const PROMPT_EPOCH_ACTIVATIONS: readonly ["session_start", "compaction", "code_change", "selection_change"];
export type PromptEpochActivation = (typeof PROMPT_EPOCH_ACTIVATIONS)[number];
/** What a `code_change` record names as changed. `published_schema` is the one replacement of a retired-shape center
 *  pin by the current center layer. */
export declare const PROMPT_EPOCH_CHANGES: readonly ["catalog", "renderers", "deploy", "task", "published_schema"];
export type PromptEpochChange = (typeof PROMPT_EPOCH_CHANGES)[number];
/** The durable record, persisted as a first-class session entry and restated in every compaction entry's
 *  `details.promptEpoch`. */
export interface PromptEpochDescriptor {
    /** Monotonic per-session record counter. */
    readonly epoch: number;
    /** The run's prompt identity ({@link promptIdentityOf}). */
    readonly identity: string;
    readonly layers: PromptIdentityLayers;
    readonly activatedBy: PromptEpochActivation;
    /** Present only on `code_change` records whose changed layers are known. */
    readonly changed?: readonly PromptEpochChange[];
    /** Opaque publish provenance of the pinned center layer (present only with `layers.center`; never digested). */
    readonly sourceRevision?: string;
}
/** What a stored epoch record reads as on the resume path: a v3 pin, or a retired shape recognized by name. */
export type StoredPromptEpoch = {
    readonly kind: "pin";
    readonly descriptor: PromptEpochDescriptor;
} | {
    readonly kind: "legacy";
    readonly centerPinned: boolean;
};
/**
 * Shape-normalize an untrusted v3 descriptor — the current shape's one judge (the first reading of
 * {@link readStoredPromptEpoch}; a session backend judges a record with it). Strict: a bounded positive epoch, a full
 * digest identity that MATCHES its layers, the closed activation and change vocabularies, provenance only beside a
 * center layer. Members it does not read (a session entry's own `type` / `id` / `parentId` / `timestamp`) are ignored.
 * Undefined for anything else — including every retired shape.
 */
export declare function normalizePromptEpoch(raw: unknown): PromptEpochDescriptor | undefined;
/**
 * The resume path's reading of one stored record: a valid v3 pin, `legacy` (a retired shape, recognized by its field
 * names — nothing in it is parsed but whether `centerArtifactDigest` is a digest, the only value the retired reader
 * took for a pin), or undefined (malformed: the walk skips it).
 */
export declare function readStoredPromptEpoch(raw: unknown): StoredPromptEpoch | undefined;
/**
 * The record a run leaves at prepare, or undefined when the stored pin already names this run's identity.
 * - no record: `session_start` for a session with no prior conversation; otherwise `code_change` (a session that
 *   predates epochs — what changed is unknown);
 * - a v3 pin: the same identity ⇒ nothing; else `code_change` naming the changed code / input layers, or
 *   `selection_change` when only the selector values moved;
 * - `legacy`: `code_change` — naming `published_schema` when the retired record pinned a center artifact (the caller
 *   applied the center source's tri-state to it), otherwise unknown. The retired record's counter is not read; the
 *   v3 line starts at 1.
 */
export declare function prepareEpochRecord(stored: StoredPromptEpoch | undefined, layers: PromptIdentityLayers, ctx: {
    readonly priorConversation: boolean;
    readonly sourceRevision?: string;
}): PromptEpochDescriptor | undefined;
/**
 * The record a compaction restates or advances: the current pin restated when the run's identity is unchanged (the
 * boundary is stamped), otherwise a new record with the run's layers after the boundary — an adopted center
 * candidate, or an emptied center layer after an explicit revocation.
 */
export declare function selectCompactionEpoch(current: PromptEpochDescriptor | undefined, layers: PromptIdentityLayers, sourceRevision?: string): PromptEpochDescriptor;
