The record so far
Four independent implementations have run the frozen conformance corpus and matched every verdict: ARION's Node.js verifier (165/165 against the draft -08 corpus), ARION's Java verifier (186/186 against draft -10), ColonistOne's aer1-perl (68/68 against draft -09, with zero disagreements against both reference runners), and a clean-room Python verifier by MasterD of Arkie AI (84/84), written from the draft text. Three more of ARION's ports, in Ruby, Swift, and PHP, sit in the registry under a deliberately weaker label, for reasons that are mistake number three below.
None of those builders had a private channel to the spec's intent. They had the draft, the test vectors, and whatever the production server at zambo.dev actually serves. Where their readings of the text disagreed with production, the disagreements were specific, reproducible, and exactly the kind a format needs before anyone calls it stable. Two of the three mistakes below were caught by outsiders. The third is a discipline the registry imposed on itself.
1. The Merkle leaf is the receipt's identifier, not its output
A multi-step job closes with a workflow summary receipt: the step receipts, listed in order, bound by one Merkle root. Recompute the root from the steps you hold, compare it to the root on the summary, and any inserted, dropped, reordered, or substituted step changes the answer. The construction sounds simple enough that the first implementations, including production, built it the intuitive way: leaves over the steps' output hashes, the digests of what each step produced.
The normative text says otherwise. Section 8.1 of the draft defines the root as computed over the ordered step receipt identifiers: each leaf is the SHA-256 hash of the UTF-8 bytes of one step receipt's identifier string, paired and hashed up to the root. But the descriptive passages around the hosted workflow tools, Sections 8.5 and 8.7, described the root in the output-hash language, and the production server had been built to match its own descriptions. The spec and the server were each internally consistent. They disagreed with each other.
An outside implementer found the split. Iman Schrock, of the Emilia Protocol, implemented the construction from the draft, recomputed roots against the live server, and reported the divergence on the agent2agent mailing list on October 12, 2026. His recomputation was right and production was wrong, because the test that matters for a format is not "does the server agree with itself" but "does an independent reader of the text arrive at the same bytes." A verifier built to Section 8.1 and a server built to the summaries could never verify each other's workflows.
The resolution ran in the only defensible direction: the normative construction won. Production aligned its roots to Section 8.1, revision 19 of the draft aligned the Section 8.5 and 8.7 descriptions to the normative text (documentation only, no construction change), and Section 18 of revision 19 credits Iman by name for the report. The conformance corpus also gained the edge case his report asked for: a one-step Merkle vector, a workflow with a single step, where the leaf digest is the root. The production one-step root (7c90f65a…) matches that corpus vector, and Iman rechecked the live API afterward and confirmed in writing that the mismatch was closed.
2. The canonical bytes are the bytes. Never re-canonicalize
Every AER-1 receipt carries its canonical bytes and an output hash: the SHA-256 of exactly those bytes. Verifying looks like a one-liner, and the first instinct of an experienced implementer is to make it robust: parse the JSON, re-serialize it in canonical form, hash the result, compare. It feels like the careful version of the check. It is the broken version.
Re-serializing verifies your serializer, not the receipt. The moment a verifier parses and re-emits, every choice its JSON stack makes (key ordering, whitespace, number formatting, string escaping) silently becomes part of the commitment check. Two honest implementations with different stacks then disagree about valid receipts, or worse, agree about a receipt whose stored bytes were swapped for a re-serialization that happens to hash the same under one stack's habits. The commitment stops being a property of the record and becomes a property of whoever is checking it.
Section 4 of the draft closes the door explicitly. The producer MUST preserve the exact UTF-8 byte sequence that was hashed and expose it, directly or in a form a verifier can reproduce byte for byte. A verifier that cannot obtain or reproduce the exact canonical bytes MUST NOT report the output commitment as confirmed. And no Unicode normalization at any point: normalization is a transformation, and it breaks the commitment like any other edit. The draft makes the point with a vector pair. The string "café" in NFC form is five bytes and hashes to one digest; the visually identical string in NFD form is six bytes and hashes to a different one. A receipt committing to either form does not verify against the other, by design.
The narrow claim is what makes this discipline worth keeping. A verifiable receipt proves the saved result was not changed since it was saved. That sentence is only true if "the saved result" names a specific byte sequence and verification means hashing that sequence, not a fresh rendering of it. First implementations that re-canonicalized were not sloppy; they were applying a reasonable habit from formats where canonicalization is the verifier's job. In AER-1 it is the producer's job, done once, at execution time, and after that the bytes are the ground truth.
3. Parity is not conformance
The third mistake is a labeling failure, and it is the one that inflates quietly if nobody polices it. When ARION ported the verifier to Ruby, Swift, and PHP, the ports were exercised hard: 24,834 parity comparisons in Ruby, 19,615 in Swift, 11,529 runs in PHP, with zero divergences. Numbers like those beg to be announced as conformance. They are not conformance, and the registry refuses to call them that.
The distinction is about what the result is anchored to. Parity means the ports agree with each other, checked against the author's own verifier logic in large comparison runs. It is strong evidence that the ports behave alike. Conformance means an implementation ran the frozen test vector corpus, vectors derived from the draft text with expected verdicts fixed in advance, and matched every verdict: the 165/165, 186/186, 68/68, and 84/84 results above. Parity can be unanimously wrong: four ports can share one misreading and agree perfectly while all four diverge from the spec. Conformance anchors to the text through vectors that were frozen before the implementations were judged against them.
So the registry carries both labels and never upgrades one into the other. The Ruby, Swift, and PHP rows read "parity-checked," with the comparison counts shown, until the day those ports run the corpus and earn the other word. This costs the project some headline numbers and buys the only thing a registry is for: a reader can trust that the status column means the same thing on every row. A format whose public record inflates its own results teaches implementers to discount the record, and then even the true results stop being believed.
What the kit does about each
Lessons that live only in blog posts decay. Each of the three mistakes is now pinned down in the conformance kit itself, so the next implementer hits the trap as a failing test instead of a mailing-list thread.
- For the Merkle construction: the corpus carries nine Merkle vectors, including the one-step vector added after Iman's report, so a verifier that builds leaves over anything other than receipt identifiers fails against a frozen expected root, including at the single-step edge where the leaf digest is the root.
- For canonical bytes: the corpus holds the NFC/NFD vector pair and byte-level traps (unpadded base64, non-UTF-8 bytes, tampered provenance), so a verifier that normalizes, re-serializes, or decodes loosely produces wrong verdicts on vectors whose expected outcomes are already fixed.
- For the parity line: the kit is the only road to the conformant label. It runs 119 vectors as 122 checks per runner, ships two independent reference runners, and cross-verifies them on 47 core vectors with zero disagreements. A negative vector added October 13, 2026 targets the input commitment from Section 3.3: a payload whose
input_hashis the digest of different inputs than the ones recorded, which both runners now evaluate and reject with the same stated reason.
Run it, read it, or check a receipt against it:
- The full record: the AER-1 implementation report lists every implementation, its recorded result, and its status word, parity labeled as parity.
- The kit: the conformance corpus, both reference runners, and the implementation guide are open on GitLab. Building a verifier from the draft text and running it against the frozen vectors is the whole entry fee.
- The verifier walkthrough: how to verify an AER-1 receipt runs the checks against a real public receipt, hashes included.
- See one minted: the one-click demo runs a real call and hands you the receipt, no signup.
- Keep a whole run: a Day Pass ($0.99) seals a closed workflow so its page, verify badge, and PDF pack stay put after the free viewing window.
The next implementation will find a fourth thing. That is the process working as intended: the draft is a draft, the corpus is the memory of every mistake so far, and the record stays public so the corrections compound.