/**
 * context-ledger/types.ts — the bookkeeper's vocabulary.
 *
 * WHY THIS LIBRARY EXISTS: context engineering fails in one predictable
 * direction — "include everything to be safe". Every injection, skill and
 * tool schema costs tokens EVERY turn, whether or not it ever mattered. The
 * ledger keeps score across runs: which pieces EARNED their tokens (were
 * called, activated, or sat on the answer's dependency slice) and which
 * never did. Its rows feed the L2 gates (gatedTools predicate, skill-graph
 * EntryScorer, injection demotion) so future turns include less — the
 * mechanism that makes lesser models viable.
 *
 * HONESTY (the discipline everything here inherits):
 * - Every counter is a STRUCTURAL fact from the run's own commit log —
 *   offers are recorded commits, uses are recorded calls/activations/slice
 *   membership. Nothing is inferred from model internals. Under an agent's
 *   `redact`, a final value the log keeps out is read from the run's live
 *   end state, and a kind nothing can answer for is left UNMETERED for the
 *   run ({@link RecordedRun.unmetered}) — a placeholder never counts as
 *   "not used".
 * - Each kind's `used` definition is explicit ({@link UsedSignal}) and rides
 *   every count — a consumer can always see WHY a piece counted as used.
 * - Slice membership is slot-granular (all injections sharing a slot share
 *   its write) — the signal name says so: `'answer-slice(slot)'`.
 * - `approxTokens*` is a serialized-length estimate (JSON chars ÷ 4), named
 *   so nobody mistakes it for a tokenizer count.
 * - The ledger never claims causation. `earnRate` is bookkeeping;
 *   ablation (context-bisect) can upgrade individual claims when you pay
 *   for it.
 */
import type { ValueBasis } from 'foottrace';
/** What kind of context piece a row tracks. Skills are injections with
 *  flavor 'skill' — split out because their `used` signal differs. */
export type PieceKind = 'injection' | 'skill' | 'tool';
/**
 * The per-kind structural definition of "used" — explicit, never blended:
 * - `'tool-called'`        — an assistant message actually called the tool.
 * - `'skill-activated'`    — the run activated the skill
 *                            (`activatedInjectionIds`).
 * - `'answer-slice(slot)'` — the injection's SLOT write sits on the final
 *                            answer's backward dependency slice
 *                            (slot-granular by construction).
 */
export type UsedSignal = 'tool-called' | 'skill-activated' | 'answer-slice(slot)';
/** One context piece's accumulated bookkeeping across recorded runs. */
export interface LedgerRow {
    /** Injection/skill id, or tool name. Unique within its kind. */
    readonly id: string;
    readonly kind: PieceKind;
    /** Offer events — once per iteration the piece was in context, across runs. */
    readonly offered: number;
    /** Serialized-length token ESTIMATE spent on those offers (chars ÷ 4). */
    readonly approxTokensSpent: number;
    /** Structural uses (per-kind definition — see breakdown in usedVia). */
    readonly used: number;
    /** Which signal(s) produced the `used` count, and how many each. */
    readonly usedVia: Readonly<Partial<Record<UsedSignal, number>>>;
    /** Distinct recorded runs in which the piece was offered at least once. */
    readonly runsSeen: number;
    /**
     * Outcome labels of runs where the piece was OFFERED (label → run count).
     * Labels are consumer-supplied via {@link ContextLedger.recordOutcome}
     * (thumbs, eval scores bucketed by the consumer, triage verdicts).
     * Presence-correlation bookkeeping — NOT a causal claim.
     */
    readonly outcomes: Readonly<Record<string, number>>;
    /** used ÷ offered (0 when never offered). THE headline number. */
    readonly earnRate: number;
}
/** What `recordRun` extracted from one run — returned for inspection/tests. */
export interface RecordedRun {
    /** Handle for {@link ContextLedger.recordOutcome}. */
    readonly runRef: string;
    /** Piece ids offered in this run (kind-qualified internal keys). */
    readonly offeredPieces: readonly string[];
    /** True when the answer slice could be computed (finalContent + reads). */
    readonly sliceAvailable: boolean;
    /**
     * The reason codes behind any NON-exact answer the ledger counted from, per
     * state key — the union of footprintjs's `commitValueAtWithBasis` /
     * `findLastWriterWithBasis` `basis` over every read of that key in this run
     * (`'nested-rows'`, `'from-initial-state'`, `'redacted'`, `'deleted'`,
     * `'never-written'`). Each code's sentence is `HONESTY_CODES[code]` on
     * `foottrace`. ABSENT when every answer was exact.
     */
    readonly basis?: Readonly<Record<string, readonly ValueBasis[]>>;
    /**
     * The kinds this run was NOT metered for: a read their offers or uses come
     * from rests on a redaction (`basis` names the key as `'redacted'`) that no
     * live state answered — an agent's `redact` kept it out of the record and
     * the source was a snapshot, or it is a value per call (what each call was
     * offered lives only in the log). Neither the kind's offers nor its uses are
     * counted for this run, so a gate never demotes a piece on uses the record
     * could not show. ABSENT when every kind was metered (always, without a policy).
     */
    readonly unmetered?: readonly PieceKind[];
}
/** JSON-safe persisted shape (consumer owns storage). */
export interface LedgerJSON {
    readonly version: 1;
    readonly rows: readonly LedgerRow[];
    readonly runsRecorded: number;
}
/** Minimal runner surface the ledger reads (any agentfootprint Runner). */
export interface RunnerLike {
    getLastSnapshot(): unknown;
}
export interface ContextLedger {
    /**
     * Ingest one FINISHED run: walk its commit log for offers (activeInjections
     * / dynamicToolSchemas per iteration), uses (assistant tool calls,
     * activatedInjectionIds, the final answer's dependency slice), and
     * accumulate. Accepts a runner or a snapshot. A runner of this library is
     * read LIVE (its live snapshot and end state — never its served record);
     * any other runner through `getLastSnapshot()`.
     */
    recordRun(source: RunnerLike | unknown): RecordedRun | undefined;
    /**
     * Label a recorded run's outcome ('good'/'bad'/any consumer label —
     * thumbs, bucketed eval score, triage verdict). Defaults to the most
     * recently recorded run. Increments the label for every piece OFFERED in
     * that run.
     */
    recordOutcome(label: string, runRef?: string): boolean;
    /** All rows, worst earnRate first (the review order that matters). */
    rows(): readonly LedgerRow[];
    /** One row (by kind + id). */
    row(kind: PieceKind, id: string): LedgerRow | undefined;
    /** JSON-safe export (consumer persists). */
    exportJSON(): LedgerJSON;
    /** Merge a previously exported ledger in (counts add). */
    importJSON(json: LedgerJSON): void;
}
//# sourceMappingURL=types.d.ts.map