Tanilo x AER-1: A Two-Party Receipt Chain, Verified End to End

On 2026-10-08, Tanilo published a two-party receipt chain. An AER-1 execution receipt references a live Tanilo receipt by its canonical hash, and the full chain verifies end to end with each receipt checked independently. Two formats, one chain, zero trust-me steps. The invariant under test: binding without claim inheritance. A valid receipt proves the record was not changed. It never proves the premise was true.

Replay it yourself: Tanilo's half at TKCollective/tanilo-receipt-spec, pinned commit e1206d1a. Brennan's AER-1 half at aer1-interop/tanilo.

What was tested

The Tanilo half is one real receipt: a POST https://api.tanilo.io/v1/verify-facts made on 2026-10-08 at 04:47 UTC, asking for a contract_price_match check on an offer of USD 2.00 per call against a caller-supplied term of USD 1.00 per call. The result is contradicted. The receipt is signed with tanilo-2026-10-ed25519-7d885da9, and everything needed to verify it offline ships in the repo: the JWS object, the exact canonical bytes, the decoded payload, the published key set, and a test script.

The AER-1 half references that receipt with an evidence reference carrying three values: the canonical_sha256, the pinned raw URL, and the kid. The evidence-reference object itself (type, url, kid, relationship, description) is AER-1's; Tanilo's specification defines canonical_sha256 and kid, not that object. The full chain verifies end to end with each receipt checked under its own rules.

The three values that bind the chain

ValueRecomputed how
canonical_sha256
sha256-ca2fb84597076f9c8fac2d957a05bf21a11bd741e519879ff09ba78fd2305325
SHA-256 of the UTF-8 bytes of the RFC 8785 canonical form of the signed payload. The repo ships payload.canonical.bin, the exact 3,655 bytes, plus test_aer1_interop.py which recomputes the hash with an independent canonicalizer.
url
pinned raw URL of receipt.jws.json at commit e1206d1a
Fetched straight from the pinned commit, so the bytes the AER-1 receipt points at are the bytes everyone else checks.
kid
tanilo-2026-10-ed25519-7d885da9
Ed25519 key in Tanilo's published key set. The repo pins the key set as fetched on 2026-10-08, public keys only.

Verify the Tanilo receipt yourself

Needs Python 3 and Tanilo's published verifier, version 0.2.0 or later. No trust required beyond the key set you choose to use.

python3 -m pip install tanilo-receipt-verify==0.2.0
curl -sS -o receipt.json https://raw.githubusercontent.com/TKCollective/tanilo-receipt-spec/e1206d1a54ae23d7e0f6fed55cd85ca7149275e2/examples/interop/aer1/receipt.jws.json
curl -sS -o jwks.json https://tanilo.io/.well-known/jwks.json
python3 -c "import json; from tanilo_receipt_verify import verify; r = verify(json.load(open('receipt.json')), jwks_by_issuer={'https://tanilo.io/.well-known/jwks.json': json.load(open('jwks.json'))}, jwks_is_complete=True); print(r.status, r.canonical_sha256, [s['kid'] for s in r.signers])"

Expected output:

valid sha256-ca2fb84597076f9c8fac2d957a05bf21a11bd741e519879ff09ba78fd2305325 ['tanilo-2026-10-ed25519-7d885da9']

Then run python3 test_aer1_interop.py in the examples directory: it recomputes the canonical hash from the RFC, runs the signature check, and asserts the receipt's content. No network needed.

Binding without claim inheritance: the AER-1 receipt binds to the referenced Tanilo receipt, but the AER-1 receipt's validity never transfers to Tanilo's claim, and Tanilo's validity never transfers to the AER-1 execution. Each claim stands or falls on its own verification.

Chain-run verification: Joe's results, 2026-10-08

On 2026-10-08, Joe Krausz (Tanilo) ran the full chain on Tanilo's side and reported all green. His write-up: chain-run-2026-10-08.md.

  • aer1_verify.py on the AER-1 example: PASS, 15/15.
  • Evidence reference carries the canonical_sha256, pinned URL, and kid exactly. The Tanilo receipt at that URL recomputes to the same hash with an independent RFC 8785 canonicalizer, and the signature verifies with tanilo-receipt-verify 0.2.0 against Tanilo's live JWKS.
  • Scenario lines up: contradicted / halt on Tanilo's side, a held call on the AER-1 side, timestamped after Tanilo's receipt.

Anchor proof: GOAT mainnet

The interop receipt was anchored on GOAT mainnet in the 2026-10-09T00:46:30Z batch, block 15948054. verify_anchor with tanilo-receipt-verify 0.2.0 against the trusted contract reports anchored. The Tanilo side of the chain now carries signature plus on-chain anchor.

Joe's finding, folded into the standard's future: in the current example, evidence_references sits outside canonical_bytes, so output_hash does not cover the URL or kid. What is committed is the sentence in output.text naming the hash. The metadata_hash in Section 3.1 of draft-zambo-aer1-14 is the natural construction to cover the reference block going forward.

The current revision of the draft is draft-zambo-aer1-23; this interop record remains aligned to the -14 text it was run against.

What the receipt records, and what it does not

It records the offer in full, digests of the offer and supplied terms, the comparison amounts, the rule applied, and the outcome. A valid signature shows which key signed those bytes and that they have not changed since.

It does not show that the premise was true. The terms are supplied by the caller and are not authenticated: nothing here shows the agreement exists, was signed by anyone, or is the one in force. The claim text behind subject.claim_hash is not stored; only its hash is in the receipt. It also does not show that any tool call acted on the result; that is the AER-1 receipt's half.

This is the whole standard in one chain. A verifiable receipt proves the saved record was not changed. It does not prove the model was right, the decision was fair, or the premise was true. Any system that reads a valid receipt as proof of the underlying claim is doing claim laundering, and this chain is the worked example that shows where the boundary sits.

What this means for the standard

An independent party read the draft text, built their half against it, and the two halves chain together with real values. That is what a standard looks like in practice. Not an announcement, but two strangers' receipts referencing each other with bytes anyone can recheck.

This is the first live independent interop validation of AER-1, alongside the FlyThink claim-scope fixture, which bound AER-1 receipts to physical completion evidence in four replayable cases. Both are recorded in the Implementation Status of draft-zambo-aer1-15.

Build on the standard: mint a verifiable receipt in 30 seconds, verify it at zambo.dev/verify, no signup.

Browse the public registry of AER-1 implementations.

See it on a real call: the live demo runs one real Zambo call and hands you its verifiable receipt, no signup. To put a receipt under every call your agent makes, a Zambo Day Pass unlocks everything for 24 hours for $0.99.