/**
 * figures — a number wearing a unit is data, and a number no result carried
 * is asked whether it DERIVES from the numbers one did, before it is flagged.
 *
 * Pattern: two pure folds — over the answer's text (`figureNumbersOf`) and
 *          over the tool results (`figureBasisOf`) — and one question
 *          (`explainFigure`). Deterministic arithmetic, no model.
 * Role:    core/ layer, loaded only under `figures` or `decimalRounding`.
 *          Both off, nothing here runs and ordinary verdicts are byte-identical.
 * Emits:   N/A.
 *
 * ## The hole this closes
 *
 * "How full is the cluster?" — a small model answered "53.2% used, 6.3 TB
 * free" and, on a second run, "64.5% used, 24.8 TB usable". The tool's rows
 * said 61.1% / 435.5 TB and 57.7% / 1,090.8 TB; neither answer's figures are
 * anywhere in them. The gate passed both answers CLEAN: `53.2`, `6.3`, `64.5`
 * and `24.8` have under `minDigits` (4) digits, so the extractor read them as
 * prose ("3 issues", "24 hours") and never looked them up. The bias is right
 * for a count in a sentence and wrong for a MEASUREMENT: a number with a unit
 * of measure stuck to it is a reading off a screen, whatever its length.
 *
 * And the reverse: the honest answer to the same question is a CLUSTER total
 * — "1,526.3 TB usable" — which is a sum, and appears in no result. The gate
 * flagged it as invented. A derived figure is neither read nor invented.
 *
 * ## The rule
 *
 * 1. **A figure is a number wearing a unit** (`FIGURE_UNITS`: `%`, `percent`,
 *    byte sizes, IOPS, throughput, `ms`/`us`), glued or one space apart. It is
 *    a candidate whatever its digit count. A whole number with no unit stays
 *    under `minDigits`' rule.
 * 2. **A number no result carried is asked for a derivation** — the closed set
 *    `FigureDerivation`, each over numbers the results DID carry, compared at
 *    the answer's own precision (`61%` matches 61.1; `61.0%` does not):
 *      • `rounded`            — a carried number, rounded;
 *      • `unit-scale`         — a carried number ÷ 1000^k or 1024^k (k = 1…5):
 *                                bytes stated as TB/TiB;
 *      • `column-sum`         — the sum of one numeric field over the rows of
 *                                one list (an array of objects, or a map of
 *                                objects), or over the rows sharing one value
 *                                of a text field (`cluster = A`); also scaled;
 *      • `column-ratio`       — 100 × one column sum ÷ another, both fields
 *                                wearing the same unit suffix (`used_tb` /
 *                                `total_tb`) — a percentage of totals;
 *      • `column-difference`  — one like-unit column sum minus another
 *                                (`total_tb` − `used_tb`), when positive;
 *      • `complement`         — 100 − a carried percentage (a field whose name
 *                                ends in `pct`/`percent`) or 100 − a ratio
 *                                above.
 *    A number that is one of these is COMPUTED (`EvidenceVerdict.computed`,
 *    with the derivation named); one that is none of them is UNSUPPORTED, and
 *    the sentences say so: no value, and no derivation.
 *
 * ## What it is not
 *
 * Not proof the arithmetic answered the question: "59.2% used" is accepted
 * as the ratio of two columns even if the person asked about one pool. Not
 * open-ended: a product, an average, a chain of two derivations, or a sum
 * over an arbitrary subset of rows is not reconstructed and is flagged — the
 * set is closed on purpose, because every derivation added is a window an
 * invented number can fall through by coincidence. The coincidence is real
 * and bounded by precision: a whole-number figure matches anything within
 * ±0.5 of it, a one-decimal figure ±0.05. The basis is bounded too
 * (`MAX_BASIS_NUMBERS`, `MAX_DERIVED`); past a bound the remaining numbers
 * are not asked about, which can only flag MORE, never fewer.
 */
import type { LLMMessage } from '../../../provider-contract/types.js';
import { LIBRARY_NOTE_OPENING } from '../../../lib/saidByPerson.js';
import type { EvidenceShape, FigureDerivation, UnsupportedValue } from './types.js';
/** Units that make a number a figure. Lower-case; `/s` may follow a size. */
export { FIGURE_UNITS } from './figureUnits.js';
/** How many carried numbers the basis keeps. */
export declare const MAX_BASIS_NUMBERS = 50000;
/** How many column-derived values (sums, ratios, differences, complements) the basis keeps. */
export declare const MAX_DERIVED = 50000;
/** The normalized numbers the answer writes as figures (rule 1). */
export declare function figureNumbersOf(answer: string): ReadonlySet<string>;
/** One carried number, and where it was. */
interface Carried {
    readonly x: number;
    readonly at: string;
    /** New-dial metadata, read before Number conversion; absent for legacy folds. */
    readonly roundingSource?: {
        readonly spelling?: string;
        readonly allowed: boolean;
    };
    /** The field it sat under, when it sat under one. */
    readonly key?: string;
    /**
     * Read off a scientific spelling in text under `decimalRounding`
     * (`1.12e-02`): a source for the exact decimal rule only. The figures
     * dial's own derivations compare doubles and never see it.
     */
    readonly decimalOnly?: true;
}
/** One reconstructed value. */
interface Derived {
    readonly x: number;
    readonly derivation: FigureDerivation;
    readonly from: string;
}
/** What the results carry, folded for the derivation question. */
export interface FigureBasis {
    readonly carried: readonly Carried[];
    readonly derived: readonly Derived[];
    /** True when a bound cut the fold — some numbers were never asked about. */
    readonly truncated: boolean;
}
/**
 * Fold every `role: 'tool'` message in `history` (the same messages, read the
 * same way, as the evidence corpus — `evidenceIndex.ts` · `readResult` over
 * `lib/toolBytes.ts` · `toolBytesOf`) into the numbers they carry and the
 * column derivations over their lists.
 */
export declare function figureBasisOf(history: readonly LLMMessage[], deriveColumns?: boolean, roundingShapes?: readonly EvidenceShape[]): FigureBasis;
/** What the gate is handed under the dial: built once per judgement. */
export interface FigureCheck {
    /** The normalized numbers the answer writes as figures (rule 1). */
    readonly numbers: ReadonlySet<string>;
    /** Opt-in unitless decimal rounding, using the written precision. */
    readonly explainDecimal?: (value: string) => {
        readonly derivation: 'rounded';
        readonly from: string;
    } | undefined;
    /** The derivation question over the results' numbers (rule 2). */
    readonly explain: (value: string) => {
        readonly derivation: FigureDerivation;
        readonly from: string;
    } | undefined;
}
/**
 * The gate's numeric input for one judgement — the answer's figures and the
 * results' basis. This module loads through `import()` under the dial only
 * (`stages/route.ts` · `loadFigures`), so a plain agent's graph never carries it.
 */
export declare function figureCheckOf(answer: string, history: readonly LLMMessage[], options?: {
    readonly figures: boolean;
    readonly decimalRounding?: boolean;
    readonly shapes?: readonly EvidenceShape[];
}): FigureCheck;
/** A plain decimal may round ONE carried number, never a column derivation. */
export declare function explainRoundedDecimal(value: string, basis: FigureBasis): {
    readonly derivation: 'rounded';
    readonly from: string;
} | undefined;
/**
 * Is `value` (a normalized number from the answer) a declared derivation of
 * the numbers in `basis`? The first derivation found, or `undefined`. Order:
 * rounded, unit-scale, then the column derivations (sum, ratio, difference,
 * complement) — each also unit-scaled for a sum.
 */
export declare function explainFigure(value: string, basis: FigureBasis): {
    readonly derivation: FigureDerivation;
    readonly from: string;
} | undefined;
/**
 * WHO says the late line — the library, not the person — in the exact words
 * the time line measured (`arguments/serve.ts` · `TIME_LINE_SOURCE`: an
 * unmarked request-only `user` line drew "You're right… I apologize" on 37 of
 * 37 answers). Both are the ONE copy in the authorship registry
 * (`lib/saidByPerson.ts`, a zero-import leaf — so this folder still never
 * loads the time layer's module graph), which is what makes `isSaidByPerson`
 * false for this line (G17).
 */
export { LIBRARY_NOTE_OPENING };
/**
 * The library's conclusion about the numbers it flagged under the figures
 * dial, as ONE line for the end of the revision request. `undefined` when no
 * flagged value is a number (an identifier is not a figure; its correction
 * is the instruction alone).
 *
 * Why a late line and not one more clause in the instruction: the instruction
 * sits in the system prompt, the top of a long context; the measured failure
 * of a served fact is recency (a library fact served late moved a bench from
 * 74 to 20 of 80), so the conclusion goes where the model decides. Worded as
 * the framework's finding — never as the person's correction, which a model
 * thanks and apologises to. It names the draft's own flagged numbers, which
 * the instruction already quotes, and tells the model not to state them.
 */
export declare function figuresConclusionLine(values: readonly UnsupportedValue[]): string | undefined;
