/**
 * key↔URL route pairing adjudication — the SINGLE source of the pairing law.
 *
 * The invariant: **the credential a request carries must belong to the URL the request targets.**
 * A request's URL half is per-ENTRY (`Model.baseUrl`, a required field) while the credential
 * fallback is per-BRAIN-INSTANCE (`options.apiKey ?? config.apiKey`): unadjudicated, a deployment
 * credential follows EVERY entry's URL through one brain — third-party hosts included. This module
 * is what the three first-party
 * brains now consult before shaping a request, what the brain decorators re-walk per hop (each
 * hop/route re-resolves the three credential states for ITS model against ITS config), and what
 * external consumers (a server annotating a model roster, a conformance suite) import so there is
 * exactly one implementation of the law.
 *
 * The judgment, by credential source (see {@link RouteCredentialSource}). ONE law for both credential
 * sources — **a credential has exactly one root** — differing only in where that root comes from:
 *  - `per-model` → a per-model credential (auth hook or a credential header on `Model.headers`) is bound to the
 *    ORIGIN (scheme + host + port) of the first request the engine SENT carrying it, in the engine's one
 *    credential-origin table ({@link credentialOriginTable}) — written only by a brain's request gate when the request
 *    goes out ({@link admitRouteRequest}), read by every judgment; a request carrying it to another origin is
 *    refused (`route.credential_origin_mismatch`), a request to another path of the same origin is not. An
 *    entry whose `baseUrl` moves to another host while its credential stays the same therefore sends
 *    nothing: the credential belongs to the host it was first sent to, and a NEW credential (the entry's
 *    credential reference changed with its address) is a new binding. The binding lasts for the process. Before any
 *    origin is read, a per-model credential is ONE value per header: a request whose per-call `apiKey` is set beside a
 *    header of the very name its lane writes that key in carries two values for one header, and is refused
 *    (`route.credential_answer_conflict`) wherever it is going.
 *  - `deployment-config` → a deployment credential has exactly ONE root: the one its brain sends to when
 *    an entry names none — `config.baseUrl`, else the lane's own default endpoint
 *    (`RoutePairingConfig.laneDefault`). A request to that root is `"paired"`; a request to any other
 *    root — an entry carrying its own `baseUrl` — is the torn pair this module exists to stop
 *    (`route.credential_mismatch`), whether or not the deployment wrote its root down. A key on the
 *    config with the URL only on the model is that torn pair: nothing says the key belongs there.
 *  - `absent` → OK for keyless deployments (nothing to protect); refused as
 *    `route.credential_missing` only where an entry declares its OWN URL away from a DECLARED
 *    deployment root — a distinct endpoint with no credential route is a configuration hole, and a
 *    loud refusal with a fix hint beats an unauthenticated request to a third-party host.
 *
 * Fail-closed direction: "no credential leak" outranks "silently works", and every refusal names the
 * entry, both URL halves, and a one-line fix.
 *
 * Bad-value loudness (garbage / contradiction / absence / misplacement):
 *  - garbage — non-string URL/credential inputs throw a `TypeError` here (a programmer error must
 *    not be laundered into a polite verdict); whitespace-only URLs normalize to "" (undeclared).
 *  - contradiction — the torn pair refuses with `route.credential_mismatch` + both halves named; a bound
 *    per-model credential sent elsewhere refuses with `route.credential_origin_mismatch` + both origins named; a
 *    per-call key beside its own header refuses with `route.credential_answer_conflict` + both header names named.
 *    Each is a VERDICT, one shape for every caller of the law ({@link adjudicateModelRoute}, which throws on garbage
 *    alone): the request gate, a pre-flight, the read face and a failover chain read the same refusal.
 *  - absence — `route.credential_missing` with the fix hint, exactly where absence is a hole.
 *  - misplacement — a credential in the URL, or a non-http(s) root: {@link assertServableRequestRoot}.
 */
import type { Model } from "../internal/llm.js";
import type { RouteAdjudication, RouteCredential, RoutePairingConfig, RoutePairingPosture } from "../internal/llm.js";
import type { Brain, EngineNotice } from "../core/types.js";
import { BrainError } from "./errors.js";
import type { RequestRootOrigin } from "./request-route.js";
/** A base URL's ROUTE KEY — the value the pairing law COMPARES, folded to WIRE equivalence: the
 *  halves the wire itself treats as case-insensitive (scheme and host, RFC 9110) fold, the scheme's
 *  default port elides, and PATH and QUERY ride byte-preserved apart from the trailing slashes the
 *  request composition itself folds (a query selects the endpoint as surely as a path does; folding
 *  anything the wire keeps would compare two different endpoints equal — the widening this module
 *  exists to stop). An unparseable value keeps its raw trimmed spelling: fail-closed raw
 *  comparison. Non-string input throws — see the module note on garbage.
 *
 *  **Never render this.** Byte-preserving on the query means `?api_key=<secret>` rides it verbatim;
 *  {@link displayUrlOf} is the one spelling allowed into text. */
export declare function routeKeyOf(url: string | undefined): string;
/** A base URL's DISPLAY spelling — the only rendering of a request root allowed into text a human,
 *  a log or a consumer sees. Composed from the PARSE (never edited out of raw bytes): userinfo
 *  drops, EVERY query value becomes {@link REDACTED_VALUE}, and a query NAME rides only where it
 *  really is a name.
 *   - no secret-name list: a list has a blind spot at the name nobody listed.
 *   - names ride because dropping the query WHOLE renders two roots differing only in query as one
 *     string — exactly the pairs the law refuses, so its refusal would read "targets X … paired
 *     with X". {@link queryDifferenceNote} closes the case where the names match too.
 *   - a BARE token (`?<token>`) renders as one placeholder with NO name: `URLSearchParams` calls it a
 *     name with an empty value, and that reading put the payload itself on screen. "Every value is
 *     withheld" protects only what IS a value, so the raw segment decides what rides.
 *   - a name rides only where {@link readQuery} finds the query PURE. A query holding any structured
 *     value — a URL, an e-mail address, anything that is not plain text once decoded — owns the `&`
 *     and `=` the split relies on, so the bytes left of an `=` are not names and are never spoken:
 *     such a query renders as ONE placeholder. A deployment's ordinary names (`tenant`, `api-version`,
 *     `x-request-id`, `filter[name]`, `x.y`) are unaffected, which is what keeps a refusal actionable.
 *  Answers `""` for an undeclared root, like its key twin. */
export declare function displayUrlOf(url: string | undefined): string;
/**
 * The bad-value refusal every base-URL seat owes: **a request root must be an absolute http(s) URL, it
 * may not carry the credential itself, and it may not carry a fragment.**
 *
 * The first two fail the same way if they are not caught here — as a TRANSPORT failure, indistinguishable
 * from an outage, retried for the whole backoff ladder. Measured: `file:`/`ftp:` reject with
 * `TypeError("fetch failed")` over a causeless "unknown scheme", the exact shell a refused connection uses.
 * Stripping userinfo instead of refusing would send an UNAUTHENTICATED request to the host the operator
 * thought they had authenticated to. A FRAGMENT fails worse than loudly: `fetch` never sends one, so a root
 * carrying it silently targets the root's own path and every endpoint suffix appended after it lands inside
 * the discarded part (`https://h/v1#note` + `/chat/completions` → a request to `/v1`). Refused where the
 * value ARRIVES — construction for `config.baseUrl`, request build for `Model.baseUrl` — and again where a
 * request URL is composed ({@link joinRequestUrl}), so a root that reached a builder by some other path
 * cannot compose a wrong URL in silence. An undeclared root is not this rule's question; the PAIRING law
 * keeps its tolerance for an unparseable spelling ({@link routeKeyOf}). Answers the value it judged.
 */
export declare function assertServableRequestRoot(url: string | undefined, seat: string): string | undefined;
/**
 * The request URL itself: a request ROOT joined with the endpoint SUFFIX its lane speaks. The one
 * composition — `${root}${suffix}` put the suffix wherever the root's last character happened to leave it,
 * which for a root carrying a query (`https://h/v1?api-version=2024-06-01`, the gateway shape a deployment
 * really declares) appended it INSIDE the last query VALUE and sent the request to `/v1`.
 *
 * The rule, stated once for all four builders: the suffix joins the **path** (exactly one separator,
 * whatever trailing slashes the root carries); the **query** rides byte-preserved AFTER it, because a query
 * selects the endpoint as surely as a path does and a deployment declares it once for every request; a
 * **fragment** never reaches here ({@link assertServableRequestRoot} refuses the root, re-asked here so a
 * root that arrived by some other path is refused rather than composed).
 *
 * Composed from the same parse `fetch` itself would make, so the spelling carries no normalization the wire
 * would not have done anyway. A suffix carrying its own `?`/`#` is a programmer error, not an input: the
 * query belongs to the root, and the suffix names a path.
 */
export declare function joinRequestUrl(root: string | undefined, suffix: string): string;
/** Remove the userinfo from every authority in free text, WHOLE — the general redactor keeps a short or
 *  unprefixed username, and `TOKEN@host` / `TOKEN:x-oauth-basic@host` are the canonical PAT spellings. */
export declare function stripUrlCredentials(text: string): string;
/** The request ROOT a brain targets — `Model.baseUrl` else `config.baseUrl` else the lane's default,
 *  in its canonical spelling ({@link canonicalRootSpelling}: trailing PATH slashes folded, query
 *  byte-preserved) — with {@link assertServableRequestRoot} applied to both declared halves on the way.
 *  The three brains each carried a copy of this coalesce-and-strip line, so a rule about base URLs had
 *  three homes; now it has one. Answers `""` when nothing is declared and the lane has no default —
 *  whether that is a refusal is the caller's. */
export declare function resolveRequestRoot(modelBaseUrl: string | undefined, configBaseUrl: string | undefined, laneDefault?: string): string;
/** {@link resolveRequestRoot} with the knob that named the root beside it (`RequestRootOrigin`) — the one
 *  resolution; the root a request build sends to and the root its route states cannot come from two readings. */
export declare function resolveRequestRootOf(modelBaseUrl: string | undefined, configBaseUrl: string | undefined, laneDefault?: string): {
    root: string;
    origin: RequestRootOrigin;
};
/** Whether a header bag carries a credential header (any case) — the engine's one reading of which header carries a
 *  credential ({@link isCredentialHeaderName}: `Authorization`, `X-Api-Key`, Azure's `api-key`, `x-goog-api-key`,
 *  `Cookie`, …), the same reading the withheld-value intake keeps. */
export declare function hasAuthCarrier(headers: Record<string, string> | undefined): boolean;
/** Test seam: empties the process's credential-origin table — every per-model credential is unbound again, as at a
 *  process start. Never called by production code (a binding lasts as long as the process; restarting rebinds). A test
 *  suite that sends one fixture credential to two local mock upstreams (two `listen(0)` ports are two origins) calls it
 *  between cases, or gives each case its own fixture credential. */
export declare function __resetCredentialOriginBindings(): void;
/**
 * Resolve WHICH credential a request would carry, tagged with its source — the input half of the
 * adjudication. One rank per SOURCE, most-specific wins; within a rank the apiKey knob and the rank's
 * credential headers are ONE credential (they ride together and are bound together):
 *   1. the per-model auth hook's answer — `options.apiKey` (presence, not truthiness: an empty string
 *      is a present credential that fails closed at emit — no key header, no fallback to the
 *      deployment's) and/or a credential header ({@link hasAuthCarrier}) in `options.headers` (a
 *      gateway's own `Helicone-Auth` beside the key, or the key spelled as a header — not both: an `apiKey`
 *      beside a header of the very name the lane writes the key in (`keyHeader`) is resolved all the same, with
 *      that conflict recorded beside it for the law to refuse). The bag MUST be
 *      per-model sourced (the hook's headers) — that provenance is what makes it a credential of THIS
 *      entry, bound to its own origin below. A caller that folds run-wide headers into the per-call
 *      options must strip credential headers first (the harness merge does), or a deployment
 *      credential would ride here and be judged per-model,
 *   2. a credential header in `model.headers` (the ENTRY's own declared credential),
 *   3. the deployment config (`config.apiKey` and/or a credential header in `config.headers` — the
 *      documented gateway dual-auth shape, both riding as they always have; the pairing gate judges
 *      the pair as one deployment credential),
 *   4. absent.
 * 1–2 are `per-model`; 3 is `deployment-config`. A per-model credential that carries a secret leaves
 * here with its identity beside it (a digest, held by this module and never a member of the returned
 * object), which {@link adjudicateModelRoute} reads against the origin table and {@link admitRouteRequest}
 * binds when its request is sent. Resolution does not judge the route: what it found — an identity, a key beside
 * its own header — is the law's to rule on, in one verdict shape for every caller.
 */
export declare function resolveRouteCredential(input: {
    optionsApiKey?: string;
    optionsHeaders?: Record<string, string>;
    modelHeaders?: Record<string, string>;
    configApiKey?: string;
    configHeaders?: Record<string, string>;
    /** The header the caller's lane writes a per-call `apiKey` in (`authorization`, `x-api-key`), when it has one. Per-call
     *  options that carry an `apiKey` and a header of that name (any case) are two values for one header: the credential
     *  is resolved with that conflict beside it, and the law refuses it (`route.credential_answer_conflict`) rather than
     *  let the key win. Optional like every input here: a caller that does not know its lane leaves it out, and then no
     *  conflict is recorded and none is refused. */
    keyHeader?: string;
}): RouteCredential;
/**
 * The pairing law (module note above). A READ: it judges against the engine's credential-origin table and writes
 * nothing, so a pre-flight, the read face ({@link routePairingStatus}) and any consumer may call it freely — same
 * inputs and same table, same verdict. A per-model credential {@link resolveRouteCredential} resolved with a key beside
 * its own header is refused first (`route.credential_answer_conflict`, both header names in the fix — wherever the
 * request goes, since the request itself is contradictory); otherwise it is judged against the origin it is bound to
 * (refused when that is another one); one not bound yet, or built by hand (no resolution facts — the published corpus
 * is such input), is servable. Every refusal is a verdict: the law throws on garbage alone. The table is written by one
 * seat only: a first-party brain's request gate ({@link admitRouteRequest}), when the engine commits the request to be
 * sent. The verdict reports nothing either: the request gate's refusal is {@link routeRefusalError}.
 */
export declare function adjudicateModelRoute(model: Pick<Model, "id" | "baseUrl">, credential: RouteCredential, config: RoutePairingConfig): RouteAdjudication;
/** Render a refusal as the one-line detail text the brains put in their thrown error (the machine
 *  code leads so log/transcript consumers can grep it; the fix hint closes it). */
export declare function routeRefusalText(verdict: Extract<RouteAdjudication, {
    ok: false;
}>): string;
/** The request gate's refusal — the ONE error a first-party brain throws when the pairing law refuses the request it is
 *  building ({@link admitRouteRequest}). A credential-origin refusal is also reported to the run it happens in (the run
 *  announces `route.credential_origin_mismatch`): here, at the request that is refused, and not in the law, whose other
 *  callers only advise (a pre-flight, the read face) and leave the outcome to the seat that asked. */
export declare function routeRefusalError(verdict: Extract<RouteAdjudication, {
    ok: false;
}>): BrainError;
/**
 * THE request gate of a first-party brain — the one seat that writes the credential-origin table. Judged while the
 * request is built ({@link adjudicateModelRoute}, the same law the pre-flight and the read face read): a refusal is
 * thrown here ({@link routeRefusalError}) before the body is built, and binds nothing — every refusal the law rules,
 * a key beside its own header included, leaves as that one error (`<code>: <fix>`); the gate rules nothing of its
 * own. An admitted request hands back its
 * ADMISSION, which the brain runs from `SSERequest.onCommitted` — the engine's one point at which THIS request is the one
 * that is sent: the law judged again and, admitted, the per-model credential bound to the request's origin, in ONE
 * synchronous step; refused (the credential went out to another origin since the build — caller code runs while a body
 * is built), the same refusal is thrown there, before anything is sent. A request built speculatively and declined (the
 * context-overflow recovery's candidate), or one whose build fails after the gate, never reaches its admission and binds
 * nothing. A credential is bound to the origin it was first SENT to, never to one it was only judged for. The request's
 * halves (the entry's id and root, the brain's root and lane default) are read ONCE, here: both judgments and the binding
 * are of the request this build is sending, whatever the caller's objects say by the time it is committed.
 *
 * Exported from the package root for a HOST that sends a request itself (its own `fetch`, outside a first-party brain): it
 * passes this same gate, so the binding does not depend on who sends first. Resolve the credential with
 * {@link resolveRouteCredential} (a credential built by hand carries no identity: it is judged and binds nothing), call this
 * before building, and run the admission it returns immediately before the request goes out; a refusal is the very error a
 * first-party brain throws for the same request. {@link adjudicateModelRoute} stays the read: it judges and binds nothing.
 */
export declare function admitRouteRequest(model: Pick<Model, "id" | "baseUrl">, credential: RouteCredential, config: RoutePairingConfig): () => void;
/**
 * Enforce "the resolved credential is the request's ONLY credential" on an already-merged header
 * bag — one source's credential rides, the other sources' credential headers do not:
 *  - PER-MODEL winner → every credential header ({@link isCredentialHeaderName}) is stripped and the
 *    winning bag's own credential headers written back — exactly the ones {@link resolveRouteCredential}
 *    read and hashed ({@link ResolvedCredentialFacts}; the caller's bag is not read again): the hook's
 *    answer (`options`) or the entry (`model`). The hook's answer is one credential — beside its apiKey,
 *    which the brain then writes in its lane's key header (a request that also holds a header of that name
 *    never gets here in a first-party brain: its request gate refused it first, `route.credential_answer_conflict`,
 *    so the lock supersedes nothing the answer carried), its other credential headers ride (a gateway's `Helicone-Auth`); an
 *    entry's credential survives a same- or variant-case deployment spelling that the plain merge order
 *    would have let win. A credential header from any OTHER bag (the entry's under a hook answer, the
 *    deployment's under either) never rides beside a per-model credential. Whether a header is stripped
 *    is decided by its SOURCE, not its name.
 *  - DEPLOYMENT-CONFIG winner → untouched. A header-only config keeps its own spelling, and a config
 *    carrying BOTH the apiKey knob and an auth header is the documented gateway dual-auth shape — the
 *    knob's lock write plus the surviving header, both on the wire.
 *  - absent → untouched (no carriers exist).
 */
export declare function applyRouteCredentialHeaders(merged: Record<string, string>, credential: RouteCredential): void;
/** A brain's construction config, received ONCE by the engine's receipt law for caller objects
 *  ({@link receiveOwnProperties}: a plain object, every own member read once): the request gate and the pre-flight
 *  judge both read this frozen copy, so a config object mutated after construction moves neither and the two cannot
 *  disagree about the root a credential is paired with. The header bag is a caller object too: it is received by the
 *  same law from that one reading into a frozen bag of the copy's own. The copy's credential — `apiKey` and the
 *  credential headers — is a credential the engine now holds: no child spawned on this host inherits a variable whose
 *  value equals it (`holdOwnCredentialValues`). */
export declare function brainConfigSnapshot<T extends {
    apiKey?: string;
    headers?: Record<string, string>;
}>(given: T, subject: string): Readonly<T>;
/**
 * The first-party brains' `adjudicateRoute` face, closed over the brain's construction config —
 * EXACTLY the resolution + judgment the brain's own request build runs (single source, two call
 * sites), so a pre-flight verdict and the request-time verdict agree on the same inputs. A refusal is
 * always a verdict here, never a throw. The pre-flight sees the
 * per-model auth it is handed, nothing later: a header a provider-request hook adds afterwards reaches
 * the request build alone, which judges it by the same law.
 */
export declare function createBrainRouteJudge(config: {
    apiKey?: string;
    baseUrl?: string;
    headers?: Record<string, string>;
    /** The lane's own default endpoint (the brain's constant), when it has one. */
    laneDefault?: string;
    /** The header the lane writes a per-call apiKey in ({@link resolveRouteCredential}'s `keyHeader`): the brain's own
     *  constant, so the judge refuses the requests its request build refuses. */
    keyHeader?: string;
}): (model: Model, perModelAuth?: {
    apiKey?: string;
    headers?: Record<string, string>;
}) => RouteAdjudication;
/**
 * Per-entry pairing status — the read-face predicate a roster/diagnostic surface annotates entries
 * with, so a torn pair is visible at configuration time instead of on the first real request.
 * `judge` is a brain's optional `adjudicateRoute` face; absent ⇒ `"unknown"` (a custom brain core
 * cannot see into — never guessed at).
 */
export type RoutePairingStatus = `ok:${RoutePairingPosture}` | `broken:${"credential_mismatch" | "credential_missing" | "credential_origin_mismatch" | "credential_answer_conflict"}` | "unknown";
export declare function routePairingStatus(brain: {
    adjudicateRoute?: (model: Model, perModelAuth?: {
        apiKey?: string;
        headers?: Record<string, string>;
    }) => RouteAdjudication | undefined;
}, model: Model, perModelAuth?: {
    apiKey?: string;
    headers?: Record<string, string>;
}): RoutePairingStatus;
/**
 * Pre-flight a DERIVED-leg model (one the engine resolved from a role/tier/system default rather
 * than an explicit caller `model`) against the deployment brain's pairing judge. The two-leg
 * disposition for a broken pairing:
 *  - a NAMED model (explicit in the spec) refuses loudly at the brain's request gate — the caller
 *    asked for that exact route and gets the refusal + fix hint;
 *  - a DERIVED model must not sink the main-model task it serves — the seat falls back to the
 *    primary model and announces `route.fallback_to_primary` (the notice IS the loudness; a silent
 *    swap would hide the misconfiguration this whole surface exists to expose).
 * Returns the verdict, or `undefined` when no judgment is possible (the brain has no judge face,
 * the judge itself threw, or the auth hook threw or outran the advisory bound — in which case the
 * seat proceeds unchanged and the failure/latency surfaces at its own request-time call site
 * exactly as before).
 *
 * The hook call is BOUNDED. The pre-flight is advisory (the request gate re-runs the same law), so
 * it must never widen a slow secret manager's blast radius from "the derived call is slow" to "task
 * preparation is wedged": past the bound the pre-flight simply abstains. The eventual request still
 * resolves the hook itself (the pre-flight result is never reused as a credential — same-inputs
 * determinism of the law is what keeps the two calls' verdicts aligned, not a cached secret).
 */
export declare const DERIVED_ROUTE_PREFLIGHT_HOOK_BOUND_MS = 5000;
export declare function adjudicateDerivedRoute(args: {
    brain: Brain;
    model: Model;
    getApiKeyAndHeaders?: ((model: Model) => Promise<{
        apiKey?: string;
        headers?: Record<string, string>;
    } | undefined> | {
        apiKey?: string;
        headers?: Record<string, string>;
    } | undefined) | undefined;
}): Promise<RouteAdjudication | undefined>;
/**
 * Whether two resolved models denote the SAME route for pre-flight purposes: identical wire id AND
 * identical entry ROUTE KEY. `Model.id` alone is NOT route identity — two catalog entries can
 * legitimately share a wire id (the same model served from two endpoints), and a same-id guard
 * would silently skip the pre-flight for exactly the split the pairing law exists to judge.
 */
export declare function sameRouteIdentity(a: Pick<Model, "id" | "baseUrl">, b: Pick<Model, "id" | "baseUrl">): boolean;
/** The `route.fallback_to_primary` announcement — one shared shape for every derived-leg seat, so
 *  a consumer can rely on `detail.{seat, from, to, cause}` regardless of which seat fell back.
 *
 *  `sessionId` (#433, additive): the swap happened while resolving ONE run's seats, so the run is
 *  what an operator correlates the line against ("which task ran on the fallback model"). The
 *  AUDIENCE stays `"operator"` — the fix is a credential/catalog fix, and no end user can act on it;
 *  attribution is a routing key, not an entitlement. Omitted when a caller has no session in hand,
 *  never fabricated.
 *
 *  `runId` (#499, additive): the SESSION is not the unit this line is about — the fallback happened
 *  while resolving ONE INVOCATION's seats, and two runs of one session each falling back on the same
 *  seat used to mint byte-identical notices ("did the same task fall back twice, or two tasks once
 *  each?" was unanswerable). Same posture as `sessionId`: a correlation key, omitted when the caller
 *  has none, never fabricated. */
export declare function fallbackToPrimaryNotice(args: {
    seat: string;
    from: string;
    to: string;
    verdict: Extract<RouteAdjudication, {
        ok: false;
    }>;
    sessionId?: string;
    runId?: string;
}): EngineNotice;
/**
 * The TWIN of {@link fallbackToPrimaryNotice}, for a seat whose deployment declared NO fallback
 * (`RunnerDeps.autoMode.classifierFallback: "none"`): the pairing is broken, nothing was swapped, and the
 * seat's own calls are refused at the request gate — which is what that declaration asked for. Same `detail`
 * keys as its twin MINUS `to`, because nothing moved and a `to` naming a model that was not used is the one
 * lie a consumer cannot detect; `action` is the discriminator, so the posture is read rather than inferred
 * from an absence. `primary` is named in the SENTENCE (what was declined) and not in the detail.
 */
export declare function unroutableSeatNotice(args: {
    seat: string;
    from: string;
    primary: string;
    verdict: Extract<RouteAdjudication, {
        ok: false;
    }>;
    sessionId?: string;
    runId?: string;
}): EngineNotice;
