UNPKG

agentfootprint

Version:

The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.

136 lines • 6.25 kB
/** * 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. */ /** Thrown by `assertAlive()` when a registered check demonstrably never ran. */ export class CheckerDeadError extends Error { check; seam; constructor(check, seam, detail) { super(`[integrity] checker_dead: '${check}' at the ${seam} seam ${detail} ` + `A green report from a check that never ran is decoration, not health — two shipped ` + `checks in this codebase decayed exactly this way. Re-wire the check or unregister it.`); this.name = 'CheckerDeadError'; this.check = check; this.seam = seam; } } /** * 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 function filedNothing(row) { return row.checked + row.notApplicable + row.unreachable === 0; } const keyOf = (check, seam) => `${seam}${check}`; // FOLD · the one owner of per-check disposition accounting — which checks ran, what they saw, and which filed nothing at all // consumers read this and never re-derive it: Agent.ts · `agentfootprint.integrity.disposition`, which files them as ONE event; every later reader reads that event, not this accumulator // detached: yes — report() returns fresh POJO rows, safe for events, snapshots and recordings. /** Start an empty ledger. One per run; feed it from every seam adapter. */ export function dispositionLedger() { const rows = new Map(); const registered = new Map(); const rowFor = (check, seam) => { const k = keyOf(check, seam); let row = rows.get(k); if (row === undefined) { row = { checked: 0, findings: 0, notApplicable: 0, unreachable: 0, synthetic: 0, syntheticCaught: 0, }; rows.set(k, row); } return row; }; return { register(check, seam) { registered.set(keyOf(check, seam), { check, seam }); rowFor(check, seam); }, note(check, seam, disposition, at) { const row = rowFor(check, seam); if (disposition === 'checked-pass') row.checked += 1; else if (disposition === 'checked-fail') { row.checked += 1; row.findings += 1; if (at !== undefined) row.lastFiredAt = at; } else if (disposition === 'not-applicable') row.notApplicable += 1; else row.unreachable += 1; }, noteSynthetic(check, seam, event) { const row = rowFor(check, seam); if (event === 'minted') row.synthetic += 1; else row.syntheticCaught += 1; }, report() { return [...registered.values()].map(({ check, seam }) => { const r = rowFor(check, seam); return { check, seam, checked: r.checked, findings: r.findings, notApplicable: r.notApplicable, unreachable: r.unreachable, ...(r.lastFiredAt !== undefined && { lastFiredAt: r.lastFiredAt }), synthetic: r.synthetic, }; }); }, assertAlive(opts) { for (const { check, seam } of registered.values()) { const r = rowFor(check, seam); // NO CANARY MASK. A minted canary proves the pure FUNCTION still // catches its own defect (theorem ii); it says nothing about whether // the PIPELINE ever called it — `beginIntegrityRun` mints by calling // the function directly. Masking (i) with it made the wiring-rot // alarm — the whole reason this ledger exists — unable to fire in // any dev-posture run, which is the decay it was written to catch. if (opts?.workExisted === true && filedNothing(r)) { throw new CheckerDeadError(check, seam, `filed no disposition at all in a run where work existed — not pass, not fail, ` + `not not-applicable, not unreachable.`); } if (r.synthetic > 0 && r.syntheticCaught < r.synthetic) { throw new CheckerDeadError(check, seam, `was handed ${String(r.synthetic)} synthetic contradiction(s) and caught ` + `${String(r.syntheticCaught)}.`); } } }, }; } //# sourceMappingURL=ledger.js.map