agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
100 lines • 5.66 kB
TypeScript
/**
* The disposition ledger's run lifecycle — registration, the dev canary,
* and nothing else.
*
* Pattern: two small functions bracketing a run; the ledger stays the one
* accumulator, this file only decides WHO is registered and runs
* the canary.
* Role: a check is registered exactly when its preconditions exist on
* THIS agent (wire: always — every run calls the model;
* compose-invariant: a mount kernel is configured; dangling: at
* least one tool declared `argumentsFrom`, which arms BOTH the
* compose-seam dangling-reference check and the choice-seam
* unsupported-argument check off the same declaration;
* empty-lookup: that same declaration AND the operator's
* `noticeEmptyLookups` dial — two halves, because an advisory that
* armed itself off a declaration made for something else would not
* be opt-in at all; column-types: `Tool.resultColumns` AND the
* operator's `checkColumnTypes` dial off `'off'` — the same two
* halves, arming BOTH `column-type-mismatch` and `missing-column`
* off the one declaration; prior-turn-evidence: the operator's
* `noticePriorTurnEvidence` dial AND an armed evidence gate, the
* same two halves — the gate is what decides which tokens in an
* answer are values at all, so without it there is nothing whose
* provenance could be reported).
* Registration is what makes silence auditable — an unregistered
* check is honest
* absence, a registered one that never notes is the wiring rot
* `assertAlive` exists to name.
*
* THE CANARY (dev posture): each registered check's PURE function is run
* once against a synthetic, deliberately contradictory fixture. A check
* that cannot catch its own canary is dead — it runs but cannot fire —
* which is theorem (ii); theorem (i), the unhooked pipeline, is what the
* real per-encounter notes prove. Canary findings never surface as events
* and never touch the real counts (`noteSynthetic` quarantine).
*/
import { type DispositionLedger } from './ledger.js';
export type IntegrityPosture = 'observe' | 'dev';
/** Which checks this agent's configuration makes applicable. */
export interface IntegrityChecksPresent {
readonly wire: boolean;
readonly composeInvariant: boolean;
/**
* At least one tool declared `Tool.argumentsFrom`. ONE FLAG, TWO CHECKS
* (9.63.0): the same declaration arms `dangling-reference` at the compose
* seam and `unsupported-argument` at the choice seam — one asks whether the
* ground is still in reach while the tool is offered, the other whether the
* value the model chose came from that ground when it was called. They are
* not separated here because nothing can arm one without arming the other.
* "At least one tool" means the FULL declared catalog (9.72.0): a skill-
* carried tool's declaration counts even though the tool reaches the model
* only after its skill activates — the declaration is known at build, and
* the harvest in `Agent.buildChart` reads the whole catalog, not just the
* static registry.
*/
readonly dangling: boolean;
/** A `.claims()` contract is declared (9.61.0). */
readonly claim?: boolean;
/**
* The write seam's `empty-lookup` notice (9.77.0) — armed only when BOTH
* halves are true: the operator turned `noticeEmptyLookups` on AND at least
* one tool declared `argumentsFrom`. Deliberately NOT armed by the
* declaration alone, unlike its two siblings: this check would otherwise
* start filing advisories in every app that already declares
* `argumentsFrom` for the other two, and an absent dial must leave a run
* byte-identical. Absent → a registered `not-applicable` ROW, never
* silence.
*/
readonly emptyLookup?: boolean;
/**
* The write seam's COLUMN-TYPE CONTRACT (9.78.0) — armed only when BOTH
* halves are true: the operator set `checkColumnTypes` to something other
* than `'off'` AND at least one tool declared `resultColumns`. The same
* two-halves law as `empty-lookup`, for the same reason: a declaration is
* a promise a consumer may already be reading for its own purposes, and
* arming a boundary check off it alone would make an absent dial change a
* run's bytes. ONE FLAG, TWO CHECKS — `column-type-mismatch` and
* `missing-column` are the same declaration read two ways, and nothing can
* arm one without arming the other.
*/
readonly columnTypes?: boolean;
/**
* The claim seam's `prior-turn-evidence` notice (9.83.0) — armed only when
* BOTH halves are true: the operator turned `noticePriorTurnEvidence` on
* AND the agent armed the evidence gate
* (`.namesAndNumbersFromEvidence()`). The same two-halves law as its two
* write-seam siblings, and here the second half is not merely a policy
* choice: the gate owns the extractor that decides which tokens in an
* answer are DATA, so with no gate there is no value whose provenance
* could be read. Absent → a registered `not-applicable` ROW, never
* silence.
*/
readonly priorTurnEvidence?: boolean;
}
/**
* Start one run's ledger: register the present checks and, in dev posture,
* prove each can still catch its own synthetic defect.
*/
export declare function beginIntegrityRun(present: IntegrityChecksPresent, posture: IntegrityPosture): DispositionLedger;
//# sourceMappingURL=lifecycle.d.ts.map