/** A containment-face state. `"roots"` = the containment judgment runs. `"open"` = the containment
 *  step is skipped (canonicalization, the deny/sensitive sets, the UNC out-of-set refusal and the
 *  type gates all still run). One type for both seats: the two faces differ in WHICH band consults
 *  them, never in what the word means. */
export type ContainmentFace = "open" | "roots";
/** Which band a face governs. Selects the seat spellings and the error codes below — never the
 *  resolution ORDER, which is one body shared by both. */
export type ContainmentFaceKind = "read" | "write";
/** Which layer a seat belongs to. The SPELLING is derived from (kind, layer), never re-typed at a
 *  call site: three doors screen the same two seats, and the value gate's message is the only place
 *  a deployment reads the seat's name back. */
export type ContainmentFaceLayer = "spec" | "deps";
/** The seat spelling for a (kind, layer) pair — single-sourced from {@link FACE_DIALECT}. */
export declare function containmentFaceSeatName(kind: ContainmentFaceKind, layer: ContainmentFaceLayer): string;
/** Loud value gate: a containment-face seat carries exactly "open" | "roots" — anything else (case
 *  variants, truthy garbage) refuses at wiring time, never folds to a default. Exported
 *  module-internally (not on the package surface) so prepare's unconditional config-guard leg can
 *  screen the seats on runs that never mount hands. The resolver itself also runs on every hands-less
 *  leg; this screen still fires first, so a garbage value refuses before any leg-shape branching. */
export declare function assertContainmentFaceValue(v: unknown, kind: ContainmentFaceKind, layer: ContainmentFaceLayer): ContainmentFace | undefined;
/** Inputs to {@link resolveContainmentFace} — structural/declaration facts; a permission mode enters only as
 *  the face its table row states ({@link modeFace}), never as a mode word. */
export interface ContainmentFaceInputs {
    /** Which face is being resolved. Selects the seat spellings and the mint codes; the ORDER below is
     *  one body, identical for both. */
    kind: ContainmentFaceKind;
    /** TaskSpec.readFace / TaskSpec.writeFace (raw — validated here). The TASK layer: may only tighten
     *  under governance. */
    specFace?: unknown;
    /** RunnerDeps / HandsToolkitOptions seat of the same face (raw) — the DEPLOYMENT's own declaration. */
    depsFace?: unknown;
    /** The verifier read-only mount (`handsReadOnly` / toolkit `readOnly`): for the read face its
     *  containment is a LOAD-BEARING wall (bash_readonly is genuinely confined by it); for the write
     *  face it is the absence of the band entirely. Neither is openable. */
    readOnlyMount: boolean;
    /** Org governance declared (`RunnerDeps.permissionRuleStore.partitions.org === true`): default roots; the task layer
     *  may not open (tighten-only under governance; the deps layer, being the deployment's own
     *  declaration, still may). */
    orgGoverned: boolean;
    /** Is the FULL shell (`core.bash@1`) structurally reachable on this mount? Computed BEFORE
     *  tool-band assembly from spec-time facts (env kind / handsReadOnly / Bash exclusion — every
     *  exclusion source is spec-time-frozen, so this is always computable). When false, the roots fence
     *  is the ONLY boundary this face has, so no IMPLICIT default may open it; an EXPLICIT "open" on
     *  either seat or the mode's face still wins (row 4 of the order is a default, not a clamp). */
    fullShellReachable: boolean;
    /** The face the leg's permission MODE states (`ModePolicy.writeFace`: `bypassPermissions` ⇒ "open"; absent ⇒
     *  the mode states nothing). Row 3′: read after the explicit seats and before the defaults — a seat's word (the
     *  deployment's ceiling, a task's tighten) outranks it, and neither the read-only mount nor org governance
     *  consults it. */
    modeFace?: ContainmentFace;
    /** Observation hook for the ONE silent branch of the order: row 1's deployment-seat clamp
     *  (readOnly mount + deps "open" + NO task seat). Fired exactly when the deps declaration was the
     *  deciding seat and the mount overrode it — not when a task-level "roots" pinned the same value
     *  anyway (the mount changed nothing there, and announcing it would claim a false cause), and
     *  never on the throw rows (those are already loud). The resolver stays the single owner of the
     *  clamp predicate; stations own delivery/dedup ({@link deploymentFaceClampNotice}). */
    onDeploymentClamp?: () => void;
}
/**
 * The ONE resolution order, first hit wins — ONE body for BOTH faces. prepare-task AND
 * createHandsToolkit both call it, once per face, so a library-direct mount gets identical validation
 * and identical defaults on each seat.
 *
 *  1. read-only (verifier) mount → ROOTS; an explicit "open" on the TASK seat is a genuine
 *     per-call CONTRADICTION and refuses loudly (never silently pick a side). An "open" on the
 *     DEPLOYMENT seat alone is a deployment-wide default, not a per-task assertion — it silently
 *     CLAMPS to roots (stricter-wins), the same seat distinction row 2 draws for org governance.
 *  2. org-governed: the task seat's "open" refuses (task layer only tightens); deps "open" wins;
 *     otherwise ROOTS.
 *  3. explicit seat: spec ?? deps.
 *  3′. the mode's face ({@link ContainmentFaceInputs.modeFace}).
 *  4. bash-less mount: ROOTS (the fence is the only boundary there — "the fence guards nothing bash
 *     reaches anyway" does not hold, so no implicit default may open it).
 *  5. default: ROOTS — the engine never opens implicitly.
 *
 * @contract fs.containment_face.seat_independence — the two containment seats never read each other:
 * each band passes its OWN resolved value into the shared containment step, a seat nobody declared
 * resolves to "roots" on its own, and no gate other than that step is touched by either word. A
 * deployment that wants both bands open declares both.
 */
export declare function resolveContainmentFace(i: ContainmentFaceInputs): ContainmentFace;
/**
 * The ONE text of a face's deployment-clamp announcement (`config.<face>_face_deployment_clamped`).
 * Both stations deliver THIS object through their own `deliverEngineNotice` call (prepare-task with
 * the `RunnerDeps.onNotice` seat, once per notice sink — the sink, not the deps object, because the
 * Runner rebuilds its deps; `createHandsToolkit` with its band-local `HandsToolkitOptions.onNotice`
 * seat — toolkit creation is itself the one-per-mount boot moment, and an absent seat prints the
 * same line via `console.warn`). Built here, import-free, so the message can never fork between
 * the stations OR between the two faces.
 */
export declare function deploymentFaceClampNotice(kind: ContainmentFaceKind): {
    code: string;
    message: string;
    detail: Record<string, unknown>;
};
