/**
 * The deployment seats a Runner may HOT-SWAP after construction — the vocabulary behind the ONE door,
 * `Runner.swapDeps` (runtask.ts).
 *
 * WHY ONE DOOR. Each hot-swappable seat used to be a verb of its own (`swapModels` was the first), and a
 * verb per seat restates the same three laws every time — validate the candidate BEFORE anything is
 * written, write the deps object ONCE (a swap is atomic: a refused candidate leaves the current deps
 * byte-identical), announce the change under a notice code — while the question "which seats may be
 * swapped at all" was answered by the list of verbs, i.e. by nothing a compiler could see. With one door
 * the laws are stated once, the swappable set is THIS closed list, and every seat carries its rows in
 * the tables beside it: the compiler refuses a member without its rows ({@link AssertAllKeysHandled}),
 * the door refuses a key outside the set at run time (never a silent ignore — a hot-config driver
 * handing `{ brain }` must learn that the brain is not a swappable seat, not watch nothing happen).
 *
 * WHAT A SWAP MEANS — the natural snapshot, one sentence for every ROUTING seat: a running task reads the
 * deps object it was handed at its prepare and holds that reference; a swap replaces the Runner's object, so
 * every LATER prepare reads the new seat and every in-flight leg keeps the value it prepared under.
 * Nothing is re-routed, re-priced or re-fenced mid-run; the divergence window is exactly the in-flight
 * legs' lifetime, by design (the `swapModels` precedent).
 *
 * …WITH ONE SEAT OUTSIDE IT, and the boundary is the point rather than the exception: `contextSettings` is
 * read LIVE by in-flight legs. The snapshot law protects the routing CARD — a request already in flight must
 * reach the endpoint it was priced, credentialed and fenced for, and re-reading any of that mid-run buys
 * nothing and breaks the request. A leg's usable WINDOW is not on that card: it is a setting about how much
 * conversation may accumulate before the leg summarizes, the reference implementation keeps it off the model
 * object for exactly this reason and re-reads it on every request (clamped to the model's physical window),
 * and an operator who lowers it is asking the legs running RIGHT NOW to compact sooner — which is the whole
 * request. So the window declarations live on their own seat (`context-settings.ts`), keyed by catalog word,
 * and the legs read them at every boundary, every recovery pass, the end-of-task summary and every request
 * build. Routing stays snapshotted; geometry follows the operator. The two are not the same question, and
 * one law over both could only be wrong about one of them.
 *
 * KEY PRESENCE IS THE INSTRUCTION: a key present on the candidate is REPLACED (an explicit `undefined`
 * CLEARS an optional seat back to its engine default — `readFace: undefined` ⇒ the deployment declares
 * no read face, `tiers: undefined` ⇒ no tier bindings); a key absent is KEPT. `Object.hasOwn`, never
 * truthiness, so the two spellings cannot be confused. An EMPTY candidate is refused: a swap that names
 * no seat is a caller defect, not a no-op.
 */
import type { AssertAllKeysHandled } from "./ask-origin.js";
import type { RunnerDeps } from "./runner-deps.js";
import { type ReadDenyDeploymentSeat } from "./read-face-seats.js";
/**
 * The closed set of hot-swappable deployment seats.
 *  - `models`   — the model catalog generation (the same-name redirect, re-pricing and retirement rules
 *                 of the former `swapModels`: a string ref resolves against the new catalog at the next
 *                 prepare; a `Model` object a leg already holds is untouched).
 *  - `tiers`    — the tier bindings, a BINDING OVER a catalog: it may only be swapped together with
 *                 `models` (the door refuses `tiers` alone — re-expanding bindings over an already
 *                 expanded catalog would keep the retired tier words as ordinary keys, which is exactly
 *                 the stale-generation shape the swap exists to end). Omitted beside `models` ⇒ the
 *                 current bindings are re-applied over the new catalog; present (including `undefined`)
 *                 ⇒ replaced.
 *  - `readFace` — the deployment's read-face declaration ({@link RunnerDeps.readFace}); screened by the
 *                 same value gate every prepare applies (`assertContainmentFaceValue`: `"open"` | `"roots"`
 *                 | absent, anything else refused loudly). The RESOLVED face of a leg is still the
 *                 resolver's business (task seat, governance, the read-only mount); the swap changes the
 *                 deployment seat that resolution reads.
 *  - `writeFace` — the deployment's write-face declaration ({@link RunnerDeps.writeFace}); the read seat's
 *                 twin (same value gate, same in-flight snapshot rule, its own notice) and independent of it.
 *  - `contextSettings` — the per-model context-window overlay ({@link RunnerDeps.contextSettings}); screened
 *                 by the same value gate construction applies (`assertContextSettingsValue`). THE ONE SEAT
 *                 IN-FLIGHT LEGS RE-READ — see the header: it carries geometry, not route.
 *  - `readDenyPatterns` / `readDenyBuiltinTiers` / `readDenyBuiltinExclude` — the deployment's read-deny
 *                 declaration (additions, built-in tier selection, built-in row removal); screened by the
 *                 gates a prepare applies ({@link screenReadDenySeat}). A resumed leg compiles against the
 *                 seats in force at its prepare (the checkpoint keeps additions only, stricter-wins).
 */
export declare const SWAPPABLE_DEP_SEATS: readonly ["models", "tiers", "readFace", "writeFace", "contextSettings", "readDenyPatterns", "readDenyBuiltinTiers", "readDenyBuiltinExclude"];
export type SwappableDepSeat = (typeof SWAPPABLE_DEP_SEATS)[number];
/** The candidate a swap takes: the swappable seats of {@link RunnerDeps}, each optional (presence = instruction). */
export type SwappableDeps = Pick<RunnerDeps, SwappableDepSeat>;
/** Whether a key names a swappable seat. */
export declare function isSwappableDepSeat(k: unknown): k is SwappableDepSeat;
/**
 * Which notice a seat's successful swap is announced under — the disposition table over the set (a seat
 * with no row does not compile: {@link SwapNoticeTableCoversEverySeat}). `models` and `tiers` share the
 * catalog-generation line (one swap, one line, both counts); each containment face has its own.
 */
export declare const SWAP_SEAT_NOTICE: {
    readonly models: "config.models_swapped";
    readonly tiers: "config.models_swapped";
    readonly readFace: "config.read_face_swapped";
    readonly writeFace: "config.write_face_swapped";
    readonly contextSettings: "config.context_settings_swapped";
    readonly readDenyPatterns: "config.read_deny_swapped";
    readonly readDenyBuiltinTiers: "config.read_deny_swapped";
    readonly readDenyBuiltinExclude: "config.read_deny_swapped";
};
/** The fence over the notice table: `never` while every seat has a row. */
export type SwapNoticeTableCoversEverySeat = AssertAllKeysHandled<Exclude<SwappableDepSeat, keyof typeof SWAP_SEAT_NOTICE>>;
/** What the screen hands back: the seats present (set order) and the ONE read of each present seat's value,
 *  copied at screen time — the door writes from THIS object and never re-reads the caller's. */
export interface ScreenedSwappableDeps {
    readonly seats: readonly SwappableDepSeat[];
    /** A fresh plain object: the screened value of every present seat (`models`/`tiers` shallow-copied,
     *  `readFace`/`writeFace` the screened word; an explicit `undefined` is kept as a PRESENT own key so the door can
     *  tell "clear this seat" from "not named"). */
    readonly candidate: SwappableDeps;
}
/**
 * Screen a swap candidate BEFORE anything is written: the object shape, the key set (every own key must
 * be a member of {@link SWAPPABLE_DEP_SEATS}; at least one), the `tiers`-rides-with-`models` rule, and
 * each present seat's own value gate. Returns the seats present (set order) and a SNAPSHOT of their values
 * — the one read. Throws on the first defect; the caller has written nothing yet, so the current deps stay
 * in force byte-identical.
 *
 * ONE READ, BY CONSTRUCTION: every seat value is read off the caller's object exactly once, here, and the
 * screened copy is what the door writes and announces. A getter-backed or concurrently-mutated candidate
 * therefore cannot present a legal value to the screen and a different one to the write (or to the
 * announcement, which runs AFTER the write — a throw there would have left a half-announced swap in
 * force). The prepare doors read their deps seats the same way.
 *
 * The per-seat gate is the SAME one the seat's prepare-time reader applies (both face seats ⇒
 * `assertContainmentFaceValue`), so a value the door admits is a value every later prepare admits.
 */
export declare function screenSwappableDeps(next: unknown): ScreenedSwappableDeps;
/**
 * Announce a swap of the deployment's read-deny declaration, after the write: ONE `config.read_deny_swapped`
 * line however many of its three seats the swap named (the line's contract lives at the notice catalog,
 * `EngineNotice.code`).
 */
export declare function announceReadDenySwap(onNotice: RunnerDeps["onNotice"], seats: readonly SwappableDepSeat[], inForce: Pick<RunnerDeps, ReadDenyDeploymentSeat>): void;
