/**
 * design/319 (B ticket) — detect-and-disclose TRAILER for reminder-shaped text in external data,
 * plus the MCP/web exact-mark defuse arm, in ONE ordered pipeline.
 *
 * The mark (A ticket, reminder-mint.ts) makes a forged `<system-reminder>` byte-distinguishable;
 * this module is the adjacency half: when a verbatim outlet (Read text/notebook/PDF text, the MCP
 * success arm) serves external bytes that LOOK like the engine's reminder tag, a trusted, marked
 * reminder is appended AFTER the data saying exactly what was found — the data bytes themselves
 * stay untouched on the strong quote-back lanes (Read↔Edit `old_string`; G3 is the veto gate).
 *
 * FOUR-STEP ORDER (design/319 §3e, single-sourced here so no outlet can re-derive it wrong):
 *   ① the caller finalizes the external projection (decode/concat/truncate done, trusted tails
 *      NOT yet appended) and hands it in as ordered text segments;
 *   ② the WHOLE projection is scanned ({@link scanReminderShaped} — full scan, never first-match:
 *      a bare decoy ahead of a marked forgery is judged marked) and the verdict recorded;
 *   ③ (MCP/web outlets only) exact-mark bytes are defused ({@link defuseExactMark}) — detection
 *      MUST precede this step: the defused text no longer carries the exact mark, so a reordered
 *      pipeline would misreport a marked forgery as the bare form (a disclosure that lies);
 *   ④ the trailer is appended, marked-form copy ALWAYS winning over the bare copy.
 *
 * ENVELOPE FAMILY (the envelope-census batch). `<system-reminder>` is not the only authority envelope
 * the engine mints — untrusted-text.ts `ENGINE_ENVELOPES` is the census, and the rows flagged
 * `disclosed` are scanned here too ({@link scanEnvelopeShaped}, step ② beside its sibling). They carry
 * no mark, so their disclosure sentence is POSITIONAL rather than byte-level ("an authentic one is
 * minted by the engine as its own message and never arrives inside file/command/server bytes"), which
 * is what lets the whole family be covered with ZERO byte change on any lane. The two families share
 * one TRAILER but keep SEPARATE throttle windows (see the ④ note): sharing the window would let an
 * envelope-only projection suppress a later reminder-only one, which is a behavior change to a
 * shipped arm rather than a shared budget. With no envelope hit, every arm below renders
 * byte-identically to the design/319 shipped copy — across a sequence, not just within one call.
 *
 * THROTTLE (bare form only): a code agent reading engine-family source trips the bare form
 * constantly (this repo's own tree carries the tag literal in dozens of files) — real disclosures,
 * not misfires, but they must not tax every page of a long read. The bare copy therefore dedups
 * per throttle key (the file path / the MCP server:tool) inside a 60s window (the gh-rate-limit
 * hint's window precedent). The MARKED copy is NEVER throttled: on the non-defusing Read lanes it
 * is the only in-band warning a leaked/forged mark gets, and consuming its budget with source
 * reads would silence exactly the rare event the trailer exists for (design/319 r2-F2).
 *
 * OBSERVATION SEAT: every append/defuse/suppression bumps a per-run counter keyed
 * `<outlet>.<form>` — surfaced as `TaskResult.stats.mechanisms.reminderDisclosures` — the G9②
 * trigger-rate reading that the D-4/D-6 re-rulings (defuse/trailer widening to Read/Bash/Grep)
 * are waiting on.
 *
 * A `mark` of `undefined` disables the whole pipeline (segments returned untouched, no trailer):
 * a library-direct mount that threaded no mark has no system-prompt declaration either, so a
 * trailer speaking about "this session's mark" would reference a contract that does not exist —
 * same byte-compat posture as every markless arm of the A ticket.
 */
/** Per-run mutable trigger counters, keyed `<outlet>.<form>` (e.g. `read.bare`, `mcp.defused`,
 *  `read.bare_throttled`). Minted once per prepared task leg and threaded to every outlet; folded
 *  into `TaskResult.stats.mechanisms.reminderDisclosures` when any key is non-zero. */
export type ReminderDisclosureCounts = Record<string, number>;
/** Bump one observation counter (no-op without a counts seat — library-direct mounts). */
export declare function bumpReminderDisclosureCount(counts: ReminderDisclosureCounts | undefined, key: string): void;
/**
 * OBSERVATION-ONLY seat for a BARE MARK ECHO — the session's exact mark VALUE appearing in external
 * bytes that carry no reminder-shaped TAG. {@link scanReminderShaped}'s grammar (the single detection
 * predicate, shared with the neutralizer so disclosure and defusal can never drift apart) judges
 * TAGS, so a naked 22-character mark reaches a verbatim/fenced outlet with `hit: false` — no `marked`
 * verdict is reachable, and before this seat no counter was either.
 *
 * The DEFENSE half of that shape is ruled covered and stays untouched here: a bare value carries no
 * authority FORM (the fenced arms neutralize every reminder-shaped tag, so the value is inert data),
 * and a mark VALUE with no tag around it asks the model nothing (the declaration speaks of reminder
 * TAGS, not of a bare value, and orders the value never written anywhere). What was
 * missing is purely this module's own stated seat: a lane whose leak/echo rate cannot be COUNTED
 * cannot later be argued about (the trigger-rate reading the trailer/defuse widening re-rulings
 * wait on). So this port counts, never rewrites and never appends — zero model-facing byte change
 * on every caller.
 *
 * Fires only where the defuse does not: on a defusing outlet any mark occurrence already lands as
 * `<outlet>.defused` + `<outlet>.marked`, so `<outlet>.mark_echo` reads unambiguously as "an arm
 * that serves this outlet's bytes without defusing saw the mark" — the Read-family verbatim lanes,
 * and the fence-but-never-defuse FAILURE arms (an MCP tool call's server-signaled, protocol and raw
 * rejections, WebFetch's non-2xx result, WebSearch's backend error) whose success twins disclose.
 *
 * CALL-SITE RULE (settled after three adversarial rounds spent moving the observation point between
 * successive bounds — truncate vs fence, fence-bound vs raw, and a fragment that never entered the
 * fence at all): **observe ONCE, at the arm's single composition or exit point, on the WHOLE string
 * that arm hands to the model.** Never on a fragment, never before a bound the arm itself applies.
 * The enumeration of "which pieces are external, and which bound has landed on each" was the defect;
 * a composed string has no enumeration to get wrong.
 *
 * CONTRACT: the count is an UPPER BOUND on model exposure, never an under-count. Bounds an arm does
 * not own — a downstream, outlet-independent clipper on the assembled tool result — may still drop
 * part of what was observed, so a mark surviving only into a discarded tail is counted anyway. That
 * asymmetry is chosen: a seat that misses a real leak is worthless; one that occasionally
 * over-reports is merely conservative.
 */
export declare function observeReminderMarkEcho(input: {
    text: string;
    mark: string | undefined;
    outlet: ReminderDisclosureOutlet;
    counts?: ReminderDisclosureCounts;
}): boolean;
/** Bare-form dedup window per throttle key (the gh-rate-limit 60s precedent — see module header). */
export declare const BARE_REMINDER_DISCLOSURE_WINDOW_MS = 60000;
/** The outlets that run this pipeline. Read/Bash/Grep clean output deliberately do NOT appear:
 *  Bash/Grep carry no trailer at all (ruled — for the `<system-reminder>` family the mark covers
 *  their impersonation half; the observation seat is the widening data), and no outlet here ever
 *  defuses Read-family bytes.
 *
 *  SCOPE CORRECTION (the envelope-census batch): that ruling's premise held for ONE envelope. The
 *  engine mints several model-facing authority envelopes (untrusted-text.ts `ENGINE_ENVELOPES`), and
 *  the others carry no mark at all, so on the Bash/Grep lanes a forged `<task-notification>` still
 *  has neither a mark test nor a trailer. The ruling itself is unchanged here (widening Bash/Grep is
 *  a separate, model-facing decision with its own trigger-rate evidence bar); what changed is that
 *  the outlets which DO carry a trailer now report the whole family, not just the reminder tag. */
export type ReminderDisclosureOutlet = "read" | "notebook" | "pdf" | "mcp" | "webFetch" | "webSearch";
export interface ReminderDisclosureInput {
    /** The finalized external projection, as ordered text segments (one per model-facing text
     *  block; a single-string outlet passes `[text]`). Detection judges the seam-joined view so a
     *  tag synthesized across a block seam is still caught (over-detection is the safe direction). */
    segments: readonly string[];
    /** The session's reminder provenance mark; `undefined` disables the pipeline (see header). */
    mark: string | undefined;
    outlet: ReminderDisclosureOutlet;
    /** True ONLY on the MCP-success/web outlets (§3b) — Read/notebook/PDF must pass false: their
     *  lanes are zero-byte-change by invariant (G3 veto). */
    defuseExactMark: boolean;
    /** Bare-form throttle seat: `windows` maps key → next-allowed epoch ms (per tool closure ≈ per
     *  task). Absent ⇒ the bare form is never suppressed (single-shot outlets). */
    throttle?: {
        key: string;
        windows: Map<string, number>;
        now?: number;
    };
    counts?: ReminderDisclosureCounts;
}
export interface ReminderDisclosureOutcome {
    /** The segments to serve — byte-identical to the input segments unless `defused`. */
    segments: string[];
    /** A full trusted reminder block (self-marked) to append AFTER the data, or `undefined`. */
    trailer: string | undefined;
    /** `marked`/`bare` are the `<system-reminder>` verdicts (mark present vs absent). `envelope` is the
     *  ENVELOPE-FAMILY-only verdict: no reminder-shaped text at all, but text shaped like one of the
     *  engine's other authority envelopes. When BOTH are present the reminder verdict names the form
     *  (it is the stronger one) and the envelope sentence is appended to its copy. */
    form: "bare" | "marked" | "envelope" | undefined;
    /** True iff the exact-mark defuse rewrote bytes. Judged over the JOINED projection (adversarial
     *  round: a mark split across a block seam is invisible as a seam to the model and must be
     *  defused too — {@link defuseExactMarkInSegments}), so on a defusing outlet this is `true`
     *  exactly when the joined projection carried the mark, and the post-defuse concatenation never
     *  does. */
    defused: boolean;
    /** True iff a trailer that was due got suppressed by a throttle window. Each family owns its own
     *  window, so a mixed projection can emit one family's copy while reporting the other's
     *  suppression — `throttled: true` alongside a defined `trailer` is that state, not a contradiction. */
    throttled: boolean;
}
/**
 * What a planned disclosure will say, as a value: which sentences the trailer carries. The Read carrier
 * renders it with {@link renderReminderDisclosureTrailer} (the bytes the pipeline has always appended);
 * another carrier renders the same verdict in its own words. Undefined `reminder` and `envelopeTags` ⇒ no
 * trailer.
 */
export interface ReminderDisclosureVerdict {
    /** The `<system-reminder>`-family sentence: the marked copy (with whether the defuse arm rewrote bytes)
     *  or the bare copy. */
    reminder?: {
        form: "marked";
        defused: boolean;
    } | {
        form: "bare";
    };
    /** The envelope-family sentence, with the REGISTRY tag names it names (never matched bytes). */
    envelopeTags?: readonly string[];
}
/** The state a planned disclosure changes — applied by {@link commitReminderDisclosureEffects}, never by
 *  the plan: the counter keys to bump (one entry per bump, in pipeline order) and the throttle windows to
 *  advance (key → next-allowed epoch ms). */
export interface ReminderDisclosureEffects {
    counts: readonly string[];
    windows: ReadonlyArray<readonly [string, number]>;
}
/** {@link planReminderDisclosure}'s answer: the outcome the pipeline reports, the verdict a carrier renders,
 *  and the effects a delivery commits. */
export interface ReminderDisclosurePlan {
    outcome: Omit<ReminderDisclosureOutcome, "trailer">;
    verdict: ReminderDisclosureVerdict;
    effects: ReminderDisclosureEffects;
}
/**
 * Plan the four-step pipeline over one finalized external projection WITHOUT changing anything: the
 * throttle windows are read (a due bare/envelope sentence is suppressed by a live window) but never
 * advanced, and the counters are not bumped — both land in `effects`, which the caller commits when the
 * projection is actually delivered ({@link commitReminderDisclosureEffects}). Two plans over the same key
 * before either commits both see the window open; that is the defined meaning of "effects ride the
 * delivery".
 */
export declare function planReminderDisclosure(input: ReminderDisclosureInput): ReminderDisclosurePlan;
/** Apply a plan's effects: bump each counter key, advance each throttle window. `windows` is the map the plan
 *  read (the outlet's per-closure throttle seat); either seat may be absent (library-direct mounts). */
export declare function commitReminderDisclosureEffects(effects: ReminderDisclosureEffects, seats: {
    counts?: ReminderDisclosureCounts;
    windows?: Map<string, number>;
}): void;
/** The trailer a verdict renders to on the tool-result carrier — a full trusted reminder block (self-marked),
 *  or undefined when the verdict carries no sentence. Byte-identical to the pipeline's historical trailer. */
export declare function renderReminderDisclosureTrailer(verdict: ReminderDisclosureVerdict, mark: string | undefined): string | undefined;
/**
 * Run the four-step pipeline over one finalized external projection and commit its effects at once — the
 * single-shot outlets (MCP, web) whose projection is delivered in the same breath. Plan + commit + render:
 * the windows and counters move exactly as they always did.
 */
export declare function discloseReminderShaped(input: ReminderDisclosureInput): ReminderDisclosureOutcome;
