/**
 * evidenceIndex — what the run can PROVE it read, as a lookup set.
 *
 * Pattern: build once per judgement, ask many times (the same "one pass, then
 *          query" shape the slice layer uses).
 * Role:    core/ layer. The other half of `namesAndNumbersFromEvidence`.
 * Emits:   N/A.
 *
 * ## Why the walk is STRUCTURAL
 *
 * The obvious implementation is `allToolResults.includes(value)`. It is wrong
 * in the direction that matters: a fabricated FCID `0xef0101` "appears" in a
 * blob that contains `0xef01011` or `naa.0xef0101ab`, so the invented value
 * reads as grounded and the check quietly passes everything. So a tool result
 * that parses as JSON is WALKED — every key, every leaf — and each leaf is
 * indexed both whole and tokenized; so is the JSON a result OPENS with when a
 * framework note follows it (`readResult`, over `servedJson.ts`). A result
 * that is not JSON is tokenized as text. Either way the comparison is
 * token-exact, never substring. Under `decimalRounding` a whole token of
 * text in scientific notation also files the exact decimal it states
 * (`1.12e-02` → `0.0112`, {@link addDecimalOf}); the spelling stays.
 *
 * ## What counts as evidence, and what deliberately does not
 *
 *   • **Tool results** — the `role: 'tool'` turns in `scope.history` AS IT
 *     STANDS AT JUDGEMENT. A value the model read from a tool is grounded.
 *
 *     Say that precisely, because "the whole conversation" is only true for an
 *     agent with no window strategy. `.window()` / `.compaction()` /
 *     `tokenBudget` REWRITE `scope.history` in place (window.ts, `scope.history
 *     = result.window`), so on those agents this corpus is the LIVE WINDOW and
 *     a result the window has dropped is not in it — the same value then reads
 *     as ungrounded. `keepLastToolResults` (default 2) is what keeps the most
 *     recent observations pinned; nothing pins the rest. Anything computed from
 *     this index therefore describes what the run can still SEE, never
 *     everything it ever read.
 *   • **Object KEYS count.** A map keyed by WWN puts real identifiers in key
 *     position, and the model saw them exactly as it saw the values.
 *   • **Tool call ARGUMENTS do not count.** The model typed those. Grounding a
 *     value because the model passed it to a tool would let any invention
 *     launder itself through one failed lookup.
 *   • **The model's own earlier answers do not count**, for the same reason.
 *   • **An `absent(…)` result grounds everything EXCEPT `looked_for`.** Its
 *     coverage lists, its `try_instead`, its note and any extra key the tool
 *     attached (a `known_shares` list, say) are the tool's own words about the
 *     world, and an answer that follows the absence's advice must not be
 *     called ungrounded for doing so. `looked_for` alone quotes the arguments
 *     the model passed, so indexing it would ground an invented identifier
 *     through the one operation that proves nothing about it: a lookup that
 *     found nothing. See `../../../semantics/coverage/evidence.ts`.
 *
 * The EXEMPT index is built from a different corpus with the same machinery:
 * the user's own message, the conversation's user/system turns, the values
 * the person typed into a typed ask (`requestInput` — its `input_received`
 * result is a `role: 'tool'` message carrying THEIR words), and the
 * system-prompt content this turn was built from — each text with the other
 * spellings of the dates and clock times in it (`time/forms.ts` ·
 * `timeFormsOf`'s `said` list: `8 Am` is also `8:00`, `2026-10-09` also
 * `2026`) — and, under `.time()`, the said spellings of the turn's recorded
 * windows (`timeSaid`). A compaction summary is a
 * user-role turn a MODEL wrote, so its text is not in it — the summary
 * carries the forms its folded person/app turns exempted instead
 * (`LLMMessage.foldedExempt`, {@link exemptLineageOf}). A value the user supplied is
 * not a fabrication — the user gave it — and neither is one the app's own
 * prompt or skill body put in front of the model.
 *
 * ## WHEN a value was read, and why the corpus is still conversation-wide
 *
 * The corpus above answers "did the run read this?" and says nothing about
 * WHEN. That gap has a measured cost: an agent answered a fresh question with
 * ZERO tool calls, and the gate approved it because all seven values appeared
 * in an inventory result fetched four turns earlier for a different question.
 * Grounded, and four turns out of date.
 *
 * The fix is NOT to narrow the corpus to this turn. "And what about that
 * disk?" legitimately leans on the previous turn's rows, and flagging those
 * would make the gate cry wolf until somebody switched it off. So the corpus
 * stays whole and every indexed form carries the TURN it was last served in
 * — one number, stamped during the walk that was happening anyway.
 *
 * A TURN starts at each `role: 'user'` message the library did NOT author.
 * `isLibraryAuthoredTurn` (frames.ts) is a statement about AUTHORSHIP, not
 * about time — it exists to keep the exempt corpus from swallowing the gate's
 * own corrections — and it is reused here for a different reason that happens
 * to need the same predicate: a frame the library wrote is not a person asking
 * something new. Excluding them is load-bearing rather than tidy. The evidence
 * recheck appends a `role: 'user'` turn MID-RUN, so counting it as a boundary
 * would push this turn's own tool results into the "earlier" bucket and file a
 * notice against every revised answer.
 *
 * Turn 1 is the first user message still in the window; anything indexed
 * before one (a history with no user turn at all) is turn 0, which is also
 * `currentTurn`, so nothing can read as earlier and no notice can be filed
 * from a conversation with no boundary in it.
 *
 * **The ordinals are WINDOW-RELATIVE**, and that is the honest bound: they
 * count the user turns the run can still see, so under a window strategy
 * "turn 2 of 4" may be the conversation's turn 9 of 13. The BOUNDARY is
 * exact regardless — the current request is un-droppable by every window
 * strategy (`'current-request'`, window/currentRequest.ts) — so "this turn
 * versus earlier" holds; only the DISTANCE is a floor.
 */
import type { LLMMessage } from '../../../provider-contract/types.js';
import type { InjectionRecord } from '../../../recorders/core/types.js';
import type { ResolvedEvidenceGate } from './types.js';
/**
 * Ceiling on indexed tokens. Generous — a 200 000-token corpus is roughly a
 * 5 MB tool result — because the cost of hitting it is not "slower", it is
 * "the gate stops accusing" (see {@link EvidenceCorpus.truncated}). The
 * declared-sources check reads a haystack to the same ceiling and says
 * `uncheckable` past it (`evidence/resultCarries.ts` · `resultReader`).
 */
export declare const MAX_INDEX_TOKENS = 200000;
/**
 * How many results one indexed form remembers as its CARRIERS (9.110.0)
 * before the list is cut and marked. Eight, because the question the list
 * answers — "did EVERY result that carried this value get judged non-fact?"
 * (`findings/contingent.ts`) — needs the whole list or none of it: a value
 * nine results carried is a common value, not a tower, and the honest answer
 * for it is "not judged" rather than a verdict read off a prefix.
 */
export declare const MAX_CARRIERS = 8;
/**
 * Which of THIS turn's tool results carried one indexed form (9.110.0) —
 * the `toolCallId` of each `role: 'tool'` message that served it, in wire
 * order, each id once. The other half of the provenance the walk already
 * had: `values` says WHEN a value was last read, this says FROM WHERE.
 */
export interface ValueCarriers {
    readonly toolCallIds: readonly string[];
    /**
     * Set when more than `MAX_CARRIERS` results carried the form: the list is
     * the first `MAX_CARRIERS` and a reader must not judge "every carrier"
     * from it.
     */
    readonly truncated?: true;
}
/** A finished index plus the honesty flag that says whether it is complete. */
export interface EvidenceCorpus {
    /**
     * Every indexed form, stamped with the LATEST turn whose tool result
     * carried it.
     *
     * A Map rather than a Set plus a second structure: the walk already visits
     * each leaf once, so the turn is an attribute of the entry it was going to
     * write anyway. `.has()` reads exactly as it did when this was a Set, which
     * is all the grounding decision ever needed; `.get()` is the new half.
     *
     * LATEST, not first, and the direction is the whole point: the question is
     * "could this turn's own results have supplied this value?", so a form
     * served in turn 2 and again in turn 7 is turn 7's.
     */
    readonly values: ReadonlyMap<string, number>;
    /**
     * Every indexed form THIS turn's tool results carried, with the ids of
     * the results that carried it (9.110.0) — `value → carriers`, beside
     * `value → turn`, written by the same walk at the same leaf. Only the
     * current turn's results are listed: the carriers of an earlier turn are
     * dropped at each turn boundary, so on a continued conversation a value
     * read four turns ago has a turn stamp here and no carrier. Bounded per
     * form by `MAX_CARRIERS` (the list is cut and marked `truncated`), and by
     * the same token budget as `values` — a form the budget refused has no
     * entry here either. Read by the contingent check
     * (`findings/contingent.ts`), which asks whether every carrier of a value
     * the model USED was one the model itself declared open, noise or
     * ruled-out.
     */
    readonly carriers: ReadonlyMap<string, ValueCarriers>;
    /**
     * True when the ceiling was hit and the index is INCOMPLETE. The gate
     * downgrades itself to record-only when this is set: a partial corpus can
     * call a grounded value fabricated, and an accusation from a half-read
     * corpus is worse than no accusation at all.
     */
    readonly truncated: boolean;
    /**
     * The turn in progress — the ordinal every stamp above is compared against.
     * `0` means the history carries no user turn at all, so there is no
     * boundary and nothing can be attributed to an earlier one.
     */
    readonly currentTurn: number;
    /**
     * How many `role: 'tool'` results this turn served. `0` is the sharp case:
     * a turn that fetched nothing sourced every value in its answer from
     * history, by construction and without needing the index to prove it.
     */
    readonly toolResultsThisTurn: number;
}
/**
 * How ONE result reads: its JSON walked (`parsed`) and any text beside it read
 * as text (`tail`: a note after the JSON, or the whole words of a string the
 * JSON was cut inside), or — when it opens with no JSON the grammar can read —
 * its text.
 */
export type ResultReading = {
    readonly parsed: unknown;
    readonly tail?: string;
} | {
    readonly text: string;
};
/**
 * How ONE tool result is read — the one reading both the index
 * (`indexResult`) and the per-result question (`resultCarries.ts` ·
 * `resultReader`) take: the parsed JSON when it is JSON (`asEvidence`: an
 * absence's `looked_for` projected away, a capped result's head read too), its
 * text otherwise.
 *
 * A result that is NOT one JSON value but OPENS with one — the tool's JSON
 * with a framework note joined after it (a step banner, an effect note, the
 * repeated-call note), or several JSON blocks (an MCP text result's content
 * blocks) — reads as those leading values, walked, and the text after them as
 * `tail`; one cut short before it closes (a tool that truncated its own
 * output) reads as the leaves the grammar can read, and — cut inside a
 * string — that string's whole words as `tail` (`servedJson.ts` ·
 * `jsonPrefixOf`: never the word the cut may have split). Read whole as text,
 * `{"id":4417}` tokenises to `:4417`, and every number and boolean the tool
 * returned would read as absent. Text that opens with a brace and is not JSON
 * (a log line) stays text.
 */
export declare function readResult(content: string): ResultReading;
/**
 * Build the evidence corpus from the history AS IT STANDS: every `role: 'tool'`
 * turn still in it, each indexed form stamped with the turn that served it.
 *
 * In a single-turn run these are exactly this turn's tool results. In a
 * continued conversation the earlier turns' results are in here too, and that
 * is deliberate: the model really did read them, and calling a value from turn
 * one a fabrication in turn two would be false. Which earlier turns are still
 * here is the WINDOW's decision, not this function's — see the header.
 */
export declare function evidenceFromHistory(history: readonly LLMMessage[], 
/**
 * The gate this corpus is judged by. Under its `decimalRounding`, a
 * standalone scientific token in a result's text also files the exact
 * decimal it states, unless it matches one of its declared `shapes`.
 * Absent, or the dial off → the corpus it always was.
 */
gate?: Pick<ResolvedEvidenceGate, 'decimalRounding' | 'shapes'>): EvidenceCorpus;
/**
 * The exemption lineage of a span about to be folded: every lookup form the
 * exempt corpus holds for these messages, in first-seen order — the person's
 * and the app's turns by the corpus's own rule, a nested summary by the
 * lineage IT carried, and a typed-ask answer by the values the person typed
 * into it (its `input_received` result is their words). Every other tool
 * result contributes nothing here: a summarized tool value keeps its tool
 * source and is judged against the tool results still in the window, exactly
 * like a value whose result a drop removed.
 *
 * @example
 * ```ts
 * const lineage = exemptLineageOf([{ role: 'user', content: 'Check array ARR-2291.' }]);
 * lineage.includes(normalizeToken('ARR-2291')); // true — the person's value
 * exemptLineageOf([{ role: 'tool', content: 'ARR-7', toolCallId: 't1' }]); // [] — a tool's
 * ```
 */
export declare function exemptLineageOf(span: readonly LLMMessage[]): readonly string[];
/**
 * Build the exempt corpus: everything the RUN put in front of the model that
 * the model did not invent — the user's message, the conversation's user and
 * system turns, and the composed system prompt (base prompt, skill bodies,
 * facts, retrieved passages).
 *
 * `rawContent` is optional on an {@link InjectionRecord} — a record that was
 * summarised or redacted contributes what it has. That direction is the safe
 * one: a missing exemption can only cost a false flag on a value the app
 * supplied, and the caller can name it in `exempt`.
 *
 * STATED REACH, because `systemPromptInjections` is broader than "the app's
 * own prompt": it also carries `.memory()` recall and RAG passages. A value
 * that reached the model through memory or retrieval is therefore EXEMPT from
 * grounding — never flagged, and never counted as tool evidence of any turn,
 * so it is invisible to the recency read too. That is the correct call for the
 * fabrication question (the run really did put those words in front of the
 * model) and a real blind spot for the recency one, and it is deliberately NOT
 * fixed here: recall is its own seam, with its own record
 * (`retrievalEvidence_<id>`, `agentfootprint.memory.attached`), and giving a
 * recalled passage a turn stamp means deciding whose turn it belongs to — the
 * one it was written in or the one it was recalled in — which is a question
 * this file has no standing to answer.
 */
export declare function exemptFromRun(args: {
    readonly userMessage?: string;
    readonly history: readonly LLMMessage[];
    readonly systemPromptInjections?: readonly InjectionRecord[];
    /**
     * The declared `assume` values of every (tool, argument) that filed a
     * `default` row this turn (the inputs layer, honesty layer 2) — the APP's own
     * declaration, read from the tool's rule and never from the row, exempt like
     * a value in the system prompt. Absent → the corpus it always was.
     */
    readonly declaredDefaults?: readonly string[];
    /**
     * The values the PERSON gave this turn by answering the inputs layer's
     * batch ask (honesty layer 2, step 4) — read from this turn's `answered`
     * rows. The library's ask writes no message, so this is the one door the
     * answer reaches the gate through. Absent → the corpus it always was.
     */
    readonly answeredValues?: readonly string[];
    /**
     * Under `.time()` (step T7): the SAID spellings of this turn's recorded
     * windows (`time/forms.ts` · `timeFormsOf`) — the parts the person
     * wrote, confirmed, typed or set, at the grain they gave them. Absent →
     * the corpus it always was.
     */
    readonly timeSaid?: readonly string[];
}): ReadonlySet<string>;
/**
 * The lookup forms of the spellings the library DERIVED from this turn's
 * time readings (`time/forms.ts` · `timeFormsOf`'s `derived` list, the
 * values the library filled from a window, the served time line) — each
 * value indexed whole and by its tokens, exactly as the exempt corpus
 * indexes a text. A value the answer took only from here is filed
 * `derived-from-reading` (time design § 9.5): never invented, never known.
 *
 * @example
 * ```ts
 * derivedFormsOf(['2026-10-09T15:00:00Z', 'PDT']).has('pdt'); // true
 * ```
 */
export declare function derivedFormsOf(spellings: readonly string[]): ReadonlySet<string>;
