In plain English: the AI drafts an answer, plain code checks it and verifies the citations, and if the check fails it refuses instead of guessing. This is a small working example of that idea.
Recorded runs and live tamper bench · Working rules · More tools
Companion code for The Careful Machine: Engineering AI Systems That Cannot Certify Themselves (Miguel Sanchez, forthcoming, 2026). One question is answered twice:
Who has this account paid most often this quarter, and are any of those counterparties new?
src/fused/is the chapter-1 machine, deliberately ordinary: a capped read nobody owns, a ranking narrated as the quarter, novelty answered from the window. Its tests demonstrate the failure: the confident wrong answers being produced while every component works as documented.src/careful/is the same question through the book's spine: contract and gate with the two standings (ch. 3-4), capability registry (ch. 5), scope intersection (ch. 6), action classifier and interception (ch. 12), evidence with coverage (ch. 7-8), derived results (ch. 9), the claim turnstile (ch. 11), the routed no (ch. 13), and replay (ch. 17).
This is a demonstration, not a framework: hold src/fused and src/careful
in your head in an afternoon. src/serve.ts and src/web are the local demo
UI, deliberately kept out of that claim - the page is the exhibit, not the
argument. The "model" is a deterministic stub that emits proposals,
including hostile and over-confident ones; the architecture is what decides.
npm install # dev-only: typescript + @types/node
npm run demo # both machines answer the question; ground truth printed first
npm run serve # local web UI at http://127.0.0.1:8787 (see below for the live model)
npm test # node's built-in runner; no runtime dependencies
npm run typecheck # the compile-time gates live here tooNode 22.6+ (uses --experimental-strip-types; the source is erasable-syntax
TypeScript, so node runs it directly).
Each core test is a book claim made executable:
| Test | Book claim |
|---|---|
| capped read truncates; narrated top payee wrong | ch. 1: the failure is in the empty space between working components |
| window read calls an old counterparty new | ch. 1/5: nothing owns the question being answered |
type gate: ExecutionRecord takes a CertId, never a ProposalId |
ch. 2: executions execute certifications |
requester-confirmed unmintable except via the requester record |
ch. 3: standing integrity; policy never certifies meaning |
| partial-read ranking struck unqualified; qualified form certified with subset named | ch. 8/11: claims carry the coverage they can support |
no-occurrence fails on incomplete read and on unknown population |
ch. 8: unknown is not zero |
| a complete read certifies the unqualified ranking, naming the true top payee | ch. 8/11: coverage is what a claim may lean on |
novelty ask lands cannot-execute with nearest-serviceable facts |
ch. 5: capability is a record; honest refusal beats invented ability |
| a least-frequent ask certifies nothing, end to end | ch. 5: the nearest registered operation is not the one asked for |
a presence ask certifies no ranking claim, and ranOperations names what ran |
ch. 5/12: what the registry selected is what executes |
| a subject no grant covers is a routed no, not a crash | ch. 13: outside-authority is an answer, with the scope owner named |
| every read is intercepted and logged under the certification it ran under | ch. 12: reads are classified and recorded, not assumed |
| a certified claim names the window and subject that were actually read | ch. 9/11: a claim carries its own provenance, not a house style |
| hostile "search every account" widens the proposal, not the scope | ch. 6: authority is an intersection the proposal cannot move |
| disposition derives from records only, by fixed precedence | ch. 13: the no is routed, not narrated |
| renderer cannot leak a struck claim | ch. 11: narration is constrained to the certified set |
| hostile drafts are rejected with the ground named, never repaired | ch. 3-4: the interpreter proposes; validation decides |
| the answer record replays with every reference resolving | ch. 17: an answer is a join over records |
| the package declares no runtime dependencies | the zero-dependency decision below, checked rather than asserted |
Every test in the suite backs a row above; the largest block is the
interpreter's hostile-draft table (test/interpreter.test.ts), one test per
draft. CLAIMS.md maps every claim on this page to the test that enforces
it, and names the few that no test can. All identifiers and numbers are
invented and illustrative.
The core repo makes zero model calls; demo:live swaps the interpreter stub
for a real one. The model drafts the RequestContract through a forced tool
schema, the draft is validated mechanically (malformed drafts are rejected,
never repaired), ids are minted locally, and the actual model identity lands
in proposedBy and the AnswerRecord. Every other station is byte-for-byte
the same code the stub runs through, which is the demonstration: the proposer
got smarter and less predictable; the guarantees did not move.
ANTHROPIC_API_KEY=sk-... npm run demo:live # hostile question, policy-admitted
ANTHROPIC_API_KEY=sk-... npm run demo:live -- --confirmed # same, requester-confirmed
ANTHROPIC_API_KEY=sk-... npm run demo:live -- "your own question"ANTHROPIC_MODEL overrides the default (claude-sonnet-5);
ANTHROPIC_BASE_URL is honoured. The key is read from the environment for
that run's requests and never stored or printed. npm test stays fully
offline.
The web UI defaults to live mode when the key is set (an "Offline stub" toggle sits next to Run). In live mode the SAME model runs on both sides: as the fused machine it is handed the question plus every row for the account, history included, and one unvalidated generation ships as the answer; as the careful machine's interpreter it drafts the reading only, and plain code does the rest. The fight is deliberately fair: nothing is withheld from the fused side, so any failure there is the generation's own, and the cap toggle re-imposes the silent 500-row page one on BOTH machines at once. Nothing is sent on page load; a run happens only when you press Run or pick a scenario, and each live run makes two small API calls (one per machine), or three when a draft is rejected and the interpreter takes its one fresh try. The "Model exchange" panel on every result shows both calls verbatim: what was sent (system prompts, question, data, tool schemas), what came back, and what each side was allowed to do with it. The key stays in the server process; the browser only ever sees the model's output. With no key, both machines run offline: the fused side is the original no-AI pipeline and the interpreter is the deterministic stub.
No LLM calls outside the one opt-in interpreter above, no persistence beyond in-memory records, no config system, no CLI polish, no framework extraction. If a change makes this less readable in one sitting, it is the wrong change.
- Reject, never repair. A malformed draft is refused with the reason named. Repairing it would launder the malformation into the record, and the record is the product.
- The model never runs inside the verifier. Drafts are input; plain code decides what they become. That boundary is what makes the recorded runs replayable and the tamper bench honest.
- Zero runtime dependencies. Every guarantee here is carried by code a reader can finish; a dependency would move part of the argument outside the afternoon.