/**
 * # session/config — the sim config descriptor: canonicalize → ConfigId → the a57.14 envelope (kestrel-5zl.6)
 *
 * The comparison axis of Simulate is the **{@link AgentConfig} descriptor**: the same recorded tape graded
 * under N configs yields comparable {@link import("../blotter").Blotter}s, keyed by config. This module is
 * the CAPTURE side of that axis — three pure derivations, no wall clock, no RNG (RUNTIME §0):
 *
 *   1. {@link canonicalizeConfig} — `(AgentConfig) → a canonical, normalized descriptor`. Deterministic and
 *      ORDER-INSENSITIVE: the SAME field values in ANY key insertion order (top-level or nested) canonicalize
 *      byte-identically, via the Blotter's own sorted-key / drop-undefined canonicalizer (the agent-harness ADR (d)).
 *   2. {@link deriveConfigId} — `(canonical) → ConfigId = sha256(canonical)` (the agent-harness ADR (d)). The **grid
 *      column key** the config matrix (5zl.7 run-identity, 5zl.8 grid/leaderboard) keys a run by: same config
 *      ⇒ same id; ANY changed field ⇒ a DIFFERENT id (a config edit mints a new column, never contaminates an
 *      old one). The ConfigId is a SUPERSET of the envelope identity — it additionally folds the sampling axis
 *      (`temperature`/`thinkingLevel`), `format`, and the leaderboard `label`, none of which are envelope
 *      fields — so two runs differing only in `temperature` are different columns yet share every envelope field.
 *   3. {@link envelopeOf} / {@link envelopeForConfig} — map the canonical descriptor to the a57.14
 *      {@link ExperimentalEnvelope} (its INPUT half — the agent-harness ADR (d): one definition, never a second one), which
 *      the Simulate driver stamps onto the graded META so the finalized Blotter carries it. The `prompt_hash`
 *      carries a HASH, NEVER prompt/strategy content (the provenance fence, AGENTS.md §7).
 *
 * ## The descriptor → envelope field map (deliverable 1)
 *   ModelIdentity     provider → provider · model → model · version → version · trainingCutoff → training_cutoff
 *   RenderingIdentity tokenizer → tokenizer · renderingIdentity → rendering_identity   (format rides the ConfigId only)
 *   AuthorPolicy      promptHash → prompt_hash (a HASH) · toolPolicy → tool_policy · wakeSource → wake_source ·
 *                     corpusTier → corpus_tier
 *   Interface/harness face → face (http|sdk|cli|mcp) · adapter → adapter · adapterVersion → adapter_version
 *                     (m9i.2 owner tweaks — the m9i.7 tournament axes, mandatory-for-certified)
 *   injected          tokenAccounting → token_accounting   (off the deterministic record path)
 *   ConfigId-only     cachePolicy (kestrel-rul, System Profile v1.1 `cache policy`) — folds into the ConfigId
 *                     like `format`/`temperature`, but is DELIBERATELY NOT an envelope field: caching is
 *                     transport-side + off the graded path, so two policies grade identically yet mint
 *                     distinct grid columns (the m9i.5 append-only-vs-redraw / cache-on-off A/B).
 *                     cacheTtl (kestrel-wa0j.1) rides the same rule: a ConfigId-only transport axis (absent ⇒
 *                     provider default ⇒ existing ConfigIds are untouched), never an envelope field.
 *                     clockHonest + latencyBufferMs (ADR-0040 / kestrel-w7la.1) are ConfigId axes too, never
 *                     envelope fields (the a57.14 fourteen stay frozen): they fold in automatically via the
 *                     generic canonicalizer, so a clocked run — or a different buffer — NEVER shares a grid
 *                     column with an unclocked one (clock-honest wakes §4). Absent ⇒ latency-blind ⇒ every
 *                     existing ConfigId is byte-identical.
 *
 * ## Fail-closed by omission (the blast-radius rule, a57.14)
 * A NO-LLM Backtest ({@link import("./agent.ts").fixedPlanAgent} / `recordedAgent`, whose
 * {@link import("./agent.ts").BACKTEST_CONFIG} authors nothing — no `provider`/`version`/`promptHash`/…)
 * DECLARES no envelope: {@link declaresEnvelope} is false ⇒ no stamp ⇒ the Blotter stays `certified` (exactly
 * a57.14's "a bus declaring NO envelope stays certified", and "never fabricate identity"). Only a config that
 * declares authorship stamps — and a declared-but-INCOMPLETE identity (e.g. a blank `provider`) is stamped as
 * an incomplete envelope so a57.14's projector fails the Blotter closed to PROVISIONAL, never omitted (which
 * would certify-by-implication) and never silently defaulted.
 */
import type { AgentConfig } from "./agent.ts";
import type { ExperimentalEnvelope, SampledQualificationClaim } from "../bus/index.ts";
import { type Json } from "../canonical/json.ts";
/** The canonical, normalized config descriptor: a plain JSON object whose keys (top-level and nested) are
 * lexicographically sorted, so `JSON.stringify` is a byte-stable function of the DATA, never of insertion
 * order — the substrate {@link deriveConfigId} hashes. `Json` is the canonical value type
 * ({@link ../canonical/json.ts}); `deepSort` was a byte-identical copy now folded into that one owner. */
export type CanonicalConfig = {
    readonly [k: string]: Json;
};
/**
 * Canonicalize an {@link AgentConfig} into its normalized descriptor: sorted keys, dropped `undefined`,
 * recursive — the SAME {@link canonicalize} the Blotter serializes through, so the ConfigId and the Blotter
 * share one notion of "canonical". PURE and ORDER-INSENSITIVE — the same field values in any key order
 * (incl. the nested `tokenAccounting`) fold to byte-identical output. No wall clock, no RNG (RUNTIME §0).
 */
export declare function canonicalizeConfig(config: AgentConfig): CanonicalConfig;
/**
 * Derive the {@link ConfigId} — the deterministic **grid column key** — as `sha256(canonical)` (the agent-harness ADR
 * (d)). Re-canonicalizes its input so the id is stable even if handed a raw descriptor. Same config ⇒ same
 * 64-hex id; ANY changed field ⇒ a different id. Pure (no wall clock, no RNG).
 */
export declare function deriveConfigId(canonical: unknown): string;
/** The canonical descriptor with the {@link REPLICATE_AXIS_KEYS} (fillSeed) removed — the substrate the CELL
 * config axis hashes. Identical to {@link canonicalizeConfig} for a config that carries no replicate axis, so
 * a seedless run's cell axis equals its full ConfigId. Pure, order-insensitive. */
export declare function cellCanonicalConfig(config: AgentConfig): CanonicalConfig;
/**
 * The **cell config-axis id**: `deriveConfigId(cellCanonicalConfig(config))` — the full ConfigId with the
 * replicate axes (fillSeed) stripped. This is the config axis the grid {@link import("./run-identity.ts").CellKey
 * CellKey} keys on (m9i.2 owner tweak 1 — temperature-only variants are DISTINCT cells — reconciled with
 * ADR-0016: seed-only variants are REPLICATES in ONE cell, not distinct columns). The ONE definition shared by
 * the driver's `cell_config_id` stamp and the grid's CellKey/cellOf, so they can never drift. For a seedless
 * config it equals the full {@link deriveConfigId ConfigId}. Pure (no wall clock, no RNG).
 */
export declare function cellConfigId(config: AgentConfig): string;
/**
 * Derive the stamped `rendering_identity` from a renderer revision — the DRIFT-PROOF binding (ADR-0013(d),
 * SYSTEM-PROFILE.md `rendering_identity`). A content-addressed handle `sha256:${sha256("kestrel.rendering/" +
 * rev)}` (the codebase's {@link import("../catalog/session-catalog.ts") RenderingIdentity} handle idiom — the
 * analog of the catalog's NO-LLM machine-frame handle), NOT a free per-config string a human bumps.
 *
 * A REAL authoring run sets `renderingIdentity = deriveRenderingIdentity()`, so the identity is a function of
 * the renderer's actual revision: a renderer BEHAVIORAL change bumps {@link RENDERER_REVISION} ⇒ a DIFFERENT
 * handle ⇒ a DIFFERENT {@link deriveConfigId ConfigId}/{@link import("./run-identity.ts").CellKey CellKey} (a
 * fresh grid column, never a collapse into the old one — the drift m9i.24 closes). The default argument binds
 * to the ONE-place {@link RENDERER_REVISION} source (`src/frame/renderer-revision.ts`), so there is exactly one
 * place a renderer revision is declared. Pure — no wall clock, no RNG (RUNTIME §0).
 *
 * NO-CHURN: this is purely ADDITIVE — it does NOT touch {@link canonicalizeConfig}/{@link deriveConfigId}/
 * {@link cellConfigId}/{@link envelopeOf}, so every existing explicit-label ConfigId/CellKey/conformance-root/
 * grid pin is byte-identical; the derived value for the current renderer is a stable pin, and only a FUTURE
 * revision bump moves it.
 */
export declare function deriveRenderingIdentity(rendererRevision?: string): string;
/**
 * Does this config DECLARE an experimental envelope (i.e. is it an authoring run, not a NO-LLM Backtest)?
 * True iff it carries any {@link ENVELOPE_DECLARING_KEYS} field. A {@link import("./agent.ts").BACKTEST_CONFIG}
 * carries none ⇒ false ⇒ no envelope is stamped (fail-closed by omission — the Blotter stays `certified`,
 * a57.14). A config with a BLANK required field (e.g. `provider: ""`) still DECLARES (it carries the other
 * identity fields) ⇒ true ⇒ its incomplete envelope IS stamped so the projector fails it closed.
 */
export declare function declaresEnvelope(config: AgentConfig): boolean;
/**
 * Map a canonical descriptor to the a57.14 {@link ExperimentalEnvelope} (the 1:1 field map above). `format`,
 * `temperature`, `thinkingLevel`, and `label` are NOT envelope identity — they ride the ConfigId only. The
 * `prompt_hash` is carried verbatim as a HASH; this function never sees prompt/strategy content (the
 * provenance fence). Pure — a deterministic function of the descriptor.
 */
export declare function envelopeOf(canonical: CanonicalConfig): ExperimentalEnvelope;
/**
 * The envelope a Simulate run stamps for `config`, or `undefined` when the config declares none (a NO-LLM
 * Backtest — {@link declaresEnvelope} false ⇒ the driver stamps no `meta.envelope` ⇒ the Blotter stays
 * `certified`, a57.14). When it declares one, the canonicalized descriptor is mapped through
 * {@link envelopeOf} (complete ⇒ the projector stamps it + certifies; incomplete ⇒ the projector fails it
 * closed to PROVISIONAL — capture happens HERE, the fail-closed evaluation stays in a57.14). Pure.
 */
export declare function envelopeForConfig(config: AgentConfig): ExperimentalEnvelope | undefined;
/**
 * The `runSeed` a Simulate run realizes sampled (seeded-Bernoulli) fills under, or `undefined` when the
 * config declares none — in which case **the sampled channel is OFF** (fail-closed, ADR-0016 §5): the run
 * grades the deterministic floor + analytic expected totals only, taking no draws. A malformed seed (a
 * non-finite or non-integer value) is treated exactly like an absent one — the sampler is never armed off a
 * value that would not replay byte-identically, never a silent `0`.
 *
 * This is the ONE provenance read the Simulate driver (kestrel-9gu.8.3) uses to decide whether to construct
 * the engine with a seeded rng. It reads the SamplingConfig axis, NOT the envelope: `fillSeed` folds into the
 * full {@link deriveConfigId ConfigId} / {@link import("./run-identity.ts").SimRunId SimRunId} (each seed is a
 * distinct RUN) but is a **replicate axis** STRIPPED from the cell config axis ({@link cellConfigId}), so two
 * seeds share one {@link import("./run-identity.ts").CellKey CellKey} (replicates in one cell — ADR-0016
 * ensembles) while each graded bus — carrying different realized fills — hashes to a distinct SimRunId. Pure.
 */
export declare function fillSeedOf(config: AgentConfig): number | undefined;
/**
 * The owner-recorded {@link SampledQualificationClaim} a config carries (`sampledQualification`), or
 * `undefined` when it declares none — in which case **the qualification gate fails closed** and the
 * strict-cross floor stays the headline (kestrel-9gu.12; 9gu.8 AC#7). A malformed claim (a missing leg, a
 * non-boolean, an empty reference) is treated exactly like an absent one — never coerced onto a passing
 * shape (RUNTIME §8, via {@link readSampledQualificationClaim}).
 *
 * Like `fillSeed`, the claim folds into the {@link deriveConfigId ConfigId} (a qualification edit mints a
 * new grid column-run) but not the a57.14 envelope. As of kestrel-9gu.12 **no study has passed** — the
 * study is kestrel-9gu.8.6 — so no shipped config declares this; the field exists so the gate seam is
 * exercised end-to-end and flipping the headline later is DATA, not code. Pure.
 */
export declare function sampledQualificationOf(config: AgentConfig): SampledQualificationClaim | undefined;
//# sourceMappingURL=config.d.ts.map