/**
 * Untrusted-text containment (design/53 §2.A — "untrusted-data-everywhere").
 *
 * A multi-agent code-orchestration system treats **every worker's output** (report / diff / code / module)
 * as untrusted data: an LLM worker can be prompt-injected or adversarial, and its output flows into other
 * models' prompts (the L3 judge, the leader, the next worker) where it could pose as instructions —
 * e.g. emitting `</system-reminder>` to escape its framing and forge a verdict (threat BUG1, verify.ts).
 *
 * The trusted side of the codebase REJECTS such sequences (runtask.ts: trusted steering / deny reasons must
 * not contain `</system-reminder>`). Worker text can't be rejected — it must be **contained**: this module
 * NEUTRALIZES break-out sequences and wraps the text in a clearly-labeled opaque fence the consuming prompt
 * tells the model to treat as data, not instructions. Structural and reusable across the chain, not a
 * per-call point-fix.
 *
 * This is defense-in-depth, NOT a guarantee: an LLM cannot reliably honor a "this is data" boundary on its
 * own (instructions and data share one channel). The real boundary is decorrelation + reading the objective
 * artifact (the diff / working tree) rather than the worker's self-report (design/53 §3, design/54 §3).
 */
/**
 * One row of {@link ENGINE_ENVELOPES}.
 *
 * WHY A TABLE EXISTS. design/319 spent its whole threat model on a single tag and three independent
 * texts stated the supporting premise as "this harness mints no other tag" — a MODULE-level
 * enumeration (`turn-attachments` really does mint only one) promoted to a HARNESS-level claim. The
 * engine in fact authors several model-facing envelopes, guarded by two different escape families
 * living in two different modules, and the two envelopes added most recently (`skills`, `scope`)
 * reached the model with NO guard at all — not because anyone argued they were safe, but because
 * nothing in the tree listed the set an author was joining. A guard family without a census is a
 * guard family that silently loses members; this table is that census, and the accompanying
 * literal-tag test keeps it honest (a new closing-tag literal in `src/` fails until it is classified
 * here).
 *
 * The same discipline as the `ToolSpec` completeness table: the registry is the declaration, the
 * test is the gate, and a NEW envelope is a two-line edit rather than an invisible omission.
 */
export interface EngineEnvelope {
    /** The tag NAME as the engine spells it, without angle brackets. */
    readonly tag: string;
    /**
     * - `authority` — the engine authors it as model-facing HARNESS speech; seeing the tag is what
     *   makes the model read the content as system information, so a forgery is an authority claim.
     * - `framing` — the engine wraps UNTRUSTED content in it as a labeled data frame; a forgery
     *   escapes the frame (or closes it early) rather than claiming harness authority.
     * - `not-an-envelope` — a tag-shaped literal in `src/` that is not an engine-minted model-facing
     *   envelope at all (a MODEL-output grammar the engine parses, a prompt-assembly placeholder,
     *   rendering metadata, or copy that merely TALKS about an envelope). Listed so the census test
     *   has a home for every literal in the tree and no reader has to re-derive the classification.
     */
    readonly kind: "authority" | "framing" | "not-an-envelope";
    /** Where the engine authors (or, for `not-an-envelope`, spells) it. */
    readonly mint: string;
    /** How untrusted bytes reaching this envelope's own body/attributes are defused at that site. */
    readonly guard: string;
    /**
     * True ⇒ neutralized inside every FENCED/inline untrusted projection ({@link delimitUntrusted},
     * {@link inlineUntrusted}). Those lanes already rewrite bytes by contract, so a forged authority
     * envelope arriving through them is defused rather than merely fenced.
     */
    readonly fenced: boolean;
    /**
     * True ⇒ DISCLOSED (never rewritten) when it appears in VERBATIM external data — the design/319
     * trailer pipeline (reminder-disclosure.ts). Verbatim lanes are byte-frozen by the G3 veto (the
     * Read↔Edit `old_string` quote-back loop), so the only available judgment bit is an appended,
     * engine-minted note. Deliberately NOT set for tags whose spelling is common in ordinary data
     * (`scope` is a Maven POM element; `summary` is HTML) — a trailer that fires on every build file
     * teaches the model to ignore trailers.
     */
    readonly disclosed: boolean;
}
/**
 * The census. Rows are grouped by {@link EngineEnvelope.kind}; within a group, by module.
 *
 * KNOWN CEILING (stated, not hidden): the accompanying test enumerates CLOSING-TAG LITERALS in
 * `src/`, so an envelope whose tag name is INTERPOLATED (`<${tag}>`) is invisible to it. Those are
 * enumerated here by hand — `teammate-message`, the observer digest's four event tags, and the
 * dynamic `<{slug}-activity>` wrapper — and each already carries its own escape at its mint site.
 */
export declare const ENGINE_ENVELOPES: readonly EngineEnvelope[];
/** The registry row for a tag name, or `undefined` when the tag is not in the census. */
export declare function engineEnvelope(tag: string): EngineEnvelope | undefined;
/** Registry-derived: the envelopes that read as HARNESS AUTHORITY on sight. */
export declare const ENGINE_AUTHORITY_ENVELOPE_TAGS: readonly string[];
/**
 * Registry-derived: the tags {@link delimitUntrusted} / {@link inlineUntrusted} neutralize on top of
 * the always-on reminder tag. These lanes carry EXTERNAL/worker bytes into a labeled data frame and
 * already rewrite them by contract, so an authority envelope forged inside them is defused rather
 * than merely fenced — the "forgery can be neutralized, never trusted" direction.
 *
 * Deliberately NOT applied inside {@link sanitizeUntrustedText} itself: that primitive is also used
 * by mint sites over an ALREADY-ASSEMBLED body (the boundary/first-frame reminder wrap runs it over
 * a body that may legitimately contain the engine's own `<skills>` block), so widening the primitive
 * would have the engine defuse its OWN envelopes. Containment belongs to the fence, not the
 * primitive.
 */
export declare const FENCED_LANE_ENVELOPE_TAGS: readonly string[];
/**
 * The same family as {@link FENCED_LANE_ENVELOPE_TAGS}, as a MUTABLE array for every body that will be
 * SHELLED in a marked `<system-reminder>` — the attachment sink, the listing/diagnostics producers,
 * the durable-resume orphan notice, the post-tool-batch hook relay, the git frame.
 *
 * These are not fences. They render deployment/server/model-supplied strings into a body the run loop
 * then wraps in engine authority, so a forged envelope inside one is laundered by the wrapper. The
 * wrapper itself cannot blanket-neutralize the family — it also shells bodies that legitimately ARE
 * envelopes (TWO owners today: `buildSkillsBlock`'s `<skills>` fence and `renderTotalTokensReminder`'s
 * `<total_tokens>` body) — so containment is expressed as OWNERSHIP: this full set for every body that
 * owns nothing, minus its own tag for each one that does (single source: `ATTACHMENT_TAGS_OWNED` in
 * turn-attachments.ts, which the per-source `attachmentEnvelopeTags` derivation reads).
 *
 * Allocated ONCE so the sanitizer's memoized break-out regex is keyed by a stable value.
 */
export declare const SHELLED_BODY_ENVELOPE_TAGS: string[];
/**
 * Registry-derived: the tags the design/319 disclosure pipeline reports when they appear in VERBATIM
 * external data (see {@link scanEnvelopeShaped}). `system-reminder` is absent on purpose — the mark
 * pipeline scans it with a stronger (marked vs bare) verdict of its own.
 */
export declare const DISCLOSED_ENVELOPE_TAGS: readonly string[];
/** The result of one envelope-shaped scan of an external projection. */
export interface EnvelopeShapedScan {
    /** ≥1 disclosed-family envelope tag (open or close) is present. */
    hit: boolean;
    /** The REGISTRY spellings that matched, de-duplicated, in registry order. Registry-owned strings —
     *  never the matched bytes — so a caller may render them into trusted copy safely. */
    tags: string[];
}
/**
 * The envelope-family sibling of {@link scanReminderShaped}: detect text shaped like one of the
 * engine's OTHER authority envelopes inside external data. Read-only — verbatim lanes are byte
 * frozen (design/319 G3 veto: the Read↔Edit `old_string` quote-back loop), so the disclosure
 * pipeline's only move is to append an engine-minted note saying what was seen.
 *
 * Grammar is deliberately the same shape as the reminder scan (attribute / case / tag-internal
 * whitespace tolerant, open OR close tag), and the tag SET comes from the registry rather than a
 * hand-copied list, so adding an envelope to {@link ENGINE_ENVELOPES} with `disclosed: true` is the
 * whole change. Same accepted residual as the reminder scan: a tag the grammar does not recognize
 * (fragmented, Unicode-lookalike) is not a hit — defense in depth, not a guarantee.
 */
export declare function scanEnvelopeShaped(text: string): EnvelopeShapedScan;
/**
 * Defuse a caller-declared occurrence of ONE specific envelope tag (opening AND closing) inside
 * content, CC `zZe` @8339092 verbatim: ``t.replace(new RegExp(`<(?=/?${e}(?:[>\\s/]|$))`, "gi"), "<\\")``.
 *
 * Homed here (beside {@link ENGINE_ENVELOPES}) rather than in the observer module that first needed
 * it: "escape one named envelope tag" is a containment primitive, and the registry's guard column
 * points at it. Re-exported from `agents/observer.ts` for its existing importers.
 *
 * Deviation from CC (hardening): the tag is regex-escaped before entering the RegExp — CC
 * interpolates raw, safe only because its slugs are `[a-zA-Z0-9_-]`; ours are too, but we don't rely
 * on the caller for that invariant.
 *
 * NOTE the two sanctioned escape SHAPES in this tree, and why they are not merged: this one inserts
 * a backslash (`<` → `<\`) because it is a byte-level CC anchor on the observer/teammate lanes;
 * {@link sanitizeUntrustedText} writes the entity `&lt;` in the bracket's place, CC's own spelling
 * for its reminder-tag escapers. Both are idempotent, both break the tag, and both are printable
 * ASCII that no format-character cleaning can remove; a merge would move bytes on one of the two
 * families for no security gain.
 */
export declare function escapeEnvelopeTag(tag: string, text: string): string;
/** design/319 (B ticket) — what one reminder-shaped scan of an external projection found. */
export interface ReminderShapedScan {
    /** ≥1 reminder-shaped tag (open or close; attribute/case/whitespace tolerant) is present. */
    hit: boolean;
    /** Some reminder-shaped TAG's own bytes contain the session's exact mark value — the strongest
     *  verdict (a full scan decides this, never the first match: a bare decoy ahead of a marked
     *  forgery must still be judged marked). `false` whenever `mark` is `undefined`. */
    hadCurrentMark: boolean;
}
/**
 * design/319 (B ticket) — the ONE detection predicate for reminder-shaped text in EXTERNAL data
 * (the Read/notebook/PDF/MCP disclosure trailers and the MCP/web exact-mark defuse all judge with
 * THIS scan). It reads the same {@link SYSTEM_REMINDER} regex the neutralizer rewrites with, so
 * "what gets defused on contained lanes" and "what gets disclosed on verbatim lanes" can never
 * drift apart — do not hand-copy the tag pattern anywhere else (same single-source discipline as
 * {@link defuseFenceMarkers}). Attribute-tolerant / case-insensitive / tag-internal whitespace
 * tolerant by construction; a tag the regex does not recognize is NOT a hit (the residual gap
 * between this grammar and what a model might read as authority is an accepted, documented
 * residual — same class as the Unicode-lookalike note on {@link defuseFenceMarkers}).
 *
 * The scan is read-only over the FINALIZED projection (post concatenation/truncation, pre any
 * trusted tail) — callers must scan BEFORE any byte-changing transform (design/319 §3e four-step
 * order): a defused/neutralized projection no longer carries the exact mark, so scanning after
 * would misreport a marked forgery as the bare form (the lying-disclosure shape).
 */
export declare function scanReminderShaped(text: string, mark: string | undefined): ReminderShapedScan;
/**
 * design/319 §3b (B ticket) — EXACT-MARK defuse for the MCP-success/web outlets: insert a ZWSP
 * inside every occurrence of the session's exact mark value so the bytes no longer spell the
 * current mark. This is the ONE sanctioned byte change on those lanes (their zero-byte-change
 * invariant's single exception): a server/page legitimately producing the 22-char session mark has
 * definitionally zero probability — the value lives only in this session's prompt and checkpoint —
 * so an occurrence is either a forgery or a leak echo, and defusing it turns a silent authority
 * forgery into a visible mismatch (the accepted failure direction; a legitimate round-trip echo of
 * a leaked mark defuses too, and the next hop then fails loudly instead of re-arming the forgery).
 * NEVER applied on Read/Bash/Grep (the strong quote-back lanes stay verbatim — ruled, observation
 * seat only). Idempotent: the rewritten text no longer contains the exact mark (ZWSP is not a
 * base64url character, so the insertion can also never synthesize a new occurrence).
 */
export declare function defuseExactMark(text: string, mark: string): string;
/**
 * design/319 §3b — the SEGMENT form of {@link defuseExactMark} (adversarial round: a server can
 * split the mark across adjacent MCP text blocks; the block seam is invisible in the model-facing
 * concatenation, so a per-segment defuse would be a bypass). Judged over the JOINED projection and
 * the ZWSP insertion mapped back into the owning segment, so the post-defuse concatenation NEVER
 * contains the exact mark — including occurrences that straddle one or more seams (one ZWSP inside
 * the occurrence's span breaks it wherever the split fell). Returns the same array (`changed:
 * false`) when the joined projection has no occurrence; otherwise fresh segment strings whose
 * concatenation equals the single-string form's output byte for byte (it IS the single-string
 * form's implementation).
 *
 * OVERLAP-AWARE (adversarial round 2): a BORDERED mark (first character = last character — ~1/64
 * random mints) admits overlapping occurrences (`mark + mark.slice(1)` carries two, one starting on
 * the other's final character), so enumeration advances ONE character per match, never by the mark
 * length — a skip-by-length walk defused the first and left the second exact while the trailer
 * claimed neutralization. Every enumerated occurrence gets a ZWSP inside its own span; ZWSP is not
 * a base64url character, so insertions can never synthesize a new occurrence and the result is
 * idempotent (no exact mark survives ⇒ a second pass is byte-identical).
 */
export declare function defuseExactMarkInSegments(segments: readonly string[], mark: string): {
    segments: string[];
    changed: boolean;
};
/**
 * Neutralize structural break-out sequences in UNTRUSTED text so it can't escape its framing into
 * model-facing instructions. Always neutralizes `<system-reminder>` / `</system-reminder>` (the codebase's
 * elevated-authority wrapper) by writing the entity {@link ESCAPED_LT} in place of the leading `<` (a form no
 * format-character or whitespace cleaning removes — see there). Pass `extraTags` to also
 * neutralize a CALLER's own data-framing tags — e.g. memory recall frames note text inside its own injection
 * tags, so an untrusted note could emit the closing tag to break out; the caller passes those tag names
 * (`MEMORY_INJECTION_TAGS`). Tag names must be literal (alphanumeric/hyphen) — they are code-supplied
 * wrapper names, never untrusted input. Idempotent for prompt assembly (a defused tag no longer matches).
 *
 * WHY THE ALWAYS-ON SET IS ONE TAG AND NOT THE WHOLE {@link ENGINE_ENVELOPES} AUTHORITY FAMILY: this is a
 * PRIMITIVE, and mint sites also run it over an ALREADY-ASSEMBLED body — the boundary/first-frame reminder
 * wrap sanitizes a body that may legitimately BE the engine's own `<skills>` block, and the memory write
 * scan diffs against it to decide what markup a note may contain. Widening the primitive would have the
 * engine defuse its own envelopes and would silently move an unrelated store's admission rule. Family-wide
 * containment therefore lives at the FENCE ({@link delimitUntrusted} / {@link inlineUntrusted}, via
 * {@link FENCED_LANE_ENVELOPE_TAGS}) and at each envelope's own mint site (the registry's guard column).
 */
export declare function sanitizeUntrustedText(text: string, extraTags?: string[]): string;
/**
 * [c209-C] 收口 C1/C2 (metadata-driven, replaces the shape-anchored
 * `stripLeadingSystemReminders`) — cut the engine-prepended prefix off a user-lane message using the
 * EXACT length recorded on the message at mint time (`UserMessage.enginePrefixChars`, stamped where
 * the engine concatenated first-frame listing reminders / a UserPromptSubmit additionalContext
 * reminder / a resume continuation's trusted head AHEAD of the real user text). The first user turn
 * carries those bytes as engine guidance, not user speech — a consumer that re-presents user
 * messages under a `[user]`/`[User]:` label (the auto-mode classifier window, the compaction
 * summarizer input) must not let them (a) impersonate user authority or (b) evict the real
 * objective from a head-truncated excerpt.
 *
 * The old helper GUESSED by reminder shape, which mis-fired in both directions (收口轮): a
 * same-line engine mint (`<system-reminder>[deadline] …</system-reminder>`) was NOT recognized and
 * entered the window under `[user]` authority, while a user who legitimately opened their own
 * prompt with a byte-exact reminder block WAS stripped. Metadata removes the guess entirely:
 * - a message WITH `enginePrefixChars` is cut at exactly that offset (no regex, no shape matching);
 * - a message WITHOUT metadata is rendered VERBATIM — user-authored `<system-reminder>` prefixes
 *   are never stripped, and OLD sessions (persisted before the field existed) render unchanged.
 *   Conservative direction, deliberate: a classifier/summarizer seeing engine listings as user text
 *   is acceptable; silently losing real user text is not.
 * An out-of-range length (≤0 / > text length — corrupt or foreign data) is ignored the same way.
 * [c209-C] R5: the parameter is `unknown` — the field can arrive as shape-poison from old/foreign
 * imported sessions (a string "9", null) and the typeof/integer checks below are the total guard.
 */
export declare function cutEnginePrefix(text: string, enginePrefixChars: unknown): {
    text: string;
    cut: boolean;
};
/** An engine-trusted segment of a user-lane message: a half-open `[start, end)` UTF-16 code-unit
 *  range — see `UserMessage.engineSegments` (engine/llm/types.ts) for the full field contract. */
export interface EngineSegment {
    start: number;
    end: number;
}
/**
 * [c209-C] R5 — the three-state result of {@link normalizeEngineSegments}. `absent`
 * and `malformed` are DIFFERENT states on purpose (R4 #1): a message whose `engineSegments` field
 * is present-but-malformed must render WHOLLY verbatim — the metadata family is suspect, so a
 * co-present `enginePrefixChars` must NOT get a second chance to cut (absent metadata is the only
 * state where the prefix sugar applies).
 */
export type NormalizedEngineSegments = {
    readonly state: "absent";
} | {
    readonly state: "malformed";
} | {
    readonly state: "valid";
    readonly segments: ReadonlyArray<EngineSegment>;
};
/**
 * [c209-C] R4 终判 (R5: three-state + exception-safe over `unknown`) — validate
 * `UserMessage.engineSegments` against the text it indexes into.
 * - `absent`: the field is `undefined` (or an empty array — it claims no engine bytes), so the
 *   `enginePrefixChars` sugar MAY still apply.
 * - `valid`: EVERY range is well-formed (elements are objects whose `start`/`end` are integers,
 *   `0 ≤ start < end ≤ text.length`, ascending and non-overlapping — `prev.end ≤ next.start`).
 *   Returns FRESH `{start, end}` copies (canonical plain data, e.g. for the import gate).
 * - `malformed`: anything else — including non-array values (`null`, `{}`), non-object elements
 *   (`[null]`), and shape-poison (`[{}]`, string offsets) from old/foreign session data. ONE bad
 *   range invalidates the WHOLE field and consumers render the entire message verbatim, prefix
 *   suppressed (losing real user text is worse than showing engine bytes). NEVER throws: the input
 *   is `unknown` by contract and any exotic shape (throwing getters included) collapses to
 *   `malformed`.
 * Shared single source for the mint clamp (agent-harness `createUserMessage`), the session import
 * gate, and every projection side (auto-mode window / compaction serializer / prompt suggestions).
 */
export declare function normalizeEngineSegments(text: string, segments: unknown): NormalizedEngineSegments;
/**
 * [c209-C] R4 终判 — the SEGMENT sibling of {@link cutEnginePrefix}: remove every
 * engine-trusted `[start, end)` segment from a user-lane message, keeping the bytes OUTSIDE the
 * segments verbatim (the caller/operator-authored content that derived views may present under
 * `[user]`/`[User]:` authority). Unlike the prefix cut, segments can sit mid-message: the resume
 * continuation preserves issue order (parked steer first, wake second — the public
 * ResumeOutcome/ResumeRun contract), so a trusted engine frame may legally follow an untrusted
 * fenced one.
 *
 * [c209-C] R5 — the result distinguishes WHY nothing was cut: `malformed:true`
 * means the field was PRESENT but bad (per {@link normalizeEngineSegments}) — the caller must
 * render the whole message verbatim and MUST NOT fall through to `enginePrefixChars` (segments
 * exist ⇒ they own the message; malformed ⇒ the metadata family is suspect wholesale). Only
 * `cut:false, malformed:false` (absent metadata) allows the prefix-sugar fallback. Never throws.
 */
export declare function cutEngineSegments(text: string, segments: unknown): {
    text: string;
    cut: boolean;
    malformed: boolean;
};
/**
 * [c209-C] R5 — the ONE flatten under which `engineSegments`/`enginePrefixChars`
 * offsets are DEFINED: a user-lane message qualifies only when its content is a plain string or a
 * SINGLE text block (whose text is that same string). Multi-block / image-bearing content returns
 * `undefined` and consumers render the message VERBATIM with their own local flatten — the two
 * projection sides flatten blocks DIFFERENTLY (the auto-mode window joins with `\n` + `[image: …]`
 * block markers; the compaction serializer drops non-text blocks and joins with no separator), so a
 * single `[start, end)` range would point at different characters on each side. The restriction
 * costs nothing real: every engine-assembled prefixed/segmented message (first-frame objective
 * concatenation, resume continuation) is minted from ONE plain string — the sole exception is a
 * first-frame objective that ALSO carries user images, which now falls back to verbatim (the
 * accepted conservative direction: engine listing bytes visible under user authority, never lost
 * user text). Single-source helper shared by both projections, the suggestions transcript, and
 * the session import gate. Accepts `unknown` (import-side data) and never throws.
 */
export declare function flattenableUserText(content: unknown): string | undefined;
/**
 * Defuse this module's triple-angle fence sentinels (`<<<` / `>>>`) inside an untrusted body so the body
 * cannot forge {@link delimitUntrusted}'s own OPEN/CLOSE markers and break out of the fence. A worker (or
 * an external page via `web_fetch`, an MCP resource — the label format is open-source, so the close marker
 * `<<<END UNTRUSTED <label>>>>` is guessable) could otherwise emit the literal close marker followed by
 * top-level injection. Caps any run of 3+ identical brackets at 2 consecutive by writing the entity
 * ({@link ESCAPED_LT} / {@link ESCAPED_GT}) in place of every third bracket — the reader still sees the text,
 * no `<<<`/`>>>` triple survives, and no format-character cleaning can put one back. Idempotent: a capped run
 * (≤2) never re-matches `{3,}`. Defusing EITHER bracket breaks the marker; we defuse both for symmetry.
 *
 * Residual (council QUESTION, accepted): only ASCII `<`/`>` (U+003C/003E) are defused. A Unicode lookalike
 * (fullwidth `＜`/`＞`, U+FF1C/FF1E) is NOT — but a fullwidth marker is a DIFFERENT string from the real
 * ASCII close sentinel, so it cannot break out at the string level; at worst it visually resembles the
 * fence to the model. Consistent with this module's "defense-in-depth, NOT a guarantee" posture.
 *
 * Exported (design/138 S2-C, O-F11/C-F10): the memory write-time scan detects a forged fence by diffing
 * `defuseFenceMarkers(text) !== text` — the ONE sentinel definition serves both the defusing and the
 * detection, so the two can never drift apart. Do not hand-copy the `<<<`/`>>>` pattern anywhere else.
 */
export declare function defuseFenceMarkers(body: string): string;
/**
 * design/177 — control-character hygiene for an untrusted BLOCK that is rendered as-is under a framing
 * line (shared-store document content). Two steps, in order:
 *  ① fold `\r\n` and a lone `\r` to `\n`, so a carriage return cannot repaint a rendered line;
 *  ② scan by code POINT and replace every C0 control except tab and newline, plus the C1 range
 *    (U+007F–U+009F), with U+FFFD.
 *
 * REPLACE, never delete — deliberately, and this is the half a naive strip gets wrong: deletion makes a
 * document with an embedded escape sequence read as clean text, while a replacement character is a scar
 * both the model and a human reviewer can see. Surrogate pairs survive intact (the scan is by code
 * point, not by UTF-16 unit).
 *
 * This is the CHARACTER layer only. Structural containment (elevated-authority tags, fence sentinels)
 * is {@link sanitizeUntrustedText} + {@link defuseFenceMarkers}, which the same pipeline applies after
 * this one — a framing line is a discipline statement, tag neutralization is the structural defense,
 * and an untrusted block needs both.
 */
export declare function defuseControlChars(text: string): string;
/**
 * Make untrusted text safe to interpolate INLINE on a trusted prompt line (not inside a {@link delimitUntrusted}
 * fence) — e.g. design/80 D-F echoes a chosen option label into the "The user answered:" block. Folds EVERY
 * line/space separator to a single space so the text cannot forge a new line — `\s` (covers CR/LF/TAB/VT/FF and
 * U+2028/U+2029 + the Unicode spaces) PLUS the whole C0 + DEL + C1 block (U+0000–U+001F, U+007F–U+009F), which
 * `\s` does NOT fully match: the C1 half carries the 8-bit CSI/OSC/ST forms (U+009B/U+009D/U+009C) a
 * C1-honoring terminal treats like their ESC-prefixed spellings, so leaving them through would let a
 * 'sanitized' value repaint the trusted line it is interpolated onto (adversarial round finding) — caps the
 * length, then applies the same tag-neutralization + fence-sentinel (`<<<`/`>>>`) defusing the fenced
 * body gets.
 *
 * The neutralized tag set is {@link FENCED_LANE_ENVELOPE_TAGS} — the engine's whole AUTHORITY envelope
 * family, not the reminder tag alone. A value interpolated onto a TRUSTED line is the cheapest place to
 * open a forged envelope, and this lane rewrites bytes by contract already, so the whole family is
 * defused here.
 * Defense-in-depth, NOT a guarantee (same posture as the rest of this module).
 */
export declare function inlineUntrusted(text: string, maxLen?: number): string;
/** The mark a cut text ends in: {@link inlineUntrusted}'s, and a notice's machine-read rule text's
 *  ({@link import("./permission-rule-model.js").noticeRuleText}) — one ellipsis, spelled once. */
export declare const INLINE_TRUNCATION_MARK = "\u2026";
/** The code points {@link inlineUntrusted} may return beyond its content cap: the one truncation mark. The longest result for a cap
 *  of `maxLen` is `maxLen` plus this. */
export declare const INLINE_TRUNCATION_MARK_CODEPOINTS: number;
/** The per-ENTRY ceiling inside a `ProbeCause` operand family (checkpoint-store's
 *  structured probe account), sized like the descriptor's own `touchedPaths` entries (the same thing
 *  on the same card). Per entry, not per cause: that is the whole point of the structured shape —
 *  one pathological path costs only itself, where a single joined string let it consume every other
 *  entry's room. HOMED HERE (the leaf neutralizer module) rather than with the `ProbeCause` types:
 *  its two consumers — the shell probe that sanitizes at the entry boundary (tools/fs) and the
 *  descriptor builder that re-sanitizes at the persist boundary (core/checkpoint-store) — sit on
 *  opposite sides of a value-import boundary, and a value import from the shell tool back into
 *  checkpoint-store closed an ESM evaluation cycle (checkpoint-store → tool-policy → tools/fs →
 *  checkpoint-store, a latent TDZ). Both already import this module; one cap, no cycle. */
export declare const PROBE_CAUSE_PATH_MAX = 200;
/** The bloat ceiling on a probe's one-sentence account (`RiskDescriptor.probeReason` /
 *  `AskRequest.probeReason`); the neutralizer is the INJECTION ceiling, this is only the LENGTH one. Homed
 *  here for the same reason as the constant above: three readers — the shell probe that MINTS the sentence
 *  (tools/fs) and must fit every load-bearing part inside this bound, the gate, the persist boundary — and
 *  a value import from tools/fs into checkpoint-store closes an ESM cycle. */
export declare const PROBE_REASON_MAX = 200;
/**
 * Whether `text` is a probe's one-sentence account the engine itself could have minted: every mint passes the sentence through
 * {@link inlineUntrusted} at {@link PROBE_REASON_MAX}, so the longest one is the cap's content plus the truncation ellipsis
 * ({@link INLINE_TRUNCATION_MARK_CODEPOINTS}), counted in code points. A host that relays the sentence (`RiskDescriptor.probeReason`,
 * `AskRequest.probeReason`) and meets a longer one has met text the engine did not mint (a third-party producer, a generation
 * with another cap) — to be dropped whole, not cut, because a cut is another sentence. The bound lives here once; a host asks, it does not count.
 * The question is total: a value that is not a string is not a sentence the engine mints (every mint is a string), so it answers
 * `false` — the relay's answer to it, dropping it whole, is the same as to an over-long one.
 */
export declare function isMintableProbeReason(text: unknown): boolean;
/** The one body bound every "reviewer note" relay passes to {@link delimitUntrusted} — the decider's
 *  free text attached to a deny (sync `AskOutcome.reason` and the durable `ResumeOutcome` `reason`
 *  legs alike). A note is steering, not payload: unbounded it can flood the transcript/context the
 *  refusal lands in. 2048 code points matches the note cap the interactive card layer already
 *  enforces on its own input, so a note that fit the card arrives whole. */
export declare const REVIEWER_NOTE_MAX_BODY = 2048;
/**
 * Wrap untrusted text in a clearly labeled opaque fence. The consuming prompt should instruct the model to
 * treat everything inside as untrusted data — never as instructions. Sanitizes internally (authority-envelope
 * neutralization + fence-sentinel defusing, on the body AND the label), so callers may pass raw
 * worker/external text — and labels derived from external identifiers (hostnames, resource URIs).
 *
 * The neutralized tag set is {@link FENCED_LANE_ENVELOPE_TAGS} — the engine's whole AUTHORITY envelope
 * family (design/319 sibling work): a fence declares its contents to be data, but a forged
 * `<task-notification>` / `<user_memory>` / `<skills>` opening inside it was previously reproduced byte
 * for byte, so a model that skims past the fence line reads harness-shaped text with no judgment bit.
 * This lane rewrites bytes by contract (it is the CONTAINED half; the verbatim quote-back lanes stay
 * frozen and are served by the disclosure trailer instead), so the whole family is defused here.
 *
 * A caller that must DISCLOSE a `maxBody` truncation calls {@link delimitUntrustedWithClip} instead —
 * never a re-derived length test of its own (see that function and {@link neutralizeForFence}).
 */
export declare function delimitUntrusted(label: string, text: string, maxBody?: number): string;
/**
 * The EXACT body neutralization {@link delimitUntrusted} applies, exported so a caller that has to
 * MEASURE the fenced body (its length in code points, whether the cap will bite) measures the string
 * the fence really carries instead of re-deriving the transform from its own copy of the tag list.
 *
 * Two copies of that list is precisely what drifted once the fenced lane widened past the reminder tag:
 * a caller pre-counting with the default (reminder-only) set under-measured the wide-set result by the
 * rewrite's few extra characters per widened-family tag occurrence, so a body got clipped while the truncation disclosure that
 * decision drove was withheld — an externally selectable window just under the cap. Idempotent (both
 * halves are), so a caller may hand the neutralized string straight back to the fence.
 */
export declare function neutralizeForFence(text: string): string;
/**
 * {@link delimitUntrusted} plus the clip verdict, for the callers that must DISCLOSE a truncation on a
 * TRUSTED line outside the fence (§25 honesty: a bare ellipsis reads to the model as the source's own
 * text, so a silent clip is a lie about what the source said).
 *
 * `clipped` is reported by the same measurement that performed the cut. A caller re-deriving "would this
 * clip?" from its own transform + its own tag list is the shape that silently broke when the fence's tag
 * set widened; there is no second condition here to keep in sync.
 */
export declare function delimitUntrustedWithClip(label: string, text: string, maxBody?: number): {
    text: string;
    clipped: boolean;
};
