/**
 * Detect **degenerate repetition** — the most common LLM failure mode: a model that gets stuck
 * emitting the same character or short phrase forever (often with no punctuation), e.g. `啊啊啊啊…`
 * or `the answer is the answer is the answer is…`. Brains poll this over the growing output and, on a
 * hit, **cancel the stream** and mark the turn errored, so the loop doesn't keep paying for garbage and
 * downstream (e.g. a team member) treats it as a failed turn rather than a real statement.
 *
 * Only an *exact* tail repetition trips it (character-for-character). The original header claimed
 * normal code "won't false-positive" because repeated structure differs in content — **falsified in
 * the field** (docs/DEADTARGET-WINNING-AVG-COREWARS-2026-07-10.md §〇-3): legitimate code repeats the
 * SAME line verbatim (redcode boot blocks `mov <bootsrc, {bootdst` ×6-8, SQL fixture rows, ASCII-art
 * banners), landed exactly in the rule-2 window, and the cut stream three-struck whole TB tasks dead.
 * Hence two structural allowances, both bounded so true runaway loops are still caught:
 *   - rule 1 exempts short symbol runs (ASCII dividers) — a run of a non-letter/digit char only
 *     counts as degenerate past `CHAR_RUN_SYMBOL`;
 *   - rule 2 exempts *code-line-shaped* units (full-line repeats carrying operand/structure chars or
 *     indentation) unless the loop SATURATES the inspection window AND is `SATURATION_REPS` deep in the
 *     output — no legitimate boot block is 16+ identical lines deep with nothing after it.
 *
 * Known residual (HRD-BRN-2): rule 2 itself never fires for a unit longer than ~66 chars, because reaching
 * `MIN_REPS` inside the fixed 400-char window requires `p ≤ WINDOW/MIN_REPS`. That is rule 2's general
 * geometry (it applies to prose units too), not the code-line allowance, and widening it means growing
 * the window — deliberately left alone rather than traded for false cuts on long legitimate lines.
 */
/**
 * The errorMessage a brain stamps on a turn it cut off for degenerate repetition — the human-readable
 * DISPLAY text, and nothing more. It is a single exported constant so the brains do not each invent their
 * own wording, but it is no longer the cross-layer signal: since RB-482 #12 the detection contract is
 * `AssistantMessage.errorKind === "degenerate"` (read via `isDegenerateCutMessage` in
 * ./terminal-cause.js), which `assembleResult` maps to `errorCode="output.degenerate"` + salvages the
 * turn text (design/39). Reword this freely; do NOT match on it. Wording: the output is salvaged now,
 * not discarded.
 */
export declare const DEGENERATE_MESSAGE = "degenerate repetition detected \u2014 the model looped on the same text; output cut off at the repetition";
/**
 * One detector hit — either the event that CUT a stream (`degenerate`) or a repetition that landed in
 * a detection window but was SPARED by a 2e1c161 structural allowance (code-line shape / divider run).
 * Spared events are the RSI raw material for judging whether the allowance is too wide or too narrow
 * (2026-07-10: the detector must report counts AND the detected segment, not just a boolean).
 */
export interface RepetitionEvent {
    /** Which rule's window the repetition landed in: rule 1 (`char-run`) or rule 2 (`unit-loop`). */
    rule: "char-run" | "unit-loop";
    /** Repeating-unit length in chars (1 for a char run). */
    period: number;
    /** How many times the unit repeated (the run length for a char run). */
    reps: number;
    /** Sample of the repeated unit/tail, truncated to ≤{@link SEGMENT_MAX} chars. */
    segment: string;
}
/** Structured result of one detector pass over a (growing) output tail. */
export interface RepetitionInspection {
    /** True ⇒ a degenerate loop tripped — the caller should cut the stream (same verdict as `looksDegenerate`). */
    degenerate: boolean;
    /** The event that tripped; present iff `degenerate`. */
    cut?: RepetitionEvent;
    /** Allowance-spared hits (at most one per rule per pass — the smallest period is the fundamental one). */
    spared: RepetitionEvent[];
}
/**
 * Structured detector pass: same verdict as {@link looksDegenerate}, plus WHAT hit (`cut`) and what
 * the 2e1c161 allowances spared. Spared collection is bounded: at most one `char-run` and one
 * `unit-loop` event per pass (rule 2 keeps the smallest period — the fundamental unit — so a p and
 * its 2p/3p multiples don't report the same loop several times).
 */
export declare function inspectDegenerate(text: string): RepetitionInspection;
export declare function looksDegenerate(text: string): boolean;
/**
 * T1-4 (brain stream-layer truncation): drop the degenerate TAIL off the text face that tripped a
 * cut, keeping ONE instance of the repeating unit, so the salvaged prefix lands in the final
 * assistant content / `salvagedOutput` without hundreds of chars of loop garbage (which the loop's
 * bounded degenerate-recovery continue would otherwise re-feed the model as context — the very text
 * it must not repeat).
 *
 * Always-on by design (no opt-out flag). The honest bound — not "zero information loss":
 *  - everything removed is a byte-identical duplicate of the unit that is KEPT, so no UNIQUE text is
 *    ever swallowed (a non-repeating tail never matches and is returned unchanged). What CAN be lost
 *    is a repetition COUNT: legitimate text ending with the same unit repeated (an intentional
 *    "very very" abutting a "very"-loop) folds into the loop and collapses to the single kept
 *    instance. That only happens on a stream the detector ALREADY cut as degenerate, and the
 *    alternative is worse (the full loop tail re-fed to the model);
 *  - most legitimate verbatim repetition (code lines, dividers) never gets here — the allowances
 *    spare it upstream, and a spared stream is never cut;
 *  - the loop may have grown far past the 400-char inspection window before the poll fired; the
 *    scan below strips ALL trailing repeats (and one trailing PARTIAL unit from post-cut buffered
 *    deltas), not just the reps the window measured.
 *
 * Fail-safe floor: the trim only fires when the tail ends with ≥2 exact repeats of the cut event's
 * unit — a WRONG-face call (e.g. the cut tripped in thinking, this is the text face) is structurally
 * a no-op unless that face coincidentally ends with ≥2 exact unit repeats (in which case those — and
 * any partial-unit suffix stripped with them — fold like any other repeats; same bounded cost as
 * above). Thinking/reasoning faces are deliberately never trimmed by the brains: anthropic thinking
 * blocks are signature-sealed for replay (mutating them invalidates the signature), and neither face
 * reaches `salvagedOutput`.
 */
export declare function trimDegenerateTail(text: string, cut: RepetitionEvent): string;
