/**
 * The messages-slot refusals — said in the same words wherever they are said.
 *
 * ── The arc this module records ──────────────────────────────────────
 * 7.19.1 refused `slot: 'messages'` BY NAME. An Injection targeting the
 * messages slot was RECORDED as injected — `context.injected` fired with
 * its content, the slot composition counted it, the engine routed it —
 * while the request assembled its message list from the conversation
 * itself, so the model never saw it. The recording said one thing and the
 * wire said another, and absence beat that lie.
 *
 * 7.21.0 delivers it, so the refusal moves: from "this placement never
 * reaches the model" to "this placement reaches the model, but not with
 * THAT role on THIS provider, and not at THAT position this iteration."
 * The two facts the old sentence bundled together are now separate, and
 * each is decided against something real:
 *
 *   • ROLE — the wire has no system role inside the message list on the
 *     Anthropic family (system is a separate top-level field) while the
 *     OpenAI family carries it. A provider declares what it carries
 *     (`LLMProvider.carriesInMessages`); a role it does not carry is
 *     REFUSED at run start, naming the provider and the roles it does
 *     carry. Never silently re-roled: changing who appears to speak is a
 *     meaning change the app must make, not the library.
 *
 *   • POSITION — a delivered injection goes at the END of the history the
 *     iteration assembled. If its role would collide with the turn already
 *     there, or the tail is waiting on a tool result, delivery is DEFERRED
 *     to the next boundary and the deferral is recorded on
 *     `messagesDelivery.deferred`. Never a silent drop, never a reorder,
 *     never a split `tool_use` / `tool_result` pair.
 *
 * Both refusals are stated in full sentences that name the fix, because a
 * refusal that does not teach just moves the puzzle.
 */
import type { WireRole } from '../provider-contract/types.js';
/**
 * The role refusal (D2), addressed from `site` (e.g.
 * `defineFact('turn-time')` or the run-start check).
 *
 * Thrown when a `slot: 'messages'` injection declares a role the attached
 * provider drops on the wire. The alternative — quietly rewriting the role
 * to one that fits — would make the recording true and the meaning false.
 */
export declare function messagesRoleRefusal(args: {
    readonly site: string;
    readonly role: string;
    readonly providerName: string;
    readonly carries: readonly WireRole[];
}): string;
/**
 * The role refusal for a role no wire can carry (`'tool'`).
 *
 * A tool message answers one specific `tool_use` id. An injection has no
 * call to answer, so the message it would produce is malformed on every
 * provider — this one is refused by shape, not by capability.
 */
export declare function messagesToolRoleRefusal(site: string): string;
/**
 * The content refusal (8.18.0) — a declared message whose `content` is not text.
 *
 * The named factories (`defineFact`, `defineInstruction`, …) have always
 * refused empty content; a hand-built `Injection` passed straight to
 * `.injection()` went through unchecked, and the delivery stage put it on the
 * wire as-is. A message with no content is not a quieter message: it becomes
 * `content: undefined` in the window, crashes the next composition, and — when
 * two of them are declared — collides on the delivery ledger's key so one is
 * silently swallowed. Refused where the declaration is, naming the injection.
 */
export declare function messagesContentRefusal(args: {
    readonly site: string;
    readonly role: string;
    readonly received: string;
}): string;
/** Why a delivery was held back this iteration. Recorded, never thrown. */
export type DeferralReason = 'role-collision' | 'unanswered-tool-call';
/**
 * The deferral note (D3) — a sentence on `messagesDelivery.deferred`, which
 * is the committed answer to "why is my declaration not on the wire yet?".
 *
 * Not an error: the next boundary retries it unchanged. The note names what
 * blocked it so the reader does not have to reconstruct the window to find out.
 */
export declare function messagesDeferralNote(args: {
    readonly injectionId: string;
    readonly role: string;
    readonly reason: DeferralReason;
    /** The effective wire role of the turn currently at the end of the window. */
    readonly tailRole?: string;
}): string;
