A check that can't fail is just a stamp.

So here is the only question worth asking about any verification system: can it go red? For the AER-1 receipt check, the answer is not a promise. It is a public record, including the time the check passed something it should not have, and the spec change that failure forced.

The direct answer

Yes, this check fails in public, on the record, and you can run every failure yourself. An outside reviewer swapped a receipt id onto a record it did not belong to: the standalone check passed it, the binding check caught it, and the failure rewrote the spec. Details and commands below.

Published October 17, 2026. Written against draft-zambo-aer1-23, the current revision of the AER-1 Internet-Draft. Commands and outputs measured with kit 1.5.4, aer1-verify 0.2.7.

The objection, in a working builder's words

A founder who runs his companies on an AI agent, unsupervised, put the objection to Zambo in one line: "The part I'd want proved is that the check could fail." He was not asking whether the math is strong. He was asking whether the green light means anything. A verifier that has never been seen to fail, on anything, is decoration: it tells you the system ran, not that the record held.

He is right, and the honest answer has two parts. First, the failure modes are real, specific, and reproducible: they are printed below with the exact commands, not described in adjectives. Second, the strongest evidence is not a staged failure. It is the time the check was beaten in the open, by an outsider, and the beating changed the specification.

Control one: the id swap

The setup. Section 3 of the draft publishes an example receipt, id 130da435-e157-498e-af90-605866a86a27, so anyone can test against the same artifact. Its committed payload is five fields: caller, output, receipt_schema_version, side_effects, and tool, sealed by the output digest sha256:0492c18e09059aa2e30ba0864f6aada2ef08475a5b35944cbf2a9ce46d12b9f1 over 520 canonical bytes. The receipt id is not one of the committed fields. It is a label that sits outside the payload.

The control. Gigawatt, an independent reviewer on The Colony, proposed two negative controls against that example receipt and predicted both outcomes in advance: a one-byte mutation of the canonical bytes fails verification, as specified, and substituting another receipt's id for the example's id is not detected by the output commitment. He took the id of a second live receipt, 42fc3298-b1e7-4087-bb1c-f80ef9f12c7c, and presented the example's genuine bytes under the donor's id. Both controls were run with the published tooling, and the outcomes were published. He was right on both counts.

Why the loose check passes it. Run the swapped artifact through the kit checker with no binding option and every digest check passes, because nothing about the bytes is wrong. The record is genuine; the pairing of id to record is the lie, and a digest over the payload has nothing to say about a label outside the payload. Under the old reading, a green verdict was the whole story. Under draft-zambo-aer1-22, it is not: Section 6 states that when a verifier performs neither binding comparison, it MUST report the id as unverified and MUST NOT present the verification as covering the id. The checker now prints that state at the top of every run:

$ python3 aer1-verifier/aer1_verify.py swapped.json
aer1-verify 0.2.7
receipt: 42fc3298-b1e7-4087-bb1c-f80ef9f12c7c
id state: unverified
  [PASS] sha256(canonical_bytes) equals output_hash
  [PASS] id binding: id_state -- id_state=unverified: the id is a label outside the commitment; no expected id or resolved record supplied, so verification does not cover the id
VERDICT: PASS: all checks passed, receipt intact
(exit code 0; the other 13 checks trimmed, run it to see all 15)

Read that output the way Section 6 forces you to: the bytes verify, and the id is explicitly not covered. The pass is real and narrow at the same time.

Bind the id, and it fails. There are two ways to bind. Give the checker the id you expected from a source independent of the presented record:

$ python3 aer1-verifier/aer1_verify.py swapped.json --expected-id 130da435-e157-498e-af90-605866a86a27
aer1-verify 0.2.7
receipt: 42fc3298-b1e7-4087-bb1c-f80ef9f12c7c
id state: mismatch
  [FAIL] id binding: id_state -- id_state=mismatch: artifact id '42fc3298-b1e7-4087-bb1c-f80ef9f12c7c' does not match the externally supplied expected id '130da435-e157-498e-af90-605866a86a27'
VERDICT: FAIL: 1 check(s) failed (id binding: id_state), do not trust this receipt
(exit code 1; passing checks trimmed)

Or resolve the claimed id under Section 9 and compare what it resolves to. The donor id resolves to the donor's own record, whose committed digest is sha256:2c0ab1e3336ffa82c12eaedd9b5cc4931f7c442e3da26912dcfe30d21c62a989, not the artifact's:

$ python3 aer1-verifier/aer1_verify.py swapped.json --resolved-record donor-record.json
aer1-verify 0.2.7
receipt: 42fc3298-b1e7-4087-bb1c-f80ef9f12c7c
id state: mismatch
  [FAIL] id binding: id_state -- id_state=mismatch: resolved record digest 'sha256:2c0ab1e3336ffa82c12eaedd9b5cc4931f7c442e3da26912dcfe30d21c62a989' disagrees with the artifact's committed digest 'sha256:0492c18e09059aa2e30ba0864f6aada2ef08475a5b35944cbf2a9ce46d12b9f1'
VERDICT: FAIL: 1 check(s) failed (id binding: id_state), do not trust this receipt
(exit code 1; passing checks trimmed)

The honest artifact still passes, bound. Run the genuine example receipt with its own expected id and the same checker reports id_state=verified-expected and VERDICT: PASS. Resolve it against its own record and it reports id_state=verified-resolved and VERDICT: PASS. Binding is not a trap that fails everything; it fails exactly the artifact whose id does not belong to its bytes.

What the failure changed. Draft-zambo-aer1-21 adopts the finding. Section 6 states the id-binding rule normatively, Section 13 describes the substitution case, and Section 18 credits Gigawatt for the controls. The five cases (unbound, bound by expectation, expectation mismatch, resolution agreement, resolution disagreement) ship in the kit as aer-1/id-binding-vectors.json, pinned to the outcomes measured in that public run, so the failure can never quietly regress into a rubber stamp again.

Control two: break one step of a handover

The id swap attacks a single receipt. The second control attacks a chain. A Zambo handover gathers the receipts of a multi-step job into one record, closed by a summary receipt that commits each step's output digest under a single root. Change any one step's saved result and its digest no longer recomputes, so the chain check fails: one red step turns the whole verification red.

The worked record is public: handover bd7e5325, a five-step delivery record from October 16, 2026, still open for anyone to inspect. Its summary receipt, bdc7422b, commits the five step digests under root 8a45f08695599fa3bc5cc231464909801261ed09c421706e472c325b014df825, and its record states the check scope plainly: saved receipt bytes only, not work accuracy. Open the handover and use its Verify all: every step is rechecked against what was committed at close. The JSON twin shows the same structure the checker reads, step digests included.

To watch the failure itself, make the smallest possible break in the fixture from control one: change a single digit of the saved price inside the committed payload, from $84,456 to $84,457, and leave the commitment untouched:

$ python3 - <<'EOF'
import json, base64
d = json.load(open('aer-1/id-binding-vectors.json'))
v = {x['name']: x for x in d['vectors']}
r = v['id-alone-unverified']['receipt']
raw = base64.b64decode(r['canonical_bytes'])
r['canonical_bytes'] = base64.b64encode(raw.replace(b'84,456', b'84,457')).decode()
json.dump(r, open('/tmp/tampered.json', 'w'), indent=2)
EOF
$ python3 aer1-verifier/aer1_verify.py /tmp/tampered.json
aer1-verify 0.2.7
receipt: 130da435-e157-498e-af90-605866a86a27
id state: unverified
  [FAIL] sha256(canonical_bytes) equals output_hash -- committed=sha256:0492c18e09059aa2e30ba0864f6aada2ef08475a5b35944cbf2a9ce46d12b9f1 recomputed=sha256:d0df4bc10af2098df50718a8e52389a7225589eae9b8f9acc85b69ba80c7d042
VERDICT: FAIL: 1 check(s) failed (sha256(canonical_bytes) equals output_hash), do not trust this receipt
(exit code 1; passing checks trimmed)

One digit, in a price nobody would dispute, and the receipt stops verifying. That is the same failure the handover chain produces when a step is edited, and the same failure the break-the-receipt challenge invites you to attempt against the hash itself.

Run the whole control set yourself

Everything above reproduces from the public kit. Clone it, pull the pinned vectors out of the file the kit ships, and run the four commands:

$ git clone https://gitlab.com/rambozambodotdev/zambo.git
$ cd zambo
$ python3 -c "
import json
d = json.load(open('aer-1/id-binding-vectors.json'))
v = {x['name']: x for x in d['vectors']}
json.dump(v['id-alone-unverified']['receipt'], open('/tmp/fixture.json', 'w'))
json.dump(v['id-expected-mismatch']['receipt'], open('/tmp/swapped.json', 'w'))
json.dump(v['id-resolution-disagreement']['resolved_record'],
          open('/tmp/donor-record.json', 'w'))
"
$ python3 aer1-verifier/aer1_verify.py /tmp/fixture.json
  id state: unverified, VERDICT: PASS (the genuine bytes, id unbound)
$ python3 aer1-verifier/aer1_verify.py /tmp/swapped.json
  id state: unverified, VERDICT: PASS (the swap, still unbound)
$ python3 aer1-verifier/aer1_verify.py /tmp/swapped.json \
    --expected-id 130da435-e157-498e-af90-605866a86a27
  id state: mismatch, VERDICT: FAIL, exit code 1
$ python3 aer1-verifier/aer1_verify.py /tmp/swapped.json \
    --resolved-record /tmp/donor-record.json
  id state: mismatch, VERDICT: FAIL, exit code 1

The full outputs, all 15 checks per run, print locally. If your runs disagree with the outputs on this page, that disagreement is itself checkable evidence: the vectors, the checker, and this page are all public, and the kit is versioned (1.5.4, aer1-verify 0.2.7) so the comparison is exact.

What a failure proves, and what it does not

Keep both halves narrow, because narrow is what makes them worth anything:

  • A failed check proves the checker can say no, on a named check, for a stated reason, with the digests printed side by side. That is the whole answer to the objection that opened this page.
  • A passed check proves the saved result was not changed since it was saved, and, when the id is bound, that the id belongs to those bytes. It does not prove the original result was correct, complete, or the right work to have done. Correctness is a judgment you make against the checked record.
  • An unbound id is reported, not hidden. A verifier that follows draft-zambo-aer1-23 shows id_state: unverified rather than letting a green verdict imply coverage it did not perform.

The format is an open Internet-Draft, draft-zambo-aer1-23, precisely so this discipline does not depend on one vendor's checker: independent implementations run the same vectors, and an independent probe of a live receipt is written up in the WhiteMagic CPR cross-check.

Now run a live job and break it yourself

The fixture proves the checker fails on a published artifact. The live version takes a minute: the demo runs one real call and hands you its verifiable receipt. Check it at zambo.dev/verify/ and watch it pass. Then take the receipt into the kit checker, change one digit of the saved result the way control two does, and watch the same receipt fail. A check you have personally seen go red is a check whose green means something.

When the work matters, the receipt should not be a demo: calls through zambo.dev/mcp leave a verifiable receipt as they run, and a $0.99 Day Pass turns that on for 24 hours.

Questions, answered

Can a receipt check fail?

Yes, and this one does, in public. Change one digit inside a receipt's committed payload and the digest check fails. Present a receipt under another receipt's id and bind the id, by an expected id or by resolution, and the id check fails. Both failures are published as test vectors in the AER-1 kit, with the exact commands on this page, so anyone can reproduce them.

Did the AER-1 check ever pass something it should not have?

Yes, in a specific and now documented way. The receipt id sits outside the committed payload, so a standalone digest check on a receipt whose id had been swapped for another receipt's id passed: the bytes were genuine, the pairing was wrong, and nothing in the loose check compared the two. An outside reviewer, Gigawatt, ran that control in public and predicted the outcome in advance. Draft-zambo-aer1-21 adopts the finding: a verifier must report an unbound id as unverified, and binding the id makes the swapped receipt fail.

What happens when a receipt check fails?

The checker names the failed check and stops trusting the receipt. In the kit checker (aer1-verify 0.2.7) a payload edit fails the line "sha256(canonical_bytes) equals output_hash" with the committed and recomputed digests side by side, and a swapped id fails with id_state mismatch. The verdict line reads FAIL and the exit code is 1, so scripts and CI pipelines can gate on it.

Does a passing check prove the AI's answer was right?

No. A passing check proves the saved result was not changed since it was saved, and that the id presented with it is the id it was bound to. Whether the result itself is correct is a separate judgment, made against the checked record. Falsifiability cuts both ways: the check can fail, and what it certifies when it passes is stated narrowly on purpose.

How can I run the failure myself?

Clone the AER-1 kit from GitLab, extract the id-binding vectors, and run aer1_verify.py on them. The swapped receipt passes standalone, fails with --expected-id, and fails with --resolved-record against the donor's record. Every command and its real output is printed on this page, measured with kit 1.5.4 and aer1-verify 0.2.7 on October 17, 2026.