Field notes · For both · 27 August 2026 · 8 min

How to prove your AI didn't hallucinate a wire transfer

The morning after: a $50,000 transfer, an agent that says it was told to, and a customer who says it wasn't. What a record has to contain to settle it — and what most stacks actually have.

It is 9:40 on a Tuesday. Finance has a $50,000 outbound wire from yesterday afternoon that nobody remembers approving. The agent that handles vendor payments says it was instructed to. The customer whose account it left says it was not. Your CEO wants to know, by lunch, which of them is right — and your general counsel wants to know what you can prove.

This note works backwards from that morning. What does a record have to contain for the question to be settled in an hour rather than a month? And, more uncomfortably, what do most stacks actually have?

What “hallucinated a transfer” actually means

Three different failures hide under that phrase, and the record has to distinguish them:

  1. 01The agent invented the instruction. No human or upstream system asked for a transfer; the model generated a tool call from nothing.
  2. 02The agent misread a real instruction. Somebody asked for $5,000 and it sent $50,000, or asked for a different payee.
  3. 03The instruction was real and the agent was right. The customer is mistaken, or is not being straight.

A stack that cannot tell these apart the morning after will end up refunding the money in all three cases, because it cannot prove the third.

What the record has to hold

Here is the sequence as it would sit on a chain, for a version of this where the control worked. Sequence numbers, the action, what was fingerprinted, and the seal.

SeqWhat happenedRecorded asSeal
4180pulled the credit filetool_call · fingerprint 9c1e…
4181declined — debt-to-income 51%decision · fingerprint 44a0…
4182asked to wire $50,000tool_call · policy: above $10,000 a person signswaiting
4183approved by r.mehta@ (session 7f…)approval · from authenticated session
4184wire_transfer executed · ref TXN-88213tool_result · fingerprint e07b…sealed #4184 · TSA 14:32:07Z

Six things in that table settle the Tuesday question, and each is a property a stack either has or does not:

  • The input the agent acted on, fingerprinted. Not the full payload — a hash of it, so the instruction can be matched against what the customer says they sent without the record itself holding their data. If the fingerprint of “wire $5,000 to Acme” does not match what the agent recorded at 4182, failure two. If nothing upstream of 4182 carries an instruction at all, failure one.
  • The tool call as the model emitted it. Function name, arguments, and the model’s own call id — recorded before execution, not reconstructed from the result.
  • The policy verdict, before execution. “Above $10,000 a person signs first” ran at 4182 and the agent stopped. If your stack has no row like this, the answer to “why did nobody stop it” is that nothing could have.
  • A named human on the approval, from the session. 4183 is r.mehta@, from an authenticated session, not from a field the agent filled in. If the approval is svc-agent-prod, you have a service account approving its own wire.
  • The result, with the external reference. TXN-88213 ties the chain to the bank’s own record. Two independent systems agreeing is what “proof” means in practice.
  • A seal with an independent timestamp. The chain head at 4184 was signed and countersigned by an RFC 3161 authority at 14:32:07Z. That is what stops “you could have written this last night” from being a reasonable objection.

What most stacks have instead

We have looked at a lot of these the morning after. The usual inventory:

  • The model provider’s request log — full payloads, a provider-controlled retention window (see OpenAI’s published endpoint policy), and no record of whether the tool call was executed, only that it was emitted.
  • An observability trace — good for the “why”, mutable, and typically expired if the dispute surfaces at month-end reconciliation.
  • The bank’s record — TXN-88213, which proves the money moved and nothing about why.
  • A Slack thread from that afternoon in which somebody says “approved 👍” and nobody can say whether that was this wire.

Nothing there is tamper-evident, nothing was checked before execution, and the one human signal is a thumbs-up emoji. In that stack the honest answer to the CEO is “we cannot prove it either way”, and the refund goes out.

The uncomfortable part: it was probably failure three

In the disputes we have seen, the agent was usually right — the instruction was real, the amount was correct, and the customer had forgotten or was testing the process. A company with the record above keeps the $50,000 and the customer. A company without it refunds, and has taught the customer that disputes work. The cost of not being able to prove your agent was right is paid most often on the days it was.

What to do before Tuesday

  1. 01Name the material actions. Wires, refunds above a figure, anything that touches a person’s data or a decision about them.
  2. 02Put a pre-execution check in front of each, with the threshold in one English sentence and the approver’s identity from the session.
  3. 03Record the input fingerprint, the tool call as emitted, the verdict, the approval and the result as five entries in order, on a chain.
  4. 04Seal the head on a schedule and get it countersigned by a timestamp authority you do not run.
  5. 05Export it once and verify it offline yourself, so you know the answer to “can you prove it” before anyone asks.

The demo at /app/demo is this exact sequence — 4182 waits, a person signs, the chain seals — and you can try to edit a row and watch the verifier fail on it. The five-entry shape is specified field by field at /ai-agent-audit-trail.

See it on a real chain

The evidence path described above is running on our own account. Every ad-account change made by the agents behind Admiral, our paid-ads product, is recorded on the chain admiral/prod — actions on the chain, seals countersigned, and the sealed-through sequence are read live at /trust, not written into the page.

Start

Keep the traces. Add the record.

Two lines in one agent, free while you evaluate — and it reads the spans you already emit.

  • No card to start
  • Nothing is blocked until you say so
  • Your proof stays yours if you leave