/**
 * PrepareTask's config-doors phase: the synchronous stretch from the
 * tool-face snapshot freeze through model/thinking/compaction-model resolution. The inputs are
 * exactly the fields of {@link PrepareConfigDoorsInput} (the original extraction slice — spec, deps,
 * sessions, the resume/internals seats); the outputs are the fields of
 * {@link PrepareConfigDoorsResult}, each one a value the slice defined and later phases consume —
 * re-verified as the complete "defined inside, consumed outside" closure at extraction time.
 *
 * ⚠️ SYNCHRONOUS FUNCTION, SYNCHRONOUS CALL — a hard constraint, not a style choice. This phase and
 * the safety scan after it run BEFORE prepareTask's first await (`sessions.acquire`), so a caller
 * has no microtask window in which to mutate `spec.tools`/the face arrays between the snapshots,
 * the doors and the scan. An `async` wrapper — even with a zero-await body — would hand the caller
 * exactly that window (the driver's `await` yields one microtask). Pinned by the
 * `prepare-task-phase-pins` microtask-latch tests.
 *
 * Throws pass through unchanged: every `config.*` / `resume_at.*` refusal here is a DELIBERATE
 * at-the-door rejection (a throw before acquisition needs no cleanup), and the
 * interaction-posture door's `deps.onError` disclosure (call order and payload) is part of the
 * contract. The per-task agents rebind returns a REBOUND spec (shallow copy, only `tools`
 * replaced) — the caller's object is never mutated; the safety scan must receive the rebound one.
 */
import { type BrainCallGuardrailRef } from "../../brain/timeout.js";
import type { Model } from "../../internal/llm.js";
import type { ThinkingLevel } from "../../internal/harness.js";
import { type MicroCompactMachine } from "../context-edit.js";
import { type LockedPreflight } from "../locked-config.js";
import { type ResolvedRole } from "../roles.js";
import { type ResolvedSkillListingBudget } from "../skill-listing-budget.js";
import type { SessionStore } from "../session.js";
import type { RunnerDeps, TaskLimits, TaskSpec } from "../types.js";
import { type UsageWindow } from "../usage-window-store.js";
import type { PrepareResume, RunInternals, ToolFaceSnapshot } from "./contracts.js";
export declare function limitConfigError(code: string, message: string): Error & {
    code?: string;
};
/**
 * Validate `TaskSpec.limits` at the door and return it unchanged.
 *
 * Two refusals, both fail-loud (the {@link resolveStallTimeoutMs} posture: a bound nobody can evaluate is
 * not a bound, and folding it to a default would silently run the task under limits nobody chose):
 *  - **unknown key** ⇒ `config.limit_unknown_key`. TypeScript already rejects a stale key, but a wire /
 *    plain-JS caller does not go through TypeScript, and the retired names (`timeoutSec` above all) used
 *    to be honored — accepting them silently is how a caller keeps believing a limit is armed when the
 *    engine has stopped reading it.
 *  - **unevaluable numeric value** (non-number / non-finite / negative) ⇒ `config.limit_invalid`, naming
 *    the key. `0` is legal on every numeric axis: on `maxTurns` it is the documented "unbounded"
 *    sentinel, and on the budget axes it is an exhausted window (absurd but honest).
 */
export declare function resolveTaskLimits(limits: TaskLimits | undefined): TaskLimits | undefined;
/**
 * Validate the MODE-VALUED members of `TaskSpec.attachments` at the same door, and return the
 * config unchanged. Today that is exactly one member, `totalTokensReminderMode`.
 *
 * WHY A DOOR AT ALL (坏值响亮度律): a knob whose bad value silently folds to the default is a knob the
 * deployment believes is armed. `totalTokensReminderMode: "padded_countdown"` (underscore) or
 * `"Countdown"` are the near-misses a hand-written config produces, and both would otherwise read as
 * "absent" and take the default arm — a DIFFERENT readout than the one that was asked for, with nothing
 * anywhere saying so.
 *
 * DELIBERATELY NARROW, twice over:
 *  - no unknown-KEY refusal (the `resolveTaskLimits` half that has no counterpart here): a wire caller
 *    that sends an attachment flag this engine does not know is asking for a lane that stays off, which
 *    is the family's own default posture — not a ceiling silently disarmed. Widening it would also be a
 *    behavior change for every existing caller, which this additive lane does not license.
 *  - the pre-existing `todoReminderMode` is NOT validated here. It has the same shape and the same
 *    weakness, but tightening it would refuse specs that run today; recorded as a follow-up rather than
 *    folded into this lane's change.
 *
 * A NON-OBJECT CONTAINER (`attachments: null` off a wire, above all) is neither refused nor crashed on
 * (verified by reading): every consumer reads this config through `attachmentsCfg?.…`,
 * so a null container already means "no lanes are wired" and the spec RUNS today. An unguarded property
 * read here — the first cut — turned that running spec into an untyped `TypeError` from inside a door
 * that promises a typed `config.attachment_invalid`, and refusing it instead would newly reject a spec
 * that works. There is no container-shape door in this family yet; that is a separate widening, not
 * something this lane gets to invent on the way past.
 *
 * The bypass is narrowed to values that CANNOT supply attachment fields: a
 * plain-JS caller can hand this a FUNCTION carrying `totalTokensReminderMode` as a property, and every
 * downstream `attachmentsCfg?.…` read would happily find it — so skipping a function here would fold a
 * typo'd mode to the default through exactly the hole this door exists to close. Functions are
 * property-bearing containers and are validated like objects; only `null` and primitives pass through.
 */
export declare function resolveAttachmentsConfig(attachments: TaskSpec["attachments"]): TaskSpec["attachments"];
/**
 * R2 双形轴(追加令 2026-07-18): CC 2.1.212's fable-variant prompt gate (b9e —
 * `fable_5_mitigations` capability / claude-mythos-5), ORTHOGONAL to the simple/classic profile.
 * sema is BYOM, so the id may carry provider prefixes ("anthropic/claude-fable-5",
 * "openrouter/anthropic/claude-fable-5"): BOUNDARY-AWARE family match on the last path segment
 * (raw substring classified "vendor/not-claude-fable-5" and "claude-mythos-50"
 * as fable), case-normalized. Recognition set = CC's _Nr (startsWith "claude-fable-") + b9e
 * (mythos-5). R3 system sections fork on the resulting fact.
 */
export declare function isFableFamilyModelId(id: string): boolean;
/**
 * The SINGLE decision point for the two prompt-shape axes.
 * Both were resolved in separate places with different mechanisms — `promptProfile` off a TaskSpec field,
 * `fableMitigations` off a raw model-id prefix test — so "which shape does this task speak" had no one
 * place to read. CC 2.1.220's counterpart is a model-registry `capabilities` array (one table drives
 * `lean_prompt` + `fable_5_mitigations` alike; anchors/2.1.220/CC-218-220-DIFF.md §2).
 *
 * sema stays BYOM: we cannot key off a capability table for arbitrary model ids, so the RESOLUTION RULES
 * are unchanged — profile: spec > inherited internals > "simple"; mitigations: model family. This is a
 * consolidation, not a behavior change (the axes stay ORTHOGONAL: neither rewrites the other).
 */
export declare function resolveModelPromptTraits(model: {
    id: string;
}, spec: {
    promptProfile?: "simple" | "classic";
}, internals?: {
    promptProfile?: "simple" | "classic";
}): {
    promptProfile: "simple" | "classic";
    fableMitigations: boolean;
};
export interface PrepareConfigDoorsInput {
    /** borrowed-readonly — the caller's spec. NEVER mutated here: the per-task agents rebind returns a
     *  SHALLOW COPY on {@link PrepareConfigDoorsResult.spec} (only `tools` replaced). */
    spec: TaskSpec;
    /** borrowed-readonly — deployment seats. Read for: the two containment-face value screens, locked-config preflight,
     *  retention door, interaction-posture door (incl. `deps.onError` disclosure), usage windows,
     *  brain-call guardrail default, model/role maps. */
    deps: RunnerDeps;
    /** borrowed-readonly — the retention door validates THIS store's declaration (it is one of the
     *  effective stores the leg would run over). No acquire happens in this phase. */
    sessions: SessionStore;
    /** borrowed-readonly — presence gates the resumeAt-conflict door and exempts the empty-objective
     *  door (a checkpoint resume passes `objective: ""` by design). */
    resume?: PrepareResume | undefined;
    /** borrowed-readonly — trusted engine channel: prompt-profile inheritance, the spawning run's
     *  interaction posture, the engine question-strip flag. */
    internals?: RunInternals | undefined;
}
export interface PrepareConfigDoorsResult {
    /** owned (by the caller, from here on) — the REBOUND spec: identical to the input object unless
     *  `spec.agents` was set, in which case it is a shallow copy whose `tools` is the
     *  withAgents-rebuilt roster. Every later phase (the safety scan above all — T21) must read THIS,
     *  never the original input. */
    spec: TaskSpec;
    /** owned — the frozen task-start snapshot of the caller's tool-face control arrays; the ONLY thing
     *  later face reads consult (own-task filter, defer classify, delegation ctx). Frozen-immutable ⇒
     *  shared by reference into tool execution ctxs. */
    toolFaceSnapshot: ToolFaceSnapshot;
    /** owned — the profile half of the single decision point (model-independent by contract). */
    promptProfile: "simple" | "classic";
    /** owned — the administrator lock snapshot; the rest of prepare reads guarded slots through it. */
    lockedPreflight: LockedPreflight;
    /** owned — the resolved interaction posture (spec > spawning run > deployment); the
     *  AskUserQuestion mount and the child-ctx injection read this same value. */
    resolvedInteractionPosture: "interactive" | "headless" | undefined;
    /** owned — the validated/resolved microCompact knob ({@link resolveMicroCompactKnob}
     *  for the door + placement reasoning). The per-run state builder consumes exactly these values —
     *  the deps bag is never re-read after this door. */
    microCompactKnob: {
        machine: MicroCompactMachine;
        clearOnRejection: boolean;
    };
    /** owned — the resolved role; its `systemPrompt` seat is still read at prompt-input time. */
    resolvedRole: ResolvedRole;
    /** owned — the resolved main model (`resolvedRole.model`, re-exposed as the name every later
     *  phase reads). */
    model: Model;
    /** owned — caller-explicit > role default > model default; undefined = off. */
    thinking: ThinkingLevel | undefined;
    /** owned — the compaction model: explicit wins, else the `summarize` role, else undefined (main
     *  model fallback inside maybeCompact). NOT derivable from {@link resolvedRole}. */
    compModel: Model | undefined;
    /** owned — the mitigations half of the decision point (model-family fact). */
    fableMitigations: boolean;
    /** owned, frozen — model-gate DISCLOSURE data (the application itself already
     *  happened on {@link spec}: its `tools` is the survivor rebind when anything was removed).
     *  prepareTask emits the notices from this after the doors return (the onNotice station);
     *  the doors stay side-effect-free on the announcement axis. */
    modelGate: {
        /** gate-class → removed wire names (sorted, unique); empty map = nothing removed. */
        removedByClass: ReadonlyMap<string, readonly string[]>;
        /** stamped classes with no merged-table row (inert tags, fail-open — announce material). */
        unknownClasses: readonly string[];
        /** a not-in-force `SEMA_TOOL_MODEL_GATE` value outside the closed set (discard-announce
         *  material; the in-force arm never lands here — it throws at the door). */
        discardedEnvRaw: string | undefined;
    };
    /** owned — the NORMALIZED per-leg delegation-evidence standard: the deps seat read
     *  ONCE, in this synchronous pre-await stretch, screened, and absent folded to the "static-face"
     *  default. The delegation wrap consumes THIS value, never the live deps object — a deps seat
     *  mutated (or getter-backed) after the door must not present an unscreened value to the mark
     *  branch (the read-once posture). */
    memoryDelegationEvidence: "static-face" | "attested-only";
    /** owned — the lowered skills-listing budget seats (`TaskSpec.skillListingBudgetFraction` /
     *  `skillListingMaxDescChars`): the renderer's two numbers, resolved once against the resolved main
     *  model's window. Read at the door so a bad value refuses BEFORE session acquisition, and carried so
     *  the listing phase and the boundary renderer measure against the same resolution. */
    skillListingBudget: ResolvedSkillListingBudget;
    /** owned — the NORMALIZED memory-provenance mode: the deps seat read ONCE in
   *  the synchronous pre-await stretch, screened, absent folded to the `"carry"` default.
     *  The memory phase constructs every engine with THIS value — never a live deps re-read. */
    memoryProvenance: "off" | "carry";
    /** owned — the NORMALIZED memory-capture posture: the deps seat read ONCE,
     *  screened (a bad value refuses, never folds), absent folded to `"open"`. The capture
     *  opt-out adjudicator consumes THIS value on every leg (declaration, resume record re-check,
     *  and the flip verb's frozen closure) — never a live deps re-read. */
    memoryCapturePolicy: "open" | "governed" | "capture-required";
    /** owned — validated deployment governance windows (undefined = ungoverned). */
    usageWindows: readonly UsageWindow[] | undefined;
    /** owned, out-param cell — created EMPTY here; the brain-call wiring later installs into
     *  `.current`. Returned so driver and harness share one cell identity. */
    brainCallGuardrailRef: BrainCallGuardrailRef;
    /** owned — the resolved outer brain-call guardrail (task > deployment > default; undefined per
     *  the resolver's off states). */
    brainCallGuardrailMs: number | undefined;
}
/** The microCompact knob door (坏值响亮度默认律, the sibling knob doors' form:
 *  interactionPosture / toolModelGate / staleToolResultOffload). Placement is load-bearing:
 *  it runs in THIS pre-first-await config-doors phase so a malformed declaration refuses
 *  BEFORE any resource-bearing preparation — session acquisition, execution-env creation, the MCP
 *  dial — whose external effects a late refusal's teardown cannot undo. SINGLE READ per seat, and
 *  the CONTAINER is judged first (reviews r1/r2): an accessor-backed bag answering a legal value at
 *  one read and junk at another must be caught by whichever read this door takes, and a
 *  `microCompact: "cc"` / null / number / array bag makes both property reads answer undefined —
 *  it must refuse exactly like a malformed field, never fold to the defaults. The RESOLVED values
 *  returned here are immutable and are the state builder's ONLY source — nothing re-reads the bag. */
export declare function resolveMicroCompactKnob(bag: RunnerDeps["microCompact"]): {
    machine: MicroCompactMachine;
    clearOnRejection: boolean;
};
export declare function prepareConfigDoors(input: PrepareConfigDoorsInput): PrepareConfigDoorsResult;
