import type { McpServerSpec, RunnerDeps, TaskSpec } from "./types.js";
import type { ToolPolicy } from "./tool-policy.js";
/** The closed set of administratively lockable configuration keys. Adding a member is a deliberate
 *  edit HERE (tsc forces the registry row), never a free-form string. */
export type LockedKey = "mcp" | "toolPolicy" | "compliancePosture" | "retentionPolicy";
/**
 * The closed locked-key registry: each key names the exact `TaskSpec` fields it guards. Keys whose
 * field set is EMPTY guard deployment-only surfaces (`compliancePosture` rides
 * `RunnerDeps.compliancePostureResolver`, `retentionPolicy` rides `RunnerDeps.retentionPolicy`) —
 * there is structurally no untrusted spec field to refuse, so for those the lock is a declaration
 * consumed elsewhere (the retention startup validation keys off `retentionPolicy` being locked; the
 * server control plane reads the declaration for its own sync gate). `satisfies` keeps the row set
 * and the {@link LockedKey} union in lockstep — tsc refuses a key without a row and a row without a
 * key.
 */
export declare const LOCKED_KEY_REGISTRY: {
    readonly mcp: {
        readonly specFields: readonly ["mcp"];
    };
    readonly toolPolicy: {
        readonly specFields: readonly ["toolPolicy", "basePolicyForResumeEdit"];
    };
    readonly compliancePosture: {
        readonly specFields: readonly [];
    };
    readonly retentionPolicy: {
        readonly specFields: readonly [];
    };
};
/** A deployment's lock declaration ({@link RunnerDeps.lockedConfig}). Config-time, trusted. */
export interface LockedConfig {
    /** The keys this deployment locks. Wire-validated against {@link LOCKED_KEY_REGISTRY} at the
     *  preflight door — an unknown member is a loud `config.locked_registry` refusal, never a no-op. */
    keys: readonly LockedKey[];
}
/** The preflight's resolved snapshot — the ONLY thing downstream task assembly reads for the
 *  guarded slots (never the raw `spec.mcp` / `spec.toolPolicy` fields). */
export interface LockedPreflight {
    /** The validated lock set (empty when the deployment declares none). */
    lockedKeys: ReadonlySet<LockedKey>;
    /** Effective MCP server list for this task: a validated, frozen SNAPSHOT of `spec.mcp` when the
     *  key is unlocked (see {@link snapshotAndValidateMcpEntries} — the content-class declaration is read once
     *  and judged here, so no mint site downstream can be handed a different value than the door
     *  approved); with `mcp` locked a spec-supplied value has already been refused, so this is always
     *  `undefined` (core has no deployment-level MCP seat — a locked deployment mounts no
     *  task-supplied servers). */
    mcp: TaskSpec["mcp"];
    /** Effective caller tool policy: the same `spec.toolPolicy ?? deps.toolPolicy` slot the gate has
     *  always enforced, resolved ONCE here. With `toolPolicy` locked, the deployment's own
     *  `deps.toolPolicy` is the whole answer (a spec-supplied policy has already been refused). */
    toolPolicy: ToolPolicy | undefined;
    /** F-012: the effective resume-edit re-adjudication OVERRIDE, resolved lock-aware in
     *  the SAME slot as {@link toolPolicy}. With `toolPolicy` locked, a spec-supplied
     *  `basePolicyForResumeEdit` has already been refused wholesale, so this is the deployment's own
     *  `deps.basePolicyForResumeEdit` (or undefined — the caller-policy fallback then applies at the use
     *  site). Unlocked: `spec.basePolicyForResumeEdit ?? deps.basePolicyForResumeEdit`. */
    basePolicyForResumeEdit: ToolPolicy | undefined;
}
/**
 * Validate a deployment's lock declaration against the closed registry. Fail-loud on any unknown
 * key (`config.locked_registry`): a security control that doesn't parse must refuse to arm, not
 * degrade to "that key silently unlocked". Exported for deployments that want the check at their
 * own startup; the task-preparation preflight runs it on every leg regardless (a mis-declared lock
 * then fails the first prepare instead of silently guarding nothing).
 */
export declare function resolveLockedKeys(config: LockedConfig | undefined): ReadonlySet<LockedKey>;
/**
 * design/378 — turn a caller-owned MCP entry list into FROZEN PLAIN DATA, reading every own property
 * exactly once.
 *
 * WHY A COPY. `McpServerSpec.contentOrigin` decides whether a server's tools mark the session's
 * memory, and the entry objects travel a long way: the preparation door validates them, then
 * `materializeMcpTools` connects them, then every mid-task refresh re-reads the same object. A value
 * read off a LIVE object is only true for as long as the object holds still, and the fail-open
 * direction is the reachable one — so both boundaries consume data instead.
 *
 * The read discipline is the load-bearing part, and it is why this is a spread rather than
 * "read the property, then copy the object": a getter answering ALTERNATING LEGAL values would
 * satisfy any number of re-reads (`"external"` to a validator, `"local"` to a mint site), and no
 * vocabulary guard anywhere has purchase on a legal value. One spread evaluates every own property
 * EXACTLY ONCE and materializes the result as plain data; every later reader — validator, connect,
 * refresh — then sees the same byte. Frozen so nothing downstream rewrites it.
 *
 * Boundary, stated: the copy is one level deep — nested option objects (transport, headers, env,
 * toolAxes) stay shared with the caller's entry exactly as before, because the axis this owns is the
 * content class; readers of the nested shapes normalize their own values (the transport DISCRIMINATOR
 * is derived, never echoed raw). Own ENUMERABLE properties only: an entry whose fields live on a
 * prototype was never the plain configuration record this type describes, and its absent class reads
 * fail-closed like any other absence.
 *
 * Exported because the SECOND boundary needs the identical guarantee: `materializeMcpTools` is public
 * and a library caller reaches it without passing any door, so it snapshots its own input through
 * this same function (idempotent over an already-frozen entry). One spelling, both entrances.
 */
export declare function snapshotMcpEntries(entries: readonly McpServerSpec[]): McpServerSpec[];
/**
 * The single preflight resolver: validate the lock declaration, refuse a spec that tries to occupy
 * a locked slot (`config.locked_key`, two-state — the whole prepare is rejected, nothing is
 * silently dropped or merged), and produce the resolved snapshot downstream assembly consumes.
 * Runs BEFORE any side effect of task preparation.
 */
export declare function preflightLockedConfig(spec: TaskSpec, deps: RunnerDeps): LockedPreflight;
