agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
69 lines (68 loc) • 3.56 kB
TypeScript
/**
* The disposition ledger — nobody's silence goes uncounted.
*
* Pattern: small mutable accumulator behind a read-only report, the
* context-ledger ingestion shape (accumulate during, read after).
* Role: every Context Integrity check files one disposition per
* encounter here. The ledger's two jobs:
*
* 1. THE INVARIANT — for every check that was registered, an encounter
* count of zero is itself reportable. `assertAlive()` fails when a
* registered check saw work available and filed nothing at all —
* which is the wiring-rot failure mode ("the checker was unhooked and
* the suite stayed green"), distinct from a clean run (encounters
* with zero findings — healthy) and from a quiet run (no applicable
* work — also healthy, and stated as such).
*
* 2. THE CANARY — in dev posture, a run mints one deliberately
* contradictory synthetic encounter per registered check at start.
* A checker that cannot catch its own canary is dead, and the run
* says so by name instead of shipping a green report. Synthetic
* findings are counted apart and never touch the real numbers.
*
* Everything here is plain data; `report()` returns fresh POJOs safe for
* events, snapshots, and recordings.
*/
import type { CheckReport, Disposition, IntegritySeam } from './types.js';
/** Thrown by `assertAlive()` when a registered check demonstrably never ran. */
export declare class CheckerDeadError extends Error {
readonly check: string;
readonly seam: IntegritySeam;
constructor(check: string, seam: IntegritySeam, detail: string);
}
/**
* Did this row file NOTHING — not a pass, a fail, a not-applicable or an
* unreachable? The first half of theorem (i) below, and the ONE owner of it:
* `assertAlive` throws on it when work existed, and a reader of the
* `integrity.disposition` rows (an exporter deciding which rows are worth a
* reader's attention) asks the same question of the same counts.
*/
export declare function filedNothing(row: Pick<CheckReport, 'checked' | 'notApplicable' | 'unreachable'>): boolean;
export interface DispositionLedger {
/** Declare a check exists at a seam. Registration is what makes silence auditable. */
register(check: string, seam: IntegritySeam): void;
/** File one encounter's disposition. `at` = epoch ms of a `checked-fail`. */
note(check: string, seam: IntegritySeam, disposition: Disposition, at?: number): void;
/**
* File the dev-posture canary pair: the mint (a synthetic contradictory
* encounter was created) and, when the check catches it, the catch.
* Synthetic counts never touch the real ones.
*/
noteSynthetic(check: string, seam: IntegritySeam, event: 'minted' | 'caught'): void;
/** Fresh POJO rows, one per registered (check, seam). */
report(): readonly CheckReport[];
/**
* The T9 theorems, both:
* (i) a registered check with real work available (`checked + findings +
* notApplicable + unreachable === 0` while the caller states work
* existed) is dead — the wiring rotted;
* (ii) in dev posture, a check whose canary was minted and never caught
* is dead — it runs but cannot fire.
* Throws {@link CheckerDeadError} naming the first dead check.
*/
assertAlive(opts?: {
workExisted?: boolean;
}): void;
}
/** Start an empty ledger. One per run; feed it from every seam adapter. */
export declare function dispositionLedger(): DispositionLedger;