Skip to main content

AER-1: A Portable Execution Receipt for AI Agent Tool Calls
draft-zambo-aer1-23

Document Type Active Internet-Draft (individual)
Author Brennan Zambo
Last updated 2026-10-19
RFC stream (None)
Intended RFC status (None)
Formats
Stream Stream state (No stream defined)
Consensus boilerplate Unknown
RFC Editor Note (None)
IESG IESG state I-D Exists
Telechat date (None)
Responsible AD (None)
Send notices to (None)
draft-zambo-aer1-23
Network Working Group                                           B. Zambo
Internet-Draft                                                     Zambo
Intended status: Informational                           19 October 2026
Expires: 22 April 2027

      AER-1: A Portable Execution Receipt for AI Agent Tool Calls
                          draft-zambo-aer1-23

Abstract

   This document specifies AER-1, a small vocabulary for recording one
   AI agent tool call as a portable, independently checkable execution
   receipt.  A receipt identifies the execution, records when it
   happened, preserves the canonical bytes used for the output
   commitment, names the tool and caller scope, carries a provenance
   class, and resolves at a stable public URL.  The format separates
   what the system observed from claims about the outside world, and it
   separates provenance (who ran or reported the action) from the record
   itself.  A reference implementation is deployed, and its receipts are
   publicly verifiable without an account or token.  The specification
   covers workflow receipts, which bind an ordered sequence of step
   receipts to a single goal with a Merkle root over the step sequence,
   and hash-chained job timelines for tamper-evident sequencing of
   executions.  This revision closes honesty and precision gaps: it adds
   the workflow-receipt truncation limit (new Section 8.4), normatively
   specifies the external anchor format and its verification procedure
   (rewritten Section 10, new Section 10.1), fixes a RECOMMENDED/MUST
   contradiction in Section 8.1, makes the Section 6 verification step
   testable, and documents replay, low-entropy, empty-record, and size-
   limit considerations.  It changes no receipt field, digest
   construction, or existing verification rule.  The -13 revision fixes
   a malformed sentence in the Abstract, three incorrect section cross-
   references, stale Table of Contents page numbers, a skipped footer
   page number, misaligned table rows, and chain version-string updates,
   and records two reported interoperability examples in Implementation
   Status; it changes no receipt field, digest construction, or
   verification rule.  The -14 revision adds tamper-evident metadata
   binding (new Section 3.1; conditional metadata_hash for schema 0.4
   and later), disambiguates the anchor receipt_id (Table 4), corrects
   the self-anchoring witnessing claim (Section 10), makes the
   Section 8.3 display rule a SHOULD with a byte-testable MUST, narrows
   the provenance attestation wording (Section 5), states the binding
   non-transfer rule normatively (new Section 10.2), pins
   anchored_digest to bare hex (Table 4), corrects the vector corpus
   counts, and adds normative disclosure of missing issuer
   authentication.  It changes no existing receipt field, digest
   construction, or verification rule for schema 0.3 and earlier.  The

Zambo                     Expires 22 April 2027                 [Page 1]
Internet-Draft                    AER-1                     October 2026

   -15 revision narrows the Implementation Status wording for the
   reported interoperability examples at the implementer's request; it
   changes no receipt field, digest construction, or verification rule.
   The -16 revision documents the live workflow tools API (new Sections
   8.5, 8.6, 8.7): the workflow_close tool, workflow metadata in step
   receipts, and the workflow view API.  It changes no receipt field,
   digest construction, or existing verification rule.  The -17 revision
   documents the recommended execution_context member (new Section 3.2):
   an optional, non-core structure for recording source and version
   context such as the model name and version behind a tool call and the
   identity of the source system acted upon.  It changes no existing
   receipt field, digest construction, or verification rule.  The -18
   revision repairs the reference apparatus (normative references to RFC
   3339, RFC 8259, RFC 4122, and RFC 4648, and the previously missing
   RFC 7942 entry), pins two parser edge cases (duplicate JSON member
   names and leap-second timestamps are rejected), names the Unicode
   normalization behavior in Section 4 with a computed vector pair,
   adopts the unknown-versus-not-applicable convention for optional
   members, adds optional members for readback outcomes, per-field
   provenance, negative records, reversal state, method descriptors, and
   payment references, completes the execution_context member set (model
   and environment digests), adds the optional input_hash commitment
   (Section 3.3), permits SCITT and RFC 3161 anchors under Section 10,
   states the clock-trust and equivocation limits in Section 13, and
   rewrites Section 15 to position the specification against adjacent
   work.  It changes no receipt field, digest construction, or
   verification outcome for any receipt well-formed under the -17 rules.
   The -19 revision aligns the workflow tool and workflow view
   descriptions in Sections 8.5 and 8.7 with the normative Merkle
   construction in Section 8.1: both descriptions named step output
   hashes as the root's leaf input where Section 8.1 specifies step
   receipt identifiers.  An implementer report identified the
   divergence.  It changes no construction, receipt field, digest, or
   verification outcome.  The -20 revision adopts three findings
   reported by an independent implementer who built a conformance
   verifier from the -19 text alone.  It requires the published byte
   layout of a recorded input to state the member ordering rule it
   applies when the input is a JSON object (Section 3.3), and it bars
   control characters from provenance class labels, with rejection
   required (Section 5).  The conformance kit's quickstart core tier
   also gains the provenance-label and schema-version metadata checks as
   a stated rule.  It changes no receipt field or digest construction; a
   receipt well-formed under the -19 rules verifies identically, except
   that an input commitment whose published layout states no ordering
   rule is no longer reported as confirmed.  The -21 revision states the
   receipt-id binding rule normatively (Section 6), describes the id-
   substitution case in Security Considerations (Section 13), and
   credits the independent control test that produced the finding

Zambo                     Expires 22 April 2027                 [Page 2]
Internet-Draft                    AER-1                     October 2026

   (Section 18).  It changes no receipt field, digest construction, or
   existing verification rule.  The -22 revision pins the legacy (schema
   0.3) member forms that satisfy the core requirements and requires
   verifiers to report a legacy acceptance explicitly rather than as a
   plain pass (Section 6), requires the canonical base64 spelling of
   canonical_bytes and the rejection of non-canonical spellings
   (Sections 3 and 4), states that the receipt object is the document
   and that no presentation envelope is part of the format (Section 3),
   enumerates the id verdict a verifier reports beside the structural
   verdict, binds the states to verifier behavior, and states the
   resolution order between the two layers (Section 6), requires the
   reason to be printed next to the rule for every check that does not
   pass (Section 6), and records an independent production validator in
   the Implementation Status.  It changes no receipt field or digest
   construction; one verification outcome changes, for a receipt whose
   canonical_bytes spelling is not canonical, which earlier revisions
   did not address.  The -23 revision states the per-anchor outcome
   report normatively (Section 6): a verifier's report carries each
   anchor's outcome in machine-visible form, and an anchor the verifier
   did not evaluate is reported as "not checked", never as an evaluated
   outcome, so that state cannot be conflated with an anchor that was
   evaluated and could not be resolved.  It changes no receipt field,
   digest construction, or existing verification rule.

Implementation Status

   This section records the implementation status of the AER-1
   vocabulary at the time of this revision, following [RFC7942].  It
   will be removed before publication as an RFC.

   Reference implementation.  Zambo (https://zambo.dev), operated by the
   document author, is a deployed implementation of Sections 3 through
   10.  Tool calls made over HTTPS as JSON-RPC to https://zambo.dev/api/
   mcp receive a public receipt page at https://zambo.dev/run/<id>,
   retrievable without an account, wallet, or token.  A machine-readable
   verifier is exposed as described in Section 6.  Receipts are anchored
   to public Nostr relays with an envelope binding the receipt
   identifier, the output hash, and the evidence hash (envelope "zambo-
   receipt-anchor/1").

   Workflow receipts (Section 8) are deployed in the reference
   implementation.  Multi-step sessions receive a workflow receipt at
   https://zambo.dev/workflow/<workflow_id> binding the ordered step
   receipts with a Merkle root, and step receipt pages link to the
   parent workflow ("Part of workflow") while workflow pages link to
   each step receipt.

Zambo                     Expires 22 April 2027                 [Page 3]
Internet-Draft                    AER-1                     October 2026

   Conformance kit.  An open conformance suite for this vocabulary is
   maintained at https://gitlab.com/rambozambodotdev/zambo.  It ships
   seven bundled kit runners (Rust, Go, TypeScript, Python, Java, C#,
   and Swift), each verified against the full vector corpus, which at
   this revision stands at 119 vectors (122 checks per runner) across
   the receipt-level, Merkle (Section 8.1), timeline (Section 7),
   hardened chain (Section 7.1), chain commitment (Section 7.3),
   Unicode, id-binding, and anchor-report suites.  The -22 revision adds
   vectors pinning the canonical base64 spelling (Section 4), the nil-
   UUID rejection as a standalone case, the legacy schema 0.3 production
   shape (Section 6), the bare presentation form (Section 3), a current-
   schema (0.4) real receipt beside the two bundled 0.3 fixtures, and
   one vector per id_verdict state (Section 6).  The -23 revision adds
   the anchor-report vectors pinning the per-anchor outcome report of
   Section 6, implemented in the kit runners (kit v1.5.6) and in the
   reference verifier (aer1-verify 0.2.13) ahead of this text.  Each
   runner is zero-dependency within its language toolchain.  Running the
   Python suite takes two steps and no dependencies beyond git and a
   Python 3 interpreter:

   git clone https://gitlab.com/rambozambodotdev/zambo.git python3 aer1-
   implementations/python/conformance.py

   An implementation is conformant when it produces byte-identical
   verdicts to the reference runners across the full vector corpus.  The
   corpus includes attack vectors for tampered provenance labels, schema
   version downgrades, and legacy (pre-0.4) receipts; conformance
   requires the Section 6 metadata checks to fail the first two and to
   report the third with a legacy notice rather than a failure.  The kit
   is versioned; the v1.5.5 release is the frozen reference for the
   corpus described above.

   Independent verification.  The Section 6 verification procedure has
   been exercised against live receipts by independent third parties:

   *  On 2026-09-16, an independent agent ("Merv", on the Clawstr
      network) verified a live receipt (id 0ec81343-cc1f-
      4c25-9c33-d76b5582406d) in three checks: the SHA-256 of the
      decoded canonical bytes matched the output commitment, the
      upstream evidence hash matched, and the anchor event carried a
      valid signature retrievable on independent relays.  The same party
      reported that the anchor envelope did not then bind the evidence
      hash; the reference implementation has since shipped the binding
      envelope described above.

Zambo                     Expires 22 April 2027                 [Page 4]
Internet-Draft                    AER-1                     October 2026

   *  On 2026-09-16, an independent agent ("nilo_agent", on Nostr) ran
      adversarial verification challenges against live receipts,
      including a witness round and a strong-form Bitcoin-anchored
      challenge (anchor block 967351, receipt 88094e26), each answered
      with bytes the challenger could check independently.

   *  On 2026-09-25 and 2026-09-26, an independent agent ("Devan", on
      Nostr) published timestamped probe receipts (v1 and v2) exercising
      independent verification of agent work in the same receipt model.

   Independent validators.  An independent implementation exposes the
   Section 6 procedure as a public service:

   *  WhiteMagic Labs (Lucas Bailey) operates a production validator for
      this specification at https://api.whitemagic.dev/aer1/verify,
      publicly accessible without a key, with the same procedure also
      exposed as an MCP tool (verify_aer1_receipt).  On 2026-10-17 the
      operator exercised the validator against the reference
      implementation and the conformance corpus.  The two
      implementations initially disagreed on cases in both directions (a
      decoding boundary in the validator; an id-binding reading and a
      nil-UUID acceptance in the reference tooling), each disagreement
      was resolved against the draft text the same day, and the
      implementations now agree across the exercised case matrix.  The
      validator reports comparison outcomes in the shared states of
      Section 6 and attaches its provenance caution as advisory metadata
      beside the verdict, the arrangement the provenance note in
      Section 6 describes.

   Seven bundled kit runners for Sections 3 through 6 are maintained in
   the conformance kit repository (Rust, Go, TypeScript, Python, Java,
   C#, and Swift), each verified against the full vector corpus
   described above (113 vectors, 116 checks per runner).  These runners
   are the kit's own test runners, not independent implementations.
   Independent third-party implementations, built from the draft text
   alone without access to kit internals, include ARION's Node.js and
   Java verifiers and ColonistOne's Perl verifier, each conformant
   against the same corpus.  Since revision 12, contributors have
   reported two scoped interoperability exercises.  On 2026-10-08,
   Tanilo and the AER-1 author published a cross-repository worked
   example linking an AER-1 receipt to a live Tanilo receipt by
   canonical hash, with the AER-1 commitment check and the Tanilo
   signature check run separately, each under its own rules.  Also on
   2026-10-08, the independent builder FlyThink published a four-case
   fixture binding AER-1 execution receipts to physical completion
   claims; all four cases replay cleanly, including the case where a
   valid AER-1 receipt coexists with invalid physical-evidence binding
   (see Section 10.2).  Reports of additional implementations or

Zambo                     Expires 22 April 2027                 [Page 5]
Internet-Draft                    AER-1                     October 2026

   independent verification results are solicited; implementers are
   encouraged to validate against the open conformance kit described
   above and to report their results.

Status of This Memo

   This Internet-Draft is submitted in full conformance with the
   provisions of BCP 78 and BCP 79.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF).  Note that other groups may also distribute
   working documents as Internet-Drafts.  The list of current Internet-
   Drafts is at https://datatracker.ietf.org/drafts/current/.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress."

   This Internet-Draft will expire on 22 April 2027.

Copyright Notice

   Copyright (c) 2026 IETF Trust and the persons identified as the
   document authors.  All rights reserved.

   This document is subject to BCP 78 and the IETF Trust's Legal
   Provisions Relating to IETF Documents (https://trustee.ietf.org/
   license-info) in effect on the date of publication of this document.
   Please review these documents carefully, as they describe your rights
   and restrictions with respect to this document.

Table of Contents

   1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   7
   2.  Terminology . . . . . . . . . . . . . . . . . . . . . . . . .   8
   3.  The Receipt Record  . . . . . . . . . . . . . . . . . . . . .   8
     3.1.  Metadata Binding  . . . . . . . . . . . . . . . . . . . .  12
     3.2.  Execution Context . . . . . . . . . . . . . . . . . . . .  12
     3.3.  Optional Input Commitment . . . . . . . . . . . . . . . .  14
     3.4.  Additional Optional Members . . . . . . . . . . . . . . .  15
   4.  Canonical Bytes and Output Commitment . . . . . . . . . . . .  16
   5.  Provenance Classes  . . . . . . . . . . . . . . . . . . . . .  17
   6.  Verification Procedure  . . . . . . . . . . . . . . . . . . .  18
   7.  Hash-Chained Job Timelines  . . . . . . . . . . . . . . . . .  22
     7.1.  The Entry Digest  . . . . . . . . . . . . . . . . . . . .  23
     7.2.  Chain Rules . . . . . . . . . . . . . . . . . . . . . . .  24
     7.3.  What the Chain Does Not Prove . . . . . . . . . . . . . .  24

Zambo                     Expires 22 April 2027                 [Page 6]
Internet-Draft                    AER-1                     October 2026

     7.4.  Versioning  . . . . . . . . . . . . . . . . . . . . . . .  26
   8.  Workflow Receipts . . . . . . . . . . . . . . . . . . . . . .  26
     8.1.  Merkle Root and Output Hash . . . . . . . . . . . . . . .  30
     8.2.  Workflow Verification Procedure . . . . . . . . . . . . .  31
     8.3.  Bidirectional Linking Between Steps and Workflows . . . .  32
     8.4.  What the Merkle Root Does Not Prove . . . . . . . . . . .  33
     8.5.  Workflow Close Tool . . . . . . . . . . . . . . . . . . .  34
     8.6.  Workflow Metadata in Step Receipts  . . . . . . . . . . .  34
     8.7.  Workflow View API . . . . . . . . . . . . . . . . . . . .  35
   9.  Public Resolution . . . . . . . . . . . . . . . . . . . . . .  35
   10. External Anchoring  . . . . . . . . . . . . . . . . . . . . .  36
     10.1.  Anchor Verification Procedure  . . . . . . . . . . . . .  38
     10.2.  Binding Does Not Transfer Claims . . . . . . . . . . . .  39
   11. Reference Implementation  . . . . . . . . . . . . . . . . . .  40
   12. Design Rationale  . . . . . . . . . . . . . . . . . . . . . .  40
   13. Security Considerations . . . . . . . . . . . . . . . . . . .  41
   14. IANA Considerations . . . . . . . . . . . . . . . . . . . . .  44
   15. Related Work  . . . . . . . . . . . . . . . . . . . . . . . .  44
   16. Normative References  . . . . . . . . . . . . . . . . . . . .  45
   17. Informative References  . . . . . . . . . . . . . . . . . . .  46
   18. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . .  47
   Appendix A.  Mapping Note: EU AI Act Article 12 (Informative) . .  49
   Author's Address  . . . . . . . . . . . . . . . . . . . . . . . .  50

1.  Introduction

   AI agents increasingly act through tool calls: they query prices,
   send messages, modify files, and invoke services on a principal's
   behalf.  When something later needs checking -- what happened, when
   it happened, and what the system actually observed -- the parties
   involved usually have only vendor-specific logs, screenshots, or the
   agent's own summary.  None of these is portable across
   implementations, and none lets an independent third party recompute
   what was recorded.

   AER-1 (AI Agent Execution Receipt, version 1) defines a small,
   portable vocabulary for recording one agent tool call as a verifiable
   receipt.  The receipt answers a narrow question: what did this system
   record for this execution?  It does not prove an external business
   outcome the system did not observe, and it does not turn a planned,
   blocked, or preview action into a completed execution.

   This document is an open proposal authored by Brennan Zambo.  It is
   not a claim to invent or own the broader execution-receipt category,
   and it does not establish certification, registry membership,
   universal adoption, or a finalized standards status.  It is intended

Zambo                     Expires 22 April 2027                 [Page 7]
Internet-Draft                    AER-1                     October 2026

   for discussion, implementation experiments, and interoperability
   feedback.  A reference implementation is deployed at the time of
   writing, and its receipts are publicly verifiable as described in
   Section 11.

2.  Terminology

   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
   "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and
   "OPTIONAL" in this document are to be interpreted as described in BCP
   14 [RFC2119] [RFC8174] when, and only when, they appear in all
   capitals, as shown here.

   This document also uses the following terms:

   Execution:  One invocation of one tool by or on behalf of an agent,
      with its inputs, observed result, and timing.

   Receipt:  A public record for one execution with a stable identifier,
      execution metadata, canonical bytes, and an output commitment, as
      defined in Section 3.

   Canonical bytes:  The exact UTF-8 byte sequence over which the output
      commitment was computed.  Verifiers MUST receive or reproduce the
      same bytes before comparing hashes.

   Observed result:  The result the implementation received and stored
      for the execution.  A receipt reports observation, not an
      unsupported claim about the world beyond the observation.

   Output commitment:  A SHA-256 digest of the canonical bytes, written
      "sha256:" followed by the lowercase hexadecimal digest.

3.  The Receipt Record

   A receipt is a JSON [RFC8259] object with the following members.
   This is the smallest useful interoperable shape; implementations MAY
   add fields, but additions MUST NOT make the core identity or
   verification fields ambiguous.

   +========================+==========+===============================+
   | Field                  | Required | Meaning                       |
   +========================+==========+===============================+
   | id                     | MUST     | Stable UUID                   |
   |                        |          | identifying the               |
   |                        |          | receipt.                      |
   +------------------------+----------+-------------------------------+
   | receipt_schema_version | MUST     | Schema version. "0.3"         |

Zambo                     Expires 22 April 2027                 [Page 8]
Internet-Draft                    AER-1                     October 2026

   |                        |          | in the reference              |
   |                        |          | implementation. Versions      |
   |                        |          | compare numerically by        |
   |                        |          | dot-separated components;     |
   |                        |          | "0.4" or later means the      |
   |                        |          | version is equal to or        |
   |                        |          | greater than "0.4" under      |
   |                        |          | that ordering.                |
   +------------------------+----------+-------------------------------+
   | created_at             | MUST     | Timestamp of record           |
   |                        |          | creation, in [RFC3339]        |
   |                        |          | format.  The timestamp MUST   |
   |                        |          | denote a valid calendar date  |
   |                        |          | and time; a verifier MUST     |
   |                        |          | reject values such as         |
   |                        |          | February 30 that match the    |
   |                        |          | RFC 3339 syntax but are not   |
   |                        |          | real dates, and MUST reject   |
   |                        |          | leap-second values (a         |
   |                        |          | seconds value of 60; see      |
   |                        |          | Section 6).                   |
   +------------------------+----------+-------------------------------+
   | tool                   | MUST     | Object naming the             |
   |                        |          | tool: name, version,          |
   |                        |          | and caller scope (for         |
   |                        |          | example "public").            |
   +------------------------+----------+-------------------------------+
   | provenance_class       | MUST     | One of the provenance         |
   |                        |          | classes in Section 5.         |
   +------------------------+----------+-------------------------------+
   | canonical_bytes        | MUST     | Base64 encoding [RFC4648]     |
   |                        |          | of the exact UTF-8 bytes      |
   |                        |          | hashed for the output         |
   |                        |          | commitment.                   |
   +------------------------+----------+-------------------------------+
   | output_hash            | MUST     | "sha256:" plus the            |
   |                        |          | lowercase hex digest          |
   |                        |          | of the decoded                |
   |                        |          | canonical_bytes.              |
   +------------------------+----------+-------------------------------+
   | metadata_hash          | Cond.    | "sha256:" plus the            |
   |                        |          | lowercase hex digest of       |
   |                        |          | the canonical metadata        |
   |                        |          | block defined in              |
   |                        |          | Section 3.1.  REQUIRED        |
   |                        |          | when receipt_schema_version   |
   |                        |          | is "0.4" or later; a          |
   |                        |          | verifier MUST recompute       |

Zambo                     Expires 22 April 2027                 [Page 9]
Internet-Draft                    AER-1                     October 2026

   |                        |          | and compare it whenever       |
   |                        |          | present.                      |
   +------------------------+----------+-------------------------------+
   | verification_status    | MUST     | "verified" when the           |
   |                        |          | stored record passes          |
   |                        |          | the procedure in              |
   |                        |          | Section 6.                    |
   +------------------------+----------+-------------------------------+
   | supersedes             | OPTIONAL | Id of a prior receipt that    |
   |                        |          | this receipt corrects         |
   |                        |          | (Section 9).                  |
   +------------------------+----------+-------------------------------+

   Table 1: Core receipt members

   The id member is a stable identifier for the receipt.  Two
   conformance tiers apply: the core tier and the strict tier.  The core
   rule (both tiers) is a lowercase UUID-shaped string: eight, four,
   four, four, and twelve lowercase hexadecimal characters separated by
   hyphens.  Lowercase is load-bearing: Section 8.1 hashes the UTF-8
   bytes of the receipt identifier string verbatim for the Merkle leaf,
   so a change of case changes the root.  A verifier MUST accept any id
   matching the core rule.  The nil UUID
   (00000000-0000-0000-0000-000000000000) MUST NOT be used as a receipt
   id at any tier; a verifier MUST reject it.  A producer MUST NOT reuse
   an id for a different receipt; each receipt id identifies exactly one
   receipt.  The strict tier additionally requires the id to be a UUID
   version 4 with [RFC4122] variant bits; it applies when the receipt is
   issued under a program that requires it (for example, a certification
   program), as documented alongside the receipt.  A verifier applying
   the strict profile MUST reject an id that is not a version 4 UUID
   with [RFC4122] variant bits.

   The lexical form of the receipt id, in ABNF [RFC5234], is:

      receipt-id = 8HEXDIG "-" 4HEXDIG "-" 4HEXDIG "-" 4HEXDIG
                   "-" 12HEXDIG

   In this ABNF, HEXDIG is restricted to lowercase a-f for alphabetic
   digits, per the core rule above.  The digest string form used by
   output_hash and metadata_hash is:

      digest-string = "sha256:" 64HEXDIG

   with the same lowercase restriction.  Where the ABNF and the prose of
   this section differ, the prose governs.

Zambo                     Expires 22 April 2027                [Page 10]
Internet-Draft                    AER-1                     October 2026

   The public URL is not a stored member; it is a resolution rule.
   Every receipt MUST be retrievable at a stable public URL without an
   account, wallet, or token, as specified in Section 9.  In the
   reference implementation the URL is https://zambo.dev/run/<id>.

   Deployed records carry additional members outside the interoperable
   core (for example caller identity, evidence references, external
   anchor data, per-check results, side-effect declarations, and a
   result preview).  A verifier MUST NOT require them, and their
   presence MUST NOT change the meaning of the core members.  For every
   optional member in this specification, absence means the producer did
   not record the value; absence is never, by itself, evidence of
   tampering.

   The receipt is the JSON object defined by its member set; that object
   is the document.  No presentation envelope is part of this format: a
   verifier MUST accept the receipt object presented bare, as the
   document itself.  A transport or an API MAY carry the receipt as a
   member of a wrapping object; the wrap is not part of the receipt, and
   a verifier that receives a wrapped receipt evaluates the same object.
   (In this document the word "envelope" otherwise denotes the anchor
   envelope of Section 10, a different object.)  A presentation that
   cannot be unwrapped to a receipt object is reported as "rejected:
   <reason>" under Section 6, never as "verification failed": no receipt
   bytes were reached.

   The canonical_bytes member MAY be the empty string, which denotes a
   tool execution that produced zero bytes of output.  The output_hash
   of empty canonical bytes is "sha256:" followed by
   e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855, the
   SHA-256 digest of the empty string.  A verifier MUST accept empty
   canonical bytes when the output_hash matches, and MUST NOT treat
   emptiness as a verification failure.

   Example: the following shows the core fields of a real receipt issued
   by the reference implementation (id 130da435-e157-498e-
   af90-605866a86a27, a live_price call).  The canonical bytes and
   output hash are elided here to respect line-length limits; the
   complete record is published at https://zambo.dev/run/130da435-e157-
   498e-af90-605866a86a27, where the output hash was independently
   recomputed from the decoded canonical bytes while preparing this
   document and matches.

Zambo                     Expires 22 April 2027                [Page 11]
Internet-Draft                    AER-1                     October 2026

   {
     "id": "130da435-e157-498e-af90-605866a86a27",
     "receipt_schema_version": "0.3",
     "created_at": "2026-09-23T23:45:20.760Z",
     "tool": {
       "name": "live_price",
       "version": "4.0.0",
       "scope": "public"
     },
     "provenance_class": "EXECUTED BY ZAMBO",
     "canonical_bytes": "(elided; full value at the URL above)",
     "output_hash": "(elided; full value at the URL above)",
     "verification_status": "verified"
   }

3.1.  Metadata Binding

   The canonical metadata block is a JSON object with exactly the
   following members: "created_at", "id", "output_hash",
   "provenance_class", "receipt_schema_version", and "tool" (an object
   with exactly "name", "scope", "version").  It is serialized with
   member names sorted by Unicode code point at every object level,
   including nested objects, no whitespace outside strings, and the
   string escaping of Section 7.1.  Every member value in the block is a
   JSON string.  The metadata_hash member is "sha256:" followed by the
   lowercase hex SHA-256 digest of the UTF-8 encoding of the block.
   Because the block includes the receipt id and the output_hash, a
   metadata_hash copied from another receipt does not verify.  A
   producer MUST NOT emit duplicate member names in the block, and a
   verifier MUST reject a block that carries them (Section 6).

3.2.  Execution Context

   A receipt MAY carry an "execution_context" member recording the
   source and version context behind the tool call: which model produced
   the action, which source system was acted upon, and which agent
   framework issued the call.  This member is OPTIONAL and sits outside
   the interoperable core defined in Table 1; a verifier MUST NOT
   require it, and its presence MUST NOT change the meaning of the core
   members.  It is NOT part of the canonical metadata block in
   Section 3.1 and MUST NOT be included in the metadata_hash
   computation.

   When present, execution_context is a JSON object whose members are
   all OPTIONAL:

Zambo                     Expires 22 April 2027                [Page 12]
Internet-Draft                    AER-1                     October 2026

   *  "model": an object with "name" and "version" string members
      identifying the AI model behind the tool call, when the producer
      knows it (for example {"name": "grok-4", "version":
      "2026-08-01"}).  The model object MAY also carry a "digest"
      member: "sha256:" plus the digest of the model weights or serving
      configuration, as recorded by the producer.

   *  "source": a string identifying the source system the tool acted
      upon, when the call targets a specific external system (for
      example a database name, repository, or API endpoint).

   *  "framework": an object with "name" and "version" string members
      identifying the agent framework that issued the tool call, when
      applicable.

   *  "environment": a string, or an object with "name" and "digest"
      members, identifying the compute environment the call ran in, when
      the producer records it.

   *  "readback": an object recording a fresh-read check of an earlier
      write, with members "receipt" (the id of the receipt whose write
      is read back), "intended" (the intended change), "write_result"
      (the recorded write outcome), "readback" (the fresh-read outcome),
      and "mismatch" (a boolean: true when the fresh read disagrees with
      the intended change).  A mismatch is a first-class recorded
      outcome of the readback receipt, not an error in it.

   *  "payment": an object binding the execution to the payment that
      authorized or paid for it, with members "method" (a string naming
      the payment method, for example "x402") and "reference" (a string
      carrying the settlement reference, for example a transaction
      identifier).  The member records the reference as stated; it does
      not by itself prove settlement.

   Within execution_context, a member present with the JSON value null
   means the value is known not to apply to this call; an omitted member
   means the value is unknown or was not recorded.  Producers SHOULD use
   the explicit null for a known-inapplicable member rather than
   omitting it.  A verifier MUST NOT treat an omitted member as a false
   or inapplicable value, and MUST NOT treat absence, by itself, as
   evidence of tampering.

   Because execution_context is outside the metadata_hash computation,
   it is unauthenticated metadata: it is asserted by the producer, and
   anyone holding the receipt can add, change, or drop it without
   affecting any verification outcome under Section 6.  A verifier MUST
   surface it as producer-asserted context, never as an attested fact.

Zambo                     Expires 22 April 2027                [Page 13]
Internet-Draft                    AER-1                     October 2026

   Producers SHOULD include execution_context whenever the information
   is available to them.  The core "tool" member already names the tool
   and its version; execution_context answers the adjacent questions of
   which model, which source, and which framework surrounded the call.
   Like all additional members, a verifier surfaces execution_context as
   recorded without upgrading its claims: the receipt proves the context
   was recorded as stated, not that the stated model or source is
   accurate.

   Consumers MAY compare the execution_context of related receipts over
   time: a change in the recorded context between a receipt and the
   current environment can serve as an invalidation signal that prompts
   re-verification.  Such a comparison changes no verification verdict
   by itself.

3.3.  Optional Input Commitment

   A receipt MAY carry an "input_hash" member: "sha256:" plus the
   lowercase hex digest of the exact tool-input bytes the producer
   recorded for the execution, computed under the same exact-byte rule
   as the output commitment (Section 4).  The producer MUST define and
   publish the byte layout of the recorded input (for example, the
   argument object under a stated serialization) alongside the receipt,
   mirroring the byte-layout rule of Section 7.1; a verifier that cannot
   reproduce the layout MUST NOT report the input commitment as
   confirmed.

   When the recorded input is a JSON object, the published byte layout
   MUST state the member ordering rule it applies (for example,
   lexicographic order of member names, or the order in which the
   members were recorded).  A byte layout that does not state a member
   ordering rule is incomplete, and a verifier MUST NOT report the input
   commitment as confirmed under an incomplete layout.  Two
   serializations of one object that differ only in member order are
   different byte strings with different digests, so an unstated
   ordering leaves two honest implementations free to compute different
   input_hash values for the same recorded input while both conform to
   the layout as published.  The conformance corpus includes a multi-
   member input vector whose stated layout pins the ordering, and the
   same object serialized under a different member order, which does not
   confirm the recorded commitment.

   input_hash is OPTIONAL and sits outside the interoperable core
   defined in Table 1; it MUST NOT be included in the metadata_hash
   computation, and a verifier MUST NOT require it.  Like every
   commitment in this specification, it proves the input was recorded as
   stated, not that the recorded arguments were the ones actually
   executed.

Zambo                     Expires 22 April 2027                [Page 14]
Internet-Draft                    AER-1                     October 2026

3.4.  Additional Optional Members

   The following members are OPTIONAL, sit outside the interoperable
   core and outside the metadata_hash computation, and are recorded as
   stated.  A verifier MUST NOT require them and MUST surface them
   without upgrading their claims.

   *  "field_provenance": an object mapping receipt member names to the
      party that wrote the member's value: "actor" (the agent or
      caller), "tool" (the executing tool or the system behind it), or
      "counterparty" (a party other than the actor, for example the
      system the tool acted upon).  The receipt-level provenance class
      (Section 5) states who ran or reported the action as a whole; this
      member states, per field, which values are externally written and
      which are self-authored, so that a field that has only ever
      carried one value is visible as such.

   *  "negative_record": an object with two OPTIONAL members,
      "not_checked" and "not_run", each an array of strings naming
      checks that were not performed and actions that were not taken in
      connection with the execution.  A receipt records what ran; this
      member records the known blind spots around it, so that a
      correctly executed action is not read as a completely checked one.

   *  "reversal": an object recording whether the execution was later
      undone, with members "state" (one of "none", "reversed", or
      "compensated") and, when one exists, "compensating_receipt" (the
      id of the receipt that records the compensating execution).
      Unlike supersedes (Section 7.3), which corrects the record, this
      member records compensation of the effect.  It records the state
      as stated; whether a reversal is permitted or enforced belongs to
      the executing system, not to the receipt.

   *  "method_descriptor": an object identifying the method that
      produced the committed bytes, with OPTIONAL members "method" (a
      tool-specific method identifier, for example a function selector
      or RPC method name), "argument_encoding" (how the arguments were
      encoded), and "decode" (how the raw result was decoded).
      Section 4 binds the exact bytes; this member names the question
      the bytes answer, so receipts can be compared by method without
      parsing tool-specific bytes.

Zambo                     Expires 22 April 2027                [Page 15]
Internet-Draft                    AER-1                     October 2026

4.  Canonical Bytes and Output Commitment

   Interoperability fails when every implementation gives a different
   name to the same boundary, so the checkable core of a receipt is
   deliberately small: an identifier locates the record, a creation time
   orders it, a tool and caller scope identify the execution context,
   and canonical bytes plus an output hash make the stored
   representation checkable.

   The producer MUST preserve the exact UTF-8 byte sequence that was
   hashed, and MUST expose it (directly, or in a form from which a
   verifier can reproduce it byte for byte) so that any party can
   recompute the digest.  The digest algorithm is SHA-256 [FIPS180-4].
   A verifier that cannot obtain or reproduce the exact canonical bytes
   MUST NOT report the output commitment as confirmed.  A verifier MUST
   decode the canonical bytes as strict UTF-8 and MUST reject the
   receipt if the bytes are not valid UTF-8, even when the base64
   decoding and hash comparison would otherwise succeed.

   The canonical_bytes member MUST carry the canonical base64 encoding
   of the bytes: the encoding of [RFC4648] with the standard padding, in
   which the pad bits of the final character are zero.  A spelling that
   decodes to the same bytes but is not the canonical spelling (for
   example, one with non-zero pad bits) is not the canonical encoding.
   A verifier MUST reject a receipt whose canonical_bytes is not the
   canonical spelling, reporting the rejection under Section 6;
   accepting the byte-identical non-canonical spelling would let two
   different records carry one commitment, which is the ambiguity the
   canonical form exists to remove.  A corpus vector pins this case.

Zambo                     Expires 22 April 2027                [Page 16]
Internet-Draft                    AER-1                     October 2026

   Producers and verifiers MUST NOT apply Unicode normalization (such as
   NFC or NFD) to the canonical bytes at any point: normalization is a
   transformation, and it breaks the commitment like any other
   (Section 13).  Visually identical strings with different UTF-8 byte
   sequences are different payloads and hash differently, by design.
   The following vector pair is specified for the conformance corpus.
   The four-character string c, a, f, U+00E9 (LATIN SMALL LETTER E WITH
   ACUTE), in NFC form, is the five bytes 63 61 66 c3 a9, base64
   "Y2Fmw6k=", with SHA-256
   850f7dc43910ff890f8879c0ed26fe697c93a067ad93a7d50f466a7028a9bf4e.
   The same visible string in NFD form (c, a, f, U+0065, U+0301
   COMBINING ACUTE ACCENT) is the six bytes 63 61 66 65 cc 81, base64
   "Y2FmZcyB", with SHA-256
   81ef060bcd98adc7824eb5c1ada83c32491b16018e11e79f00ab9d09e04b015a.  A
   receipt committing to either form does not verify against the other:
   presenting the NFD bytes against the NFC commitment is a verification
   failure, not a match.  A verifier MAY offer a documented strict mode
   that reports a non-NFC payload as "rejected"; a verifier MUST NOT
   normalize a payload and then report agreement.

   A result preview MAY accompany the receipt to give a human reader a
   useful first read.  A preview is not the source dataset, and a
   verifier MUST NOT treat agreement with a preview as agreement with
   the committed bytes.

   Byte commitment alone does not identify the method that produced the
   bytes: the same byte shape can answer different questions under
   different methods.  Section 3.4 defines an optional structured method
   descriptor that names the method alongside the committed bytes.

5.  Provenance Classes

   A whole job can combine actions performed by the recording system
   itself, actions observed through an integrated gateway, and actions
   reported by another agent.  Those cases can all be useful, but they
   do not support the same statement, so every receipt MUST name exactly
   one provenance class.  Verification MUST NOT upgrade a report into an
   observation.

   The three classes are:

   EXECUTED BY ZAMBO: The recording system ran the tool and recorded the
   returned result.  The receipt attests to that recording act and its
   stored output commitment, not to facts beyond what the recording
   system recorded.

Zambo                     Expires 22 April 2027                [Page 17]
Internet-Draft                    AER-1                     October 2026

   OBSERVED VIA GATEWAY: The recording system observed the action
   through an integrated gateway.  The receipt attests to the gateway
   observation, not to facts beyond what the gateway returned.

   LOGGED BY AGENT: An external agent reported the action through a
   journal interface.  The receipt attests that the report was received,
   redacted, timestamped, and chained.  The recording system does not
   claim it ran or observed the action.

   The first label names the recording system; its interoperable content
   is the definition, and another implementation substitutes its own
   system name in that position.  The second and third labels are fixed
   strings.

   A provenance class label MUST NOT contain control characters (code
   points U+0000 to U+001F, or U+007F).  A verifier MUST reject a
   receipt whose provenance_class member contains a control character,
   under the Section 6 metadata checks.  Matching a label by a prefix of
   its characters is not a substitute: a value that merely starts with a
   class label's characters is not that class, and parsing that ignores
   or strips control characters when comparing labels is not conformant.

   Provenance is a separate design axis from the receipt envelope.  Two
   receipts with identical envelopes can carry different provenance, and
   a verifier MUST surface the provenance class alongside every other
   field when presenting a receipt.  Section 3.4 defines an optional
   per-field provenance member that complements this receipt-level
   class.

6.  Verification Procedure

   To verify a receipt, a verifier performs the following steps:

   1.  Resolve the public receipt URL and confirm the id in the
       retrieved record matches the requested execution.

   2.  Read the exact canonical bytes, or the representation needed to
       reproduce them byte for byte.

   3.  Compute SHA-256 over those bytes and compare the result with
       output_hash.

   4.  Check the provenance class (Section 5) and confirm it is one of
       the three defined values.  Confirm the created_at timestamp
       denotes a valid calendar date and time.  This check establishes
       form and calendar validity only, not that the stated time is true
       (Section 13).  When the receipt carries metadata_hash, or when
       receipt_schema_version is "0.4" or later, recompute the metadata

Zambo                     Expires 22 April 2027                [Page 18]
Internet-Draft                    AER-1                     October 2026

       block from the receipt's stored member values per Section 3.1 and
       compare; a mismatch MUST cause verification to fail.  A "0.4"
       receipt without metadata_hash MUST fail.  A "0.3" receipt without
       metadata_hash verifies under the prior rules, but its id, tool
       name, version, scope, creation time, and provenance class are NOT
       bound to the output commitment.  For such a receipt, the Table 1
       requirements are satisfied by the legacy member forms where they
       exist: the creation time MAY be carried by a "timestamp" member
       when "created_at" is absent, and the tool member MAY be a bare
       string naming the tool when the object form is absent.  No other
       Table 1 member has a legacy form.  A verifier that accepts a
       receipt under the prior rules MUST report the legacy acceptance
       as such, MUST state which members were read in legacy form, and
       MUST state the unbound set named above; a legacy acceptance MUST
       NOT be reported as a plain pass under the current schema.  If
       anchors are published for the receipt (Section 10), verify each
       anchor using the procedure in Section 10.1; an anchor that fails
       verification MUST NOT be reported as verified, but anchor failure
       MUST NOT by itself cause the receipt's output commitment check to
       fail.  Report the tool name, timestamp, caller scope, provenance
       class, and per-anchor outcomes alongside the hash check result,
       each labeled with what was actually checked.

   5.  Report only what the stored observation supports.  A passing hash
       confirms the bytes match the commitment; it does not confirm
       anything the system did not observe.  Report outcomes in two
       classes: "verification failed" when a recomputed value does not
       match the committed value (hash mismatch, Merkle root mismatch,
       anchor digest mismatch), and "rejected: <reason>" when the record
       cannot be fully evaluated for a structural, policy, or resource
       reason (duplicate receipt_id, size limit, unresolvable record,
       unreproducible bytes).  A rejection MUST NOT be reported as
       "verification failed," since the record may verify under
       different conditions.

   For every check that does not pass, and for every rejection, the
   report MUST print the reason next to the rule: which requirement was
   applied, and how the record failed it.  A bare outcome with no stated
   reason does not conform to this section.

   The output commitment covers the canonical bytes.  The receipt id is
   not a committed field of the output commitment: it does not appear in
   the canonical bytes, and no step above recomputes it.  The steps
   above, applied to a presented record alone, therefore establish the
   integrity of the presented bytes only.  A verifier establishes that
   the id belongs to those bytes only when it (a) compares the record's
   id against an expected id obtained from a source independent of the
   presented record, or (b) resolves the id under Section 9 and confirms

Zambo                     Expires 22 April 2027                [Page 19]
Internet-Draft                    AER-1                     October 2026

   that the resolved record's output_hash matches the presented record's
   output_hash.  When a verifier performs neither comparison, it MUST
   report the id as unverified alongside the step 5 outcome, and MUST
   NOT present the verification as covering the id.

   A verifier's report carries two layers, and both are always reported.
   The structural verdict is the outcome of the steps above for the
   presented bytes: a pass, "verification failed", or "rejected:
   <reason>".  Beside it, the verifier MUST report an id verdict, named
   "id_verdict", with exactly one of these values:

   *  "matched": the verifier compared the record's id against an
      expected id obtained from a source independent of the presented
      record, as in (a) above, and the two are equal.

   *  "resolved": the verifier resolved the id under Section 9, as in
      (b) above, and the resolved record's output_hash matches the
      presented record's output_hash.

   *  "mismatched": a comparison under (a) or (b) was performed and
      failed: the expected id differs from the record's id, or the
      resolved record's output_hash differs from the presented record's.

   *  "unverified": the presented record carries an id, but the verifier
      performed neither comparison.  This is the case the paragraph
      above governs.

   *  "absent": no receipt id was presented to the verifier at all (for
      example, only canonical bytes were supplied).

   The states bind behavior, not only naming: a conforming verifier MUST
   emit the distinct value for each case, and the conformance corpus
   carries one vector per state.  The values are a partition: every
   verification report falls in exactly one state.  When the two layers
   disagree, the resolution order is fixed.  The structural verdict
   governs the presented bytes and is never upgraded or downgraded by
   the id verdict.  The composite claim "verified receipt <id>" is
   presented only when the structural verdict is a pass and the id
   verdict is "matched" or "resolved".  A report MUST NOT present an id
   verdict of "mismatched" or "unverified" as the verification covering
   the id, and a report that omits the id verdict, or collapses two
   states into one value, does not conform to this section.

   How much a binding is worth depends on the channel that delivered the
   expected id: an expected id supplied by the same party that presents
   the receipt binds the record to that party's assertion, and no
   further.  Weighing the channel belongs to the reader of the report,
   not to the verifier.  A verifier MAY attach provenance advice to its

Zambo                     Expires 22 April 2027                [Page 20]
Internet-Draft                    AER-1                     October 2026

   report (for example, that an expected id was caller-asserted and that
   corroboration from an independent channel is advisable) as additional
   information.  Such advice is metadata about the binding; it MUST NOT
   alter the structural verdict or the id verdict.

   Beside the structural verdict and the id verdict, the report carries
   the per-anchor outcomes in machine-visible form.  For each anchor,
   the report states three distinct pieces of information: whether an
   anchor is present, whether the verifier evaluated it, and the
   outcome.  In the reference tooling the report is an object with
   "present", "evaluated", and "outcome" members; another presentation
   that keeps the three pieces distinct and machine-readable conforms to
   this section.  An anchor is present for this report when the record
   carries an anchor in a shape the verifier can attempt to evaluate.  A
   member named "anchor" whose value is in no anchor shape the verifier
   implements (for example, a record of publication in another system)
   does not make an anchor present.

   The outcome is exactly one of these values:

   *  "verified": the verifier evaluated the anchor and the anchor
      verifies under the procedure that applies to it (Section 10.1 for
      external anchors; the anchor profile's own checks for an anchor
      carried in the record).

   *  "verification failed": the verifier evaluated the anchor and a
      recomputed or stored value does not match what was committed.

   *  "rejected: unresolvable record": the verifier evaluated the anchor
      and the anchor's record could not be resolved, the resource
      outcome of step 5 above.

   *  "not checked": an anchor is present and the verifier did not
      evaluate it.

   *  "absent": no anchor is present for the verifier to evaluate.

Zambo                     Expires 22 April 2027                [Page 21]
Internet-Draft                    AER-1                     October 2026

   The states bind behavior, not only naming.  A verifier MUST NOT
   report an evaluated outcome for an anchor it did not evaluate: an
   unevaluated anchor is reported "not checked", whatever the verifier
   expects evaluation would have found. "not checked" and "rejected:
   unresolvable record" are different states and MUST NOT be conflated:
   the first records that no evaluation was attempted, the second that
   evaluation was attempted and the record could not be resolved.  A
   reader of the report is entitled to rely on the distinction.  The
   anchor outcome is reported beside the structural verdict and does not
   alter it: an anchor that fails or cannot be resolved does not by
   itself fail the receipt's output commitment check (step 4).  The
   conformance corpus carries one vector per state.

   Two structural rules apply before any digest comparison.  A producer
   MUST NOT emit duplicate member names in any JSON object whose
   contents are covered by a digest in this specification (the receipt
   object, the canonical metadata block of Section 3.1, and chain
   entries under Section 7.1), and a verifier MUST reject a receipt in
   which any such object, as received, contains duplicate member names:
   a parser that silently keeps one value would let one byte string
   carry two meanings.  A verifier MUST also reject any timestamp it is
   required to validate whose seconds value is 60 (for example
   "2026-06-30T23:59:60Z"): leap-second validity cannot be checked
   offline, so leap-second timestamps are not accepted.  These outcomes
   are reported as "rejected: duplicate member name" and "rejected:
   leap-second timestamp" under the outcome classes of step 5, and a
   negative vector for each is specified for the conformance corpus.

   A machine-readable verifier SHOULD expose the same procedure over
   HTTP, returning the receipt identifier, verification status, and
   output hash, and signaling failure with a non-success status when the
   record does not verify.  In the reference implementation, an HTTP GET
   on https://zambo.dev/api/receipt/<id>/verify returns a JSON object
   containing at least id, verification_status, and output_hash.

7.  Hash-Chained Job Timelines

   Entries for one job form an append-only hash chain.  Each entry
   carries a prev_digest member whose value is the lowercase hex-encoded
   SHA-256 entry digest of the previous entry, computed as defined in
   Section 7.1.  Because the entry digest binds the entry's sequence
   position, job identifier, closing flag, receipt identifier, tool
   name, provenance class, and output commitment, relabeling an entry's
   metadata, moving the closing flag, or splicing entries across jobs
   breaks the links and is detectable by recomputation.  The conformance
   kit exposes this as a chain-validity check alongside the other
   verification checks.

Zambo                     Expires 22 April 2027                [Page 22]
Internet-Draft                    AER-1                     October 2026

7.1.  The Entry Digest

   The entry digest of a chain entry is SHA-256 over the UTF-8 encoding
   of a canonical JSON object with exactly the following members.
   Member names are sorted by Unicode code point; the serialization
   emits no whitespace outside strings.  The member list below is in
   description order.  The serialization order is the code-point sort:
   close, id, job_id, output_hash, prev_digest, provenance_class, seq,
   tool:

   prev_digest: the entry's prev_digest member, a string.

   seq: the entry's sequence number, a JSON number with an integer
   value.  The representations 1 and 1.0 are equivalent; both are
   accepted, and the digest serializes the value in integer form (1,
   never 1.0).  A verifier MUST reject a non-integer number (such as
   1.5), a boolean, a string, null, or a missing seq.

   job_id: the entry's job identifier, a string.

   close: the entry's close member if present; if the member is absent,
   the boolean false.

   id: the entry's receipt identifier, a string.

   tool: the entry's tool name, a string.

   provenance_class: the entry's provenance class, a string.

   output_hash: the lowercase hex-encoded SHA-256 digest of the raw
   bytes obtained by base64-decoding the entry's canonical_bytes member.

   Strings are serialized as JSON strings with the following exact
   escaping, which matches the output of Python's json.dumps with
   ensure_ascii=True: the quotation mark (U+0022) and reverse solidus
   (U+005C) are escaped as \" and \\; U+0008, U+0009, U+000A, U+000C,
   and U+000D are escaped as \b, \t, \n, \f, and \r; and every other
   code point outside the range U+0020 to U+007E, including U+007F
   (DELETE), is escaped as \u followed by four lowercase hexadecimal
   digits, using a surrogate pair for code points above U+FFFF.  No
   other escaping is used.  A verifier MUST decode canonical_bytes with
   strict base64 [RFC4648] and fail closed: any input that is not valid
   base64 causes chain verification to fail rather than being skipped or
   repaired.

Zambo                     Expires 22 April 2027                [Page 23]
Internet-Draft                    AER-1                     October 2026

7.2.  Chain Rules

   A timeline is a non-empty JSON array of chain entries.  A verifier
   MUST reject an empty timeline.  Each entry carries canonical_bytes (a
   base64 string), prev_digest (a string), seq (an integer), job_id, id,
   tool, and provenance_class (non-empty strings), and optionally close.

   Genesis.  The first entry's prev_digest MUST be 64 zero characters
   ("0" repeated 64 times), the conventional zero digest.  A verifier
   MUST reject a first entry carrying any other prev_digest value.

   Sequence.  The first entry's seq MUST be 1, and each subsequent
   entry's seq MUST be exactly one greater than the previous entry's
   seq.  A verifier MUST reject a timeline with a gap, a duplicate, or
   an out-of-order sequence number.

   One job.  Every entry in a timeline MUST carry the same job_id.  A
   verifier MUST reject a timeline whose entries name different jobs;
   entries cannot be spliced across jobs without breaking the chain.

   Closing.  The close member, when present, MUST be a boolean.  The
   value true MUST appear only on the last entry of the timeline, and
   the last entry MUST carry close set to true.  A verifier MUST fail a
   timeline whose last entry is not a closing entry, and MUST fail a
   timeline carrying close set to true on any earlier entry.

   Links.  A verifier MUST recompute the Section 7.1 entry digest of
   every entry and confirm that each entry after the first carries a
   prev_digest equal to the recomputed digest of the entry before it.  A
   verifier MUST NOT accept a link on the basis of the stored
   prev_digest values alone.

7.3.  What the Chain Does Not Prove

   Recomputation detects relabeling, insertion, deletion, and reordering
   only when the attacker cannot rebuild the links.  An attacker who
   removes entries from either end of a timeline and recomputes a
   complete, valid shorter chain produces a timeline that verifies under
   the rules above: the chain mechanics alone cannot distinguish a
   rebuilt truncation from a job that genuinely ended earlier or started
   later.  This is an honest limit of hash chaining, not a defect in the
   digest.

Zambo                     Expires 22 April 2027                [Page 24]
Internet-Draft                    AER-1                     October 2026

   Truncation resistance needs a commitment outside the chain: a
   witness, a timestamped head, an anchor, or a workflow manifest that
   binds the expected step list or step count.  Deployments that need to
   detect truncation MUST publish such a commitment and verify the
   timeline against it.  The chain check alone MUST NOT be presented as
   truncation-proof.

   That commitment SHOULD bind the digest of the final chain entry, not
   merely the expected step count.  Every entry except the last is bound
   by the following entry's prev_digest; the final entry's digest is
   referenced by nothing inside the chain.  An attacker who rewrites the
   final entry's content without changing the entry count produces a
   chain that still verifies.  A commitment that records the final entry
   digest detects this; a commitment that records only the count does
   not.

   To make such commitments interoperable, a deployment MAY publish a
   chain commitment: a JSON document separate from the chain with the
   following members:

   job_id: the job identifier the timeline binds, a string matching the
   job_id of every entry in the timeline.

   final_entry_digest: the lowercase hex-encoded SHA-256 entry digest of
   the timeline's last entry, recomputed as in Section 7.1, a string of
   64 lowercase hexadecimal characters.

   entry_count: the number of entries in the timeline, a JSON number
   with an integer value.

   published_at: the time the commitment was published, an RFC 3339
   timestamp denoting a valid calendar date and time.

   The commitment MUST be published outside the chain: it binds the
   digest of the final entry, and recording it inside the final entry
   would be circular.  A verifier checks a chain commitment by
   recomputing the final entry digest as in Section 7.1 and comparing it
   with final_entry_digest, comparing entry_count with the number of
   entries in the timeline, and confirming job_id matches the timeline's
   job identifier.  The conformance kit implements this check; a
   commitment that fails it MUST NOT be presented as binding the
   timeline.

   As with receipts, chaining provides tamper evidence for the sequence,
   not truth about the world.  A chained entry with LOGGED BY AGENT
   provenance remains a chained report; the chain upgrades nothing about
   what the entry attests.  A public page resolving the whole timeline
   reports whether the visible chain verifies.

Zambo                     Expires 22 April 2027                [Page 25]
Internet-Draft                    AER-1                     October 2026

7.4.  Versioning

   The construction in this section is the -10 chain construction, which
   is identical to the -07/-08/-09 construction; the -11, -12, -13, and
   -14 revisions change no chain verification rule.  The -10 revision
   precisely specifies the Section 7.1 string escaping; it changes no
   verification rule.  The -08 revision adds guidance in Section 7.3
   that the external truncation commitment SHOULD bind the final entry
   digest; it changes no verification rule.  The -09 revision defines
   the optional chain commitment artifact in Section 7.3, which the
   conformance kit verifies; it changes no chain verification rule.  The
   -07 construction differs from the -06 construction, whose entry
   digest covered only the base64-decoded canonical_bytes.  A verifier
   MUST distinguish the -06 construction from the -07/-08/-09/-10/-11/-
   12/-13/-14 construction: a timeline that verifies under the -06
   construction MUST NOT be reported as verifying under the -07/-08/-
   09/-10/-11/-12/-13/-14 construction.  The -06 construction is
   retained for historical chains only; new timelines MUST use the -07/-
   08/-09/-10/-11/-12/-13/-14 construction, and historical -06 chains
   MUST be labeled historical and MUST NOT verify as current.

8.  Workflow Receipts

   A single execution receipt (Section 3) records one tool call.  When
   an agent performs several tool calls toward one goal, the sequence
   itself needs a verifiable record.  A workflow receipt binds an
   ordered list of step receipts to a single goal, with a Merkle root
   over the step sequence and an output hash for the workflow's final
   result.

   A workflow receipt is a JSON object with the following members.  This
   is the smallest useful interoperable shape; implementations MAY add
   fields, but additions MUST NOT make the core identity or verification
   fields ambiguous.

   +========================+==========+===============================+
   | Field                  | Required | Meaning                       |
   +========================+==========+===============================+
   | type                   | MUST     | "verifiable-workflow-         |
   |                        |          | receipt".                     |
   +------------------------+----------+-------------------------------+
   | version                | MUST     | Workflow receipt schema       |
   |                        |          | version. "1" in the           |
   |                        |          | reference implementation.     |
   +------------------------+----------+-------------------------------+
   | workflow_id            | MUST     | Stable UUID identifying the   |
   |                        |          | workflow.                     |
   +------------------------+----------+-------------------------------+

Zambo                     Expires 22 April 2027                [Page 26]
Internet-Draft                    AER-1                     October 2026

   | receipt_id             | MUST     | Stable UUID identifying this  |
   |                        |          | workflow receipt record.      |
   |                        |          | Distinct from workflow_id.    |
   +------------------------+----------+-------------------------------+
   | session_id             | MUST     | Identifier for the session    |
   |                        |          | that produced the workflow.   |
   +------------------------+----------+-------------------------------+
   | goal                   | MUST     | Human-readable description    |
   |                        |          | of the goal the workflow      |
   |                        |          | pursued.                      |
   +------------------------+----------+-------------------------------+
   | status                 | MUST     | Overall workflow status,      |
   |                        |          | for example "ok" or "error".  |
   +------------------------+----------+-------------------------------+
   | steps                  | MUST     | Non-empty ordered array       |
   |                        |          | of step objects (see          |
   |                        |          | below), ordered by            |
   |                        |          | execution sequence.  An       |
   |                        |          | empty array MUST be           |
   |                        |          | rejected by a verifier.       |
   +------------------------+----------+-------------------------------+
   | merkle_root            | MUST     | Hex-encoded SHA-256 Merkle    |
   |                        |          | root over the ordered step    |
   |                        |          | receipt identifiers           |
   |                        |          | (Section 8.1).                |
   +------------------------+----------+-------------------------------+
   | output_hash            | MUST     | Hex-encoded SHA-256 digest    |
   |                        |          | of the workflow's final       |
   |                        |          | output bytes                  |
   |                        |          | (Section 8.1).                |
   +------------------------+----------+-------------------------------+
   | verify_url             | MUST     | Stable public URL where the   |
   |                        |          | workflow receipt can be       |
   |                        |          | retrieved and checked         |
   |                        |          | without an account, wallet,   |
   |                        |          | or token.                     |
   +------------------------+----------+-------------------------------+

   Table 2: Workflow receipt members

   Each step object in the steps array has the following members:

Zambo                     Expires 22 April 2027                [Page 27]
Internet-Draft                    AER-1                     October 2026

   +========================+==========+===============================+
   | Field                  | Required | Meaning                       |
   +========================+==========+===============================+
   | seq                    | MUST     | 1-based sequence number       |
   |                        |          | within the workflow,          |
   |                        |          | starting at 1 with no gaps.   |
   +------------------------+----------+-------------------------------+
   | tool                   | MUST     | Name of the tool invoked for  |
   |                        |          | this step.                    |
   +------------------------+----------+-------------------------------+
   | receipt_id             | MUST     | UUID of the execution         |
   |                        |          | receipt for this step         |
   |                        |          | (Section 3).                  |
   +------------------------+----------+-------------------------------+
   | receipt_hash           | MUST     | Hex-encoded SHA-256 digest    |
   |                        |          | of the canonical bytes of   |
   |                        |          | the step receipt (the same   |
   |                        |          | bytes verified in             |
   |                        |          | Section 6), as retrieved      |
   |                        |          | at workflow assembly time.    |
   +------------------------+----------+-------------------------------+
   | started_at             | MUST     | Timestamp when the step       |
   |                        |          | began, in RFC 3339 format.    |
   +------------------------+----------+-------------------------------+
   | ended_at               | MUST     | Timestamp when the step       |
   |                        |          | completed, in RFC 3339        |
   |                        |          | format.                       |
   +------------------------+----------+-------------------------------+
   | status                 | MUST     | Step status, for example      |
   |                        |          | "ok" or "error".              |
   +------------------------+----------+-------------------------------+
   | receipt_url            | OPTIONAL | Public URL where the step     |
   |                        |          | receipt can be retrieved.     |
   +------------------------+----------+-------------------------------+

   Table 3: Workflow step members

   The public URL is not a stored member beyond verify_url; it is a
   resolution rule.  Every workflow receipt MUST be retrievable at its
   verify_url without an account, wallet, or token, as specified for
   execution receipts in Section 9.  In the reference implementation the
   URL is https://zambo.dev/workflow/<workflow_id>.

   Example: the following shows the core fields of a real workflow
   receipt issued by the reference implementation (workflow_id 42a3c2cf-
   2cdd-5b8a-aced-016e5a2fb634, goal "get BTC price", five steps).  The
   complete record is published at https://zambo.dev/workflow/42a3c2cf-
   2cdd-5b8a-aced-016e5a2fb634.

Zambo                     Expires 22 April 2027                [Page 28]
Internet-Draft                    AER-1                     October 2026

   {
     "type": "verifiable-workflow-receipt",
     "version": "1",
     "workflow_id": "42a3c2cf-2cdd-5b8a-aced-016e5a2fb634",
     "receipt_id": "442243d2-9c32-53f7-817e-2def28fa5b07",
     "session_id": "receipt-test-001",
     "goal": "get BTC price",
     "status": "ok",
     "steps": [
       {
         "seq": 1,
         "tool": "zambo_universal",
         "receipt_id": "e80168eb-a6a1-4ec9-8478-ac108f9397ff",
         "receipt_hash":
     "11c3a071051a42cbf5cf4da60a7577b1dffeb0419e6dd8a258b19c4c0d0d108e",
         "started_at": "2026-09-29T10:57:40.911Z",
         "ended_at": "2026-09-29T10:57:41.147Z",
         "status": "ok"
       },
       {
         "seq": 2,
         "tool": "zambo_universal",
         "receipt_id": "514fe841-bbdd-4804-9ef4-6828842d8763",
         "receipt_hash":
     "68e3bcad3f46218672fd7ef7bf32f4a7089937dda2b8ade3cfe1050cec856285",
         "started_at": "2026-09-29T10:57:42.920Z",
         "ended_at": "2026-09-29T10:57:43.069Z",
         "status": "ok"
       },
       {
         "seq": 3,
         "tool": "zambo_universal",
         "receipt_id": "a090bdad-f2cf-48c9-bc89-e9e17700fb15",
         "receipt_hash":
     "3da48b2d392fb79ed78f7ed0cc8e6c122fc1089947ff6d7f829748d7745840dd",
         "started_at": "2026-09-29T10:57:45.415Z",
         "ended_at": "2026-09-29T10:57:45.564Z",
         "status": "ok"
       },
       {
         "seq": 4,
         "tool": "zambo_universal",
         "receipt_id": "bf88a036-416b-456a-8e82-8c0991811d68",
         "receipt_hash":
     "0f024f209392b918909df5478aadd3a9189520d74cfdf78e2ccf51b9f075f926",
         "started_at": "2026-09-29T10:57:48.459Z",
         "ended_at": "2026-09-29T10:57:48.605Z",
         "status": "ok"

Zambo                     Expires 22 April 2027                [Page 29]
Internet-Draft                    AER-1                     October 2026

       },
       {
         "seq": 5,
         "tool": "zambo_universal",
         "receipt_id": "ae795bf0-27f8-4cf2-8aef-3f8142b77217",
         "receipt_hash":
     "f52d9c03605047ad0ac347e5e9cbc0e2e197a009d8ee5c7d775f86f360eca963",
         "started_at": "2026-09-29T10:57:55.227Z",
         "ended_at": "2026-09-29T10:57:55.434Z",
         "status": "ok"
       }
     ],
     "merkle_root":
     "7c4817ca249edfeae259b98abf63ed38a31d9dbeebf5ee23139410a7a7f63b37",
     "output_hash":
     "16566e46433dd9a00e4437873102531be71fbae3872db8888b7ddc9282d90f54",
     "verify_url":
      "https://zambo.dev/workflow/42a3c2cf-2cdd-5b8a-aced-016e5a2fb634"
   }

   The merkle_root above recomputes from the five step receipt_id values
   with the Section 8.1 construction: the leaf for each step is SHA-256
   over the UTF-8 bytes of its receipt_id string, paired and hashed up
   the tree with last-duplication on odd levels.  The complete live
   record remains published at the verify_url above.

8.1.  Merkle Root and Output Hash

   The merkle_root binds the ordered step sequence so that insertion,
   deletion, reordering, or substitution of steps is detectable by
   recomputation.  It is a lowercase hex-encoded SHA-256 digest computed
   over the ordered step receipt identifiers.

   The Merkle tree construction is a binary Merkle tree, specified as
   follows:

   1.  For each step in order, compute the leaf digest as SHA-256 over
       the UTF-8 bytes of the step's receipt_id string.

   2.  Pair adjacent digests in order; for each pair, compute SHA-256
       over the concatenation of the two 32-byte digests.  If the number
       of digests at any level is odd, duplicate the last digest before
       pairing.

   3.  Repeat step 2 on the resulting digests until one digest remains.
       Hex-encode that digest in lowercase; this is the merkle_root.

Zambo                     Expires 22 April 2027                [Page 30]
Internet-Draft                    AER-1                     October 2026

   With a single step, the leaf digest is the merkle_root; no pairing
   occurs.  (The steps array is always non-empty per Section 8.)

   An implementation MUST use the construction specified above.  The
   alternative-construction permission from earlier revisions is
   removed: permitting divergent constructions allows different Merkle
   roots for the same workflow, which breaks cross-implementation
   verification of the step sequence.  The construction in this section
   is the only permitted one; a verifier recomputes the root from the
   steps array alone.

   The output_hash is a lowercase hex-encoded SHA-256 digest of the
   canonical bytes representing the workflow's final output.  The
   producer MUST define and publish the exact byte layout used (for
   example, the canonical JSON of a documented final-output document) at
   the verify_url.  If the producer publishes no layout, the bytes are
   the Section 7.1 serialization of {"output": <final-output>}. A
   verifier that cannot obtain or reproduce those bytes
   deterministically from published artifacts alone MUST NOT report the
   output hash as confirmed.

   A verifier recomputes each step's receipt_hash from the step receipt
   retrieved in Section 8.2 step 2 and MUST report a mismatch as a step-
   binding failure, distinct from a Merkle root failure.

8.2.  Workflow Verification Procedure

   To verify a workflow receipt, a verifier performs the following
   steps:

   1.  Resolve the verify_url and confirm the workflow_id in the
       retrieved record matches the requested workflow.

   2.  For each step in the steps array, in order, retrieve the step's
       receipt: at the step's receipt_url when present, otherwise at the
       publisher's documented URL scheme for step receipts, and run the
       Section 6 verification procedure on the step receipt.  A verifier
       that cannot locate a step receipt MUST NOT report the workflow
       receipt as verified.  Every step receipt MUST verify
       independently; a workflow receipt MUST NOT be reported as
       verified if any constituent step receipt fails verification.

   3.  Confirm the steps array is ordered by seq starting from 1 with no
       gaps and no duplicate sequence numbers.  Confirm that no two
       steps carry the same receipt_id value.  A verifier MUST reject a
       workflow receipt whose steps array contains the same receipt_id
       value more than once.

Zambo                     Expires 22 April 2027                [Page 31]
Internet-Draft                    AER-1                     October 2026

       This rule is structural, not cosmetic.  With the Section 8.1
       odd-level duplication rule, the step list [r1, r2, r3, r4, r5]
       and the step list [r1, r2, r3, r4, r5, r5] recompute to the
       identical Merkle root, so the root comparison in step 4 cannot
       distinguish them.  Rejecting duplicate receipt_id values closes
       this collision class at the verification layer.  For the
       Section 8 example workflow, the six-step list that repeats
       the fifth step's receipt_id recomputes to the identical root
       (7c4817ca...f63b37); the conformance corpus carries that
       pair as the isolating vector for this rule.

   4.  Recompute the merkle_root from the ordered step receipt_id values
       using the construction documented for the receipt (Section 8.1),
       and compare it to the published merkle_root.

   5.  Review the goal, status, timestamps, and output hash separately
       from the structural checks.

   6.  Report only what the stored observations support.  A passing
       Merkle root confirms the step sequence is intact as recorded; it
       does not confirm anything the individual step receipts did not
       observe.  Provenance classes (Section 5) apply per step; the
       workflow receipt does not upgrade the provenance of its steps.

   A machine-readable verifier SHOULD expose the same procedure over
   HTTP, returning the workflow identifier, verification status, the
   per-step outcomes, and the Merkle root check result, and signaling
   failure with a non-success status when the record does not verify.

8.3.  Bidirectional Linking Between Steps and Workflows

   When a step receipt belongs to a workflow, the step receipt's public
   page MUST reference the parent workflow, and the workflow receipt
   MUST reference each constituent step receipt.  This lets a reviewer
   start from any single action and reach the full goal context, or
   start from the goal and drill into any individual action, without
   needing session identifiers or internal system knowledge.

   Specifically:

Zambo                     Expires 22 April 2027                [Page 32]
Internet-Draft                    AER-1                     October 2026

   *  The public page for a step receipt that is part of a workflow
      SHOULD display a reference to the parent workflow, including a
      link to the workflow's verify_url.  In the reference
      implementation this appears as "Part of workflow" with a link to
      https://zambo.dev/workflow/<workflow_id>.  Whether or not the page
      displays such a reference, any published step-to-workflow linkage
      MUST be byte-testable: the referenced workflow receipt's steps
      array MUST include that step's receipt_id, as required in the next
      bullet, and a verifier resolving the workflow's verify_url MUST be
      able to reach the step receipt by that receipt_id.

   *  The workflow receipt's steps array MUST include the receipt_id of
      every step in the workflow, and the public workflow page SHOULD
      link each step entry to its receipt page.

   *  A step receipt that is not part of any workflow MUST NOT display a
      workflow reference.  The absence of the link is not an error and
      MUST NOT be treated as a verification failure.

   Linking is presentational and navigational; it does not alter the
   receipt bytes, the output commitment, or the Merkle root.  Adding or
   removing a link MUST NOT invalidate verification.

8.4.  What the Merkle Root Does Not Prove

   Recomputation detects insertion, deletion, reordering, and
   substitution of steps only when the attacker cannot rebuild the root.
   An attacker who removes steps from the steps array and recomputes a
   complete, valid Merkle root over the shorter list produces a workflow
   receipt that verifies under Section 8.2: the Merkle root alone cannot
   distinguish a rebuilt truncation from a workflow that genuinely
   contained fewer steps.  This is the same honest limit stated for hash
   chains in Section 7.3, applied to the step sequence.

   Truncation resistance for a workflow needs a commitment outside the
   receipt: an external anchor binding the merkle_root (Section 10), or
   a workflow manifest published before execution that binds the
   expected step list or step count.  Deployments that need to detect
   step truncation MUST publish such a commitment and verify the
   workflow receipt against it.  The Merkle root check alone MUST NOT be
   presented as truncation-proof.

   That commitment SHOULD bind the merkle_root itself, not merely the
   expected step count.  As with chain commitments (Section 7.3), a
   count-only commitment does not detect content substitution within the
   same count.  A verifier checks a workflow anchor by recomputing the
   merkle_root as in Section 8.1 and comparing it with the anchored
   value, as specified in Section 10.

Zambo                     Expires 22 April 2027                [Page 33]
Internet-Draft                    AER-1                     October 2026

8.5.  Workflow Close Tool

   The reference implementation provides a workflow_close tool that
   seals a session's workflow and issues the workflow receipt described
   in Section 8.

   The tool takes a single input: _session_id, the session identifier
   grouping the workflow's steps.

   The tool returns a JSON object with the following members:

   *  workflow_id: Stable UUID identifying the workflow.

   *  count: Number of step receipts in the workflow.

   *  merkle_root: Hex-encoded SHA-256 Merkle root over the ordered step
      receipt identifiers, computed as in Section 8.1.

   *  children: Ordered array of objects, each with id (the step receipt
      UUID) and output_hash (hex-encoded SHA-256 digest of the step's
      output bytes).

   *  message: Human-readable confirmation, for example "recorded 3
      receipts for this session".

   *  verification_status: Always "not_verified" for the summary itself.
      The summary records; it does not verify.

   *  issuer_authenticated: Boolean indicating whether the issuer was
      authenticated.

   The tool is idempotent on data: repeated invocations return the same
   count, merkle_root, and children.  Each invocation mints its own
   execution receipt, as the close action is itself a recorded tool
   call.  The summary receipt is excluded from the workflow's step count
   (the meta-receipt rule): a workflow_close receipt never appears in
   its own workflow's steps array.

8.6.  Workflow Metadata in Step Receipts

   Each execution receipt that is part of a workflow carries a workflow
   object with the following members:

   *  id: The workflow_id UUID.

   *  url: Stable public URL where the workflow can be retrieved,
      https://zambo.dev/workflow/<workflow_id>.

Zambo                     Expires 22 April 2027                [Page 34]
Internet-Draft                    AER-1                     October 2026

   *  step_index: Zero-based position of this receipt in the workflow's
      execution order.

   The workflow_id is unbound metadata: it is NOT included in the
   receipt's canonical_bytes and does not affect the output_hash.  The
   authoritative binding of workflow membership is the workflow_close
   summary receipt's children array together with the merkle_root
   (Section 8.5).

8.7.  Workflow View API

   The workflow receipt and its steps are retrievable as JSON at:

      GET /api/workflow/<workflow_id>

   Both the workflow_id and the id forms resolve identically.

   The response is a JSON object with the following members:

   *  id: The workflow_id.

   *  workflow_id: Same as id.

   *  session_hash: Hex-encoded SHA-256 hash of the session identifier.

   *  count: Number of step receipts in the workflow.

   *  first_at: RFC 3339 timestamp of the earliest step.

   *  last_at: RFC 3339 timestamp of the latest step.

   *  merkle_root: Hex-encoded SHA-256 Merkle root over the ordered step
      receipt identifiers (Section 8.1).

   *  receipts: Ordered array of step receipt objects, each with id,
      tool, status, timestamp (RFC 3339), receipt_url, output_hash (hex-
      encoded SHA-256), and step_index (zero-based).

   The workflow view excludes workflow_close summary receipts per the
   meta-receipt rule (Section 8.5).

9.  Public Resolution

   Every receipt MUST be retrievable at its public URL without an
   account, wallet, or token.  The URL is stable: once published, the
   record at that URL MUST NOT be altered.  Corrections are published as
   new receipts that carry the superseded id in the supersedes member;
   they MUST NOT rewrite history at the original URL.

Zambo                     Expires 22 April 2027                [Page 35]
Internet-Draft                    AER-1                     October 2026

   The public page SHOULD present the receipt fields, the provenance
   class, the verification outcome, and the hash chain position in
   human-readable form alongside the raw JSON.

10.  External Anchoring

   A receipt MAY be bound to one or more external anchors after
   issuance.  Anchoring is additive: it does not alter the receipt bytes
   and MUST NOT invalidate the output commitment.

   An anchor is a JSON object with the following members:

   +========================+==========+===============================+
   | Field                  | Required | Meaning                       |
   +========================+==========+===============================+
   | type                   | MUST     | "aer1-anchor".                |
   +------------------------+----------+-------------------------------+
   | version                | MUST     | Anchor schema version. "1"    |
   |                        |          | in this specification.        |
   +------------------------+----------+-------------------------------+
   | receipt_id             | MUST     | Identifier of the anchored    |
   |                        |          | record.  For a single        |
   |                        |          | receipt, the receipt's id     |
   |                        |          | member (Section 3).  For a    |
   |                        |          | workflow receipt, the         |
   |                        |          | workflow receipt's            |
   |                        |          | receipt_id member             |
   |                        |          | (Section 8); this is the      |
   |                        |          | record identifier, not the    |
   |                        |          | workflow_id.  For a job       |
   |                        |          | timeline, the job_id of the   |
   |                        |          | chain commitment              |
   |                        |          | (Section 7.3).                |
   +------------------------+----------+-------------------------------+
   | anchored_digest        | MUST     | The anchored digest as 64     |
   |                        |          | lowercase hexadecimal         |
   |                        |          | characters, with no           |
   |                        |          | algorithm prefix.  For a      |
   |                        |          | single receipt: the hex       |
   |                        |          | digest carried by the         |
   |                        |          | output_hash member            |
   |                        |          | (Section 3), i.e. the         |
   |                        |          | output_hash value with the    |
   |                        |          | leading 'sha256:' removed.    |
   |                        |          | For a workflow receipt: the   |
   |                        |          | merkle_root value             |
   |                        |          | (Section 8.1).  For a job     |
   |                        |          | timeline: the                 |

Zambo                     Expires 22 April 2027                [Page 36]
Internet-Draft                    AER-1                     October 2026

   |                        |          | final_entry_digest of the     |
   |                        |          | chain commitment (Section     |
   |                        |          | 7.3).                         |
   +------------------------+----------+-------------------------------+
   | anchor_type            | MUST     | One of "nostr", "ots",        |
   |                        |          | "witness", "scitt", or        |
   |                        |          | "rfc3161".  See below.        |
   +------------------------+----------+-------------------------------+
   | anchored_at            | MUST     | RFC 3339 timestamp of         |
   |                        |          | anchor publication.           |
   +------------------------+----------+-------------------------------+
   | proof                  | MUST     | Anchor-type-specific proof    |
   |                        |          | object (see below).           |
   +------------------------+----------+-------------------------------+
   | record_url             | OPTIONAL | Public URL where the anchored |
   |                        |          | record can be retrieved.      |
   +------------------------+----------+-------------------------------+

   Table 4: Anchor members

   The proof object for anchor_type "nostr" carries: event_id (the Nostr
   event identifier, 64 lowercase hex characters), pubkey (the
   publisher's public key, 64 lowercase hex characters), and relays (an
   array of relay URLs where the event was published, each a non-empty
   string).

   The proof object for anchor_type "ots" carries: ots_proof (a
   base64-encoded OpenTimestamps proof) or ots_request (a base64-encoded
   pending OTS request, with status "pending").

   The proof object for anchor_type "witness" carries: witness_url (a
   stable public URL where the witness record can be retrieved without
   an account) and witness_statement (a human-readable description of
   what the witness attests).

   The proof object for anchor_type "scitt" carries: service (the URL of
   the SCITT Transparency Service with which the anchored_digest was
   registered as the payload digest of a Signed Statement [RFC9943]) and
   cose_receipt (a base64-encoded COSE receipt: the inclusion proof the
   service returned for that registration).

   The proof object for anchor_type "rfc3161" carries: timestamp_token
   (a base64-encoded DER TimeStampToken issued by an RFC 3161 timestamp
   authority over the anchored_digest) [RFC3161].

   The anchored_digest member has the lexical form anchored-digest =
   64HEXDIG, with the lowercase restriction stated for digest strings in
   Section 3.

Zambo                     Expires 22 April 2027                [Page 37]
Internet-Draft                    AER-1                     October 2026

   Privacy bound.  An anchor MUST NOT contain step content, tool inputs,
   tool outputs, canonical bytes, or any data beyond the members in
   Table 4.  The anchored_digest is a hash; hashes of low-entropy or
   guessable inputs may be vulnerable to dictionary attacks, and
   verifiers and publishers MUST NOT treat anchoring as a
   confidentiality mechanism.

   What anchoring proves.  A verified anchor proves that the
   anchored_digest existed no later than the anchor's publication time.
   The proof lives on infrastructure outside the receipt itself: Nostr
   relays, the Bitcoin blockchain, or a witness's publication point.
   Verification confirms the proof is present on that infrastructure and
   is correctly signed against proof.pubkey.  It does not establish who
   controls the signing key.  A verifier MUST NOT present a verified
   anchor as proof that the witness is independent of the receipt
   publisher unless that independence is established out of band (for
   example, a well-known witness key or a key the verifier already
   trusts).  A "witness" anchor whose witness record is publisher-
   controlled provides no independent witnessing; it binds only the
   digest to the publisher's own statement at the anchor time.
   Anchoring does not prove the receipt's content was correct,
   authorized, or truthful; it does not prove the publisher's identity
   beyond what the anchor_type's own authentication provides; and it
   does not by itself prove the absence of truncation (Section 7.3,
   Section 8.4) unless the verifier also confirms the anchored digest
   matches a recomputation over the complete record.

   Anchor discovery.  Anchor references are published alongside the
   receipt at its public URL (Section 9) or at a documented anchor index
   keyed by receipt_id, outside the frozen receipt bytes: adding an
   anchor reference to the public page is presentational (Section 8.3)
   and does not alter the published record.  A verifier obtains the
   anchor references from that location before running the Section 10.1
   procedure; a receipt for which no anchors are published verifies
   without anchor checks.

10.1.  Anchor Verification Procedure

   To verify an anchor, a verifier performs the following steps:

   1.  Confirm the anchor's receipt_id matches the identifier of the
       record being verified per Table 4: the receipt id for a single
       receipt, the workflow receipt_id for a workflow receipt, or the
       chain commitment job_id for a job timeline.

   2.  Recompute the expected digest: for a single receipt, the hex
       digest carried by output_hash (with the "sha256:" prefix removed)
       per Section 6; for a workflow receipt, the merkle_root per

Zambo                     Expires 22 April 2027                [Page 38]
Internet-Draft                    AER-1                     October 2026

       Section 8.1; for a chain, the final_entry_digest per Section 7.3.
       Compare it with anchored_digest.  A mismatch MUST cause anchor
       verification to fail.

   3.  Verify the proof according to its anchor_type: for "nostr",
       resolve the event_id at one or more of the listed relays, verify
       the event's Nostr signature against proof.pubkey, and confirm the
       event content carries the same receipt_id and anchored_digest;
       for "ots", verify the timestamp proof against the Bitcoin block
       header it commits to; for "witness", retrieve the witness_url and
       confirm the retrieved statement contains the anchored_digest
       string verbatim; for "scitt", verify the COSE receipt against the
       Transparency Service's published key and confirm the registered
       statement's payload digest equals anchored_digest; for "rfc3161",
       validate the TimeStampToken and confirm its message imprint is
       the anchored_digest.

   4.  Report the anchor as verified only if steps 1 through 3 all pass.
       A verified anchor confirms the digest existed at the anchor time;
       it does not upgrade the receipt's provenance class (Section 5).

   A workflow receipt MUST be retrievable by its receipt_id member as
   well as by its workflow_id at its verify_url, so that either
   identifier locates the same record.  When an anchor carries a
   record_url, retrieving that URL MUST return the anchored record, so
   that the anchor reference alone suffices to locate it.

10.2.  Binding Does Not Transfer Claims

   Anchoring a digest (Section 10), including a receipt in a Merkle tree
   or workflow (Section 8), chaining receipts (Section 7), or
   referencing one record from another binds the records for integrity
   checking.  Binding does not transfer claims between the bound
   records, in either direction.  A verified anchor does not make the
   anchored content true, authorized, or correctly recorded; a valid
   receipt bound to an external assertion (for example, a claim about a
   physical outcome) neither proves that assertion nor is invalidated by
   the assertion's falsity; and a container receipt does not upgrade the
   provenance class of its members (Sections 5, 8.2, 10.1).  A verifier
   MUST evaluate each bound record under that record's own verification
   procedure and MUST NOT report a claim as verified solely because it
   is bound to a verified record.

Zambo                     Expires 22 April 2027                [Page 39]
Internet-Draft                    AER-1                     October 2026

11.  Reference Implementation

   A reference implementation of this vocabulary is deployed at the time
   of writing, described at [AER-1-HOME].  The implementation exposes
   the receipt contract through one MCP endpoint and gives successful
   calls a public receipt page:

   *  Tool calls are made over HTTPS as JSON-RPC to
      https://zambo.dev/api/mcp using the tools/call method.  The
      response contains the receipt identity and the public verification
      link.

   *  Each receipt resolves at https://zambo.dev/run/<id> and can be
      opened and checked by anyone, with no account or token.

   *  A verifier endpoint returns the machine-readable verification
      result for a receipt identifier, as described in Section 6.

   The endpoint and the receipt pages are independent live records:
   anyone can reproduce the Section 6 procedure against them today.
   Their availability is a deployment fact, not a standards claim; if
   the deployment moves, the canonical home of this document's latest
   revision is updated accordingly.

   Implementers building against this vocabulary SHOULD start from the
   open conformance kit (see Implementation Status): clone
   https://gitlab.com/rambozambodotdev/zambo, run the conformance runner
   for their language (for example, aer1-implementations/python/
   conformance.py for Python) against the frozen vector corpus, and
   treat byte-identical verdicts as the conformance bar.  The kit
   documents the vector inventory and the reference-producer profile
   boundary that separates a core-valid receipt from one the reference
   producer will emit.

12.  Design Rationale

   AER-1 starts with a narrow record rather than a universal theory of
   agent behavior.  An agent may call several tools, receive information
   from several providers, and hand work to another agent.  A reviewer
   still needs a stable way to identify one execution, understand what
   the system observed, and check whether the published bytes match the
   stated commitment.  The draft keeps those needs separate from claims
   about the outside world.

   The vocabulary is intentionally small because interoperability fails
   when every implementation gives a different name to the same
   boundary.  An identifier locates the record.  A creation time orders
   it.  A tool and caller scope identify the execution context.

Zambo                     Expires 22 April 2027                [Page 40]
Internet-Draft                    AER-1                     October 2026

   Canonical bytes and an output hash make the stored representation
   checkable.  A result preview gives a human a useful first read
   without pretending that a preview is the entire source dataset.

   Provenance is a separate design axis (Section 5).  A system can
   execute a tool itself, observe an action through an integrated
   gateway, or receive a report from another agent.  AER-1 treats these
   as distinct attestations because they are distinct claims, and a
   verifier that cannot tell them apart cannot report honestly.

   On canonicalization: AER-1 preserves the producer's exact bytes and
   carries them explicitly, rather than mandating a canonicalization
   scheme such as the JSON Canonicalization Scheme [RFC8785].  A
   verifier MUST NOT re-serialize the record under a different scheme
   and claim agreement with the commitment.  The cost of this choice is
   stated plainly: digests computed under different canonicalizations do
   not interoperate, so cross-implementation verification requires byte-
   identical canonical content.

   On resolution: AER-1 chooses public URL resolution as the primary
   verification experience, so that checking a receipt needs no key
   distribution and no trust anchor obtained out of band.  The tradeoff
   is availability dependence on the publisher; deployments that cannot
   accept that tradeoff can pair the record with the external anchoring
   in Section 10 or with offline recomputation from the carried
   canonical bytes.

13.  Security Considerations

   A receipt is evidence of what was recorded, not a security boundary
   by itself.  The following considerations apply to implementations:

   *  The output commitment binds the recorded bytes, not the real
      world.  An implementation that records attacker-controlled input
      produces a verifiable receipt of attacker-controlled input.
      Verifiers MUST present the observed result as observed, never as
      independently true.

   *  Canonical bytes MUST be preserved exactly.  Any transformation
      (re-encoding, whitespace normalization, character set conversion)
      between recording and verification breaks the commitment and MUST
      cause verification to fail closed.

Zambo                     Expires 22 April 2027                [Page 41]
Internet-Draft                    AER-1                     October 2026

   *  Public receipt URLs are stable and permanent.  A receipt that
      embeds personal data, credentials, or confidential business
      information in its canonical bytes publishes that data to
      everyone; implementations MUST NOT publish such receipts without
      redacting the sensitive data first.  A receipt cannot be
      unpublished.

   *  Provenance classes are attestations by the recording system about
      itself.  A dishonest recorder can mislabel provenance.  Consumers
      who need stronger guarantees should use the external anchoring in
      Section 10 or bind receipts to independent witness records.

   *  The Section 7 chain digest binds entry metadata (sequence
      position, job identifier, closing flag, receipt identifier, tool
      name, provenance class) so metadata relabeling and cross-job
      splicing are detectable by recomputation.  It does not make the
      chain truncation-proof: a rebuilt shorter chain verifies, so
      deployments that need truncation detection MUST anchor an external
      commitment (Section 7.3) and MUST NOT present the chain check
      alone as sufficient.

   *  The Section 8 Merkle root binds the step sequence so that
      insertion, deletion, reordering, or substitution is detectable by
      recomputation, but it does not make the workflow truncation-proof:
      a rebuilt shorter step list with a recomputed root verifies, so
      deployments that need truncation detection MUST anchor the
      merkle_root externally (Section 8.4, Section 10) and MUST NOT
      present the Merkle check alone as sufficient.

   *  A standalone receipt (Section 3) is not bound to a job, session,
      or principal beyond its own identifier.  A receipt presented as
      evidence for a different execution than the one it records is a
      replay, and this specification provides no standalone-receipt
      replay defense.  Consumers that need replay resistance MUST use
      chained timelines (Section 7, which binds job_id per entry) or
      workflow receipts (Section 8, which binds steps to a workflow_id),
      or bind the receipt identifier to their own session context out of
      band.  A bare receipt proves what was recorded for one execution;
      it does not prove the execution belongs to any particular job.

   *  Anchored digests are public.  SHA-256 of a low-entropy input (a
      boolean, a small number, a value from a guessable set) can be
      reversed by enumeration.  Anchoring a digest does not keep the
      preimage confidential.  Where the committed bytes are sensitive
      but the commitment must be public, use a high-entropy salt or a
      keyed commitment and document the construction; a verifier that
      cannot reproduce the salted bytes MUST NOT report the commitment
      as confirmed (Section 4).

Zambo                     Expires 22 April 2027                [Page 42]
Internet-Draft                    AER-1                     October 2026

   *  The created_at timestamp is asserted by the producer.
      Verification checks its form and that it denotes a valid calendar
      date and time; it does not check that the stated time is the true
      time, and a verifier MUST NOT present created_at as externally
      established time.  The external time evidence for a receipt is its
      anchors (Section 10): a verified anchor proves the anchored digest
      existed no later than the anchor's publication time.  Absent an
      anchor, a receipt carries no trusted time.

   *  A producer can equivocate: present different records, or different
      chain or workflow heads, to different verifiers.  The core record
      does not prevent this.  The mitigations are the stable public URL
      (Section 9), external anchors on third-party infrastructure
      (Section 10) compared against previously anchored values rather
      than against counts alone, and, for deployments that need a
      single-history guarantee, registration with a transparency service
      as a "scitt" anchor (Section 10).

   *  Chain verifiers MUST distinguish the -07/-08/-09/-10/-11/-12/-
      13/-14 construction construction from the historical -06
      construction and MUST NOT report a -06 chain as satisfying the -
      07/-08/-09/-10/-11/-12/-13/-14 construction rules (Section 7.4).

   *  Verification endpoints MUST NOT leak information beyond the
      receipt record itself, and MUST rate-limit verification requests
      to prevent the endpoint from becoming an oracle for probing non-
      public executions.

   *  This specification sets no maximum size for canonical_bytes, steps
      arrays, or job timelines.  Implementations MAY set local size
      limits and reject records exceeding them, but a rejection on size
      grounds MUST be reported as "rejected: size limit" and MUST NOT be
      reported as "verification failed," since the record may verify
      correctly under a higher limit.  Implementations SHOULD document
      their limits alongside the verifier.

   *  For receipts without metadata_hash (schema "0.3" and earlier), the
      output commitment binds the recorded bytes but not the metadata: a
      relabeled copy with identical canonical bytes verifies under
      Section 6.  A forger can also strip metadata_hash and rewrite the
      schema version to "0.3".  Consumers that need tamper-evident
      metadata MUST require metadata_hash (schema "0.4" or later), or
      use chained timelines (Section 7) or workflow receipts
      (Section 8).

   *  The receipt id is an identifier label, not a committed field of
      the output commitment.  Replacing a receipt's id with the id of
      another receipt, every other byte unchanged, does not disturb the

Zambo                     Expires 22 April 2027                [Page 43]
Internet-Draft                    AER-1                     October 2026

      output commitment: the relabeled record verifies under Section 6
      exactly as the original did.  The swap breaks nothing about the
      recorded bytes and proves nothing false about them.  What it
      breaks is the association between the record and the execution its
      presenter claims it documents.  That association is established
      only outside the record: by comparison against an independently
      supplied expected id, or by resolving the id under Section 9 and
      comparing the resolved record's output_hash against the presented
      record's.  A verifier that performs neither check has verified
      bytes, not identity, and MUST NOT report the id as verified.
      Where a receipt carries metadata_hash and a verifier recomputes it
      under Section 6, an id change that leaves metadata_hash untouched
      is detected, because the metadata block of Section 3.1 includes
      the id; a record whose metadata block is recomputed wholesale is
      indistinguishable by any in-record check, which is why the
      external comparison, not another in-record field, is the control
      for the swap.

   *  Issuer authentication is not part of this specification.  Anyone
      can mint a well-formed receipt for any tool name, any provenance
      class, and any bytes; verification proves the recorded bytes were
      not altered after minting, not who minted them and not that the
      minting party was authorized to speak for the named tool.  A
      verifier MUST NOT present a passing check as proof of issuer
      identity.  Consumers that need to bind a receipt to its issuer
      MUST use an out-of-band trust root or a signature scheme
      documented alongside the receipt; this specification defines no
      signature scheme.  Without such binding, the receipt is self-
      asserted as to origin.

14.  IANA Considerations

   This document has no IANA actions.

15.  Related Work

   Action receipts for AI agents are an active area with multiple
   concurrent individual proposals, occupying distinct slots.  The SCITT
   architecture [RFC9943] defines transparency services that register
   signed statements and return inclusion proofs; [NOA] profiles an
   agent action receipt as such a signed statement.  [NELSON] specifies
   authorization receipts: records of what a principal permitted, a
   different record from what executed.  [XAIP], [SAHU], and [VAARA]
   specify signed per-call receipts whose digests are computed over
   canonicalized JSON [RFC8785].  [SHARIF] specifies an agent audit
   trail: an operator-side log format with regulatory mappings and
   transport exports, rather than publicly resolvable per-execution
   records.  [KLASSEN] specifies content profiles that carry verdicts

Zambo                     Expires 22 April 2027                [Page 44]
Internet-Draft                    AER-1                     October 2026

   about outputs and are designed to ride over other record formats.
   Naming these slots is positioning, not endorsement.

   AER-1 composes with the transparency-service slot rather than
   competing with it: an AER-1 anchored_digest MAY be registered with a
   SCITT Transparency Service, and the resulting inclusion proof is
   carried as an anchor of type "scitt" under Section 10.  AER-1 core
   verification neither requires nor is changed by that registration.

   AER-1 differs in three ways.  First, the receipt is identified by a
   UUID and resolved at a stable public URL, with verification offered
   as a public HTTP endpoint rather than offline recomputation.  Second,
   it carries provenance (executed, observed-via-gateway, logged-by-
   agent) as a first-class field, so a verifier can distinguish what the
   recording system did from what it merely recorded.  Third, a
   reference implementation is deployed whose receipts are publicly
   verifiable without an account, key, or token.  AER-1 standardizes the
   narrow per-execution record and its public verification procedure,
   leaving decision semantics, authorization, and settlement bindings to
   other specifications.

16.  Normative References

   [FIPS180-4] National Institute of Standards and Technology, "Secure
   Hash Standard", DOI 10.6028/NIST.FIPS.180-4, FIPS 180-4, August 2015.

   [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
   Requirement Levels", BCP 14, RFC 2119, March 1997, <https://www.rfc-
   editor.org/rfc/rfc2119>.

   [RFC3161] Adams, C., Cain, P., Pinkas, D., and R.  Zuccherato,
   "Internet X.509 Public Key Infrastructure Time-Stamp Protocol (TSP)",
   RFC 3161, August 2001, <https://www.rfc-editor.org/rfc/rfc3161>.

   [RFC3339] Klyne, G. and C.  Newman, "Date and Time on the Internet:
   Timestamps", RFC 3339, July 2002, <https://www.rfc-editor.org/rfc/
   rfc3339>.

   [RFC4122] Leach, P., Mealling, M., and R.  Salz, "A Universally
   Unique IDentifier (UUID) URN Namespace", RFC 4122, July 2005,
   <https://www.rfc-editor.org/rfc/rfc4122>.

   [RFC4648] Josefsson, S., "The Base16, Base32, and Base64 Data
   Encodings", RFC 4648, October 2006, <https://www.rfc-editor.org/rfc/
   rfc4648>.

Zambo                     Expires 22 April 2027                [Page 45]
Internet-Draft                    AER-1                     October 2026

   [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119
   Key Words", BCP 14, RFC 8174, May 2017, <https://www.rfc-
   editor.org/rfc/rfc8174>.

   [RFC8259] Bray, T., Ed., "The JavaScript Object Notation (JSON) Data
   Interchange Format", STD 90, RFC 8259, December 2017,
   <https://www.rfc-editor.org/rfc/rfc8259>.

17.  Informative References

   [AER-1-HOME] Zambo, B., "AER-1: AI Agent Execution Receipt (open
   draft)", https://zambo.dev/aer-1, September 2026.

   [KLASSEN] "draft-klassen-eu2122-content-profile-03", Internet-Draft,
   Work in Progress.

   [NELSON] "draft-nelson-agent-delegation-receipts-12", Internet-Draft,
   Work in Progress.

   [NOA] "draft-noa-scitt-ai-agent-receipt-01", Internet-Draft, Work in
   Progress.

   [RFC5234] Crocker, D., Ed. and P.  Overell, "Augmented BNF for Syntax
   Specifications: ABNF", STD 68, RFC 5234, January 2008,
   <https://www.rfc-editor.org/rfc/rfc5234>.

   [RFC7942] Sheffer, Y. and A.  Farrel, "Improving Awareness of Running
   Code: The Implementation Status Section", BCP 205, RFC 7942, July
   2016, <https://www.rfc-editor.org/rfc/rfc7942>.

   [RFC8785] Rundgren, A., Jordan, B., and S.  Erdtman, "JSON
   Canonicalization Scheme (JCS)", RFC 8785, June 2020,
   <https://www.rfc-editor.org/rfc/rfc8785>.

   [RFC9943] Birkholz, H., et al., "An Architecture for Trustworthy and
   Transparent Digital Supply Chains", RFC 9943, <https://www.rfc-
   editor.org/rfc/rfc9943>.

   [SAHU] "draft-sahu-agent-action-receipts-00", Internet-Draft, Work in
   Progress.

   [SHARIF] "draft-sharif-agent-audit-trail-07", Internet-Draft, Work in
   Progress.

   [VAARA] "draft-sirkkavaara-vaara-receipt-13", Internet-Draft, Work in
   Progress.

Zambo                     Expires 22 April 2027                [Page 46]
Internet-Draft                    AER-1                     October 2026

   [XAIP] "draft-xkumakichi-xaip-receipts-03", Internet-Draft, Work in
   Progress.

18.  Acknowledgments

   Matthew Moore provided the first substantive independent technical
   review of this draft on the agent2agent list, identifying the
   duplicate receipt_id Merkle collision (Section 8.2), the unpinned
   Section 7 chain construction and its suffix-truncation weakness, and
   the stale test-vector count.  The -06 revision folded those findings
   into the specification and the conformance kit.  Moore then ran eight
   chain attacks from the VLC-1 project against the -06 construction and
   showed all eight were accepted, confirming the digest bound too
   little.  The -07 revision hardens the Section 7 entry digest in
   direct response: the digest now binds the entry's sequence position,
   job identifier, closing flag, receipt identifier, tool name, and
   provenance class, and the section states the honest truncation limit
   his testing established.  Moore then cross-tested the -07
   construction with thirty cases from VLC-1, confirming all fourteen
   Section 7 attack cases produced the specified outcomes, and
   identified the last-entry digest gap: the final chain entry's digest
   is referenced by nothing inside the chain, so the external truncation
   commitment should bind it.  The -08 revision adds that guidance to
   Section 7.3.  The -09 revision defines the optional chain commitment
   artifact in Section 7.3 and the conformance kit check that verifies
   it.

   ARION produced the first complete independent implementation of AER-
   1, a zero-dependency Node.js verifier written from the -08 draft text
   alone, and filed three specification findings that the -09 revision
   adopts.

   ColonistOne (CMO of The Colony) produced an independent Perl
   implementation of the -09 draft, verified 68/68 against the
   conformance kit with zero disagreements against either reference
   runner, and filed three specification findings that the -10 revision
   adopts: the under-specified Section 7.1 string escaping (including
   the U+007F divergence between the draft text and the reference
   implementation), the Python-version-dependent timestamp check, and
   nine conformance rules lacking isolating vectors.

   Token Maxxer identified the workflow-receipt truncation gap that the
   -12 revision closes in Section 8.4: the observation that a hash
   chain's honest truncation limit applies equally to the Section 8
   Merkle root, and that the draft's silence on the point was an
   inconsistency.

Zambo                     Expires 22 April 2027                [Page 47]
Internet-Draft                    AER-1                     October 2026

   Leo Oliemans raised the unknown-versus-not-applicable distinction and
   the write/readback outcome gap that the -18 revision addresses in
   Section 3.2.  The agent penny filed the findings behind Section 3.4
   (per-field provenance, the negative record, reversal state, and the
   method descriptor) and the unauthenticated-metadata wording adopted
   in Section 3.2. czh raised the Unicode normalization question
   answered in Section 4, and dumate-scout proposed the
   execution_context invalidation signal noted in Section 3.2.  The -18
   revision folds those reports.

   Iman Schrock of the Emilia Protocol reported that the workflow
   descriptions in Sections 8.5 and 8.7 named step output hashes as the
   Merkle root's leaf input where Section 8.1 specifies step receipt
   identifiers, so the two descriptions give different roots for the
   same workflow.  The -19 revision aligns Sections 8.5 and 8.7 with
   Section 8.1, and the conformance corpus adds the one-step test vector
   the report requested.

   Genesis, an independent agent on The Colony, built a conformance
   verifier from the -19 draft text alone, with no reference
   implementation import, and reported three gaps that the -20 revision
   adopts: the kit quickstart's core tier did not state the provenance-
   label and schema-version metadata checks (now its ninth rule),
   Section 3.3 did not require a stated member ordering rule for
   recorded JSON inputs (now required), and the Section 5 provenance
   labels carried no rule against control characters (now barred, with
   rejection required).

   Gigawatt, an independent reviewer on The Colony, proposed two
   negative controls against the Section 3 example receipt and predicted
   their 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.
   Both controls were run with the published tooling and the outcomes
   published.  The -21 revision adopts the finding: Section 6 states the
   id-binding rule normatively, and Section 13 describes the
   substitution case.

Zambo                     Expires 22 April 2027                [Page 48]
Internet-Draft                    AER-1                     October 2026

   WhiteMagic Labs (Lucas Bailey) built and operates an independent
   production validator for this specification, recorded in the
   Implementation Status.  Exercising it against this draft on
   2026-10-17 produced a same-day exchange of findings in both
   directions: a base64 decoding-boundary defect in the validator, fixed
   by its operator, and a nil-UUID acceptance gap in the reference
   verifier, fixed in the kit (aer1-verify 0.2.9).  A design
   disagreement on expected-id binding was argued and resolved to the
   model Section 6 states, with the operator's provenance caution
   retained as advisory metadata; that discussion is the origin of the
   channel note in Section 6.

   Skitter (SwarmMemo) replayed the verifier case matrix independently
   and filed three findings the -22 revision adopts: a non-canonical
   base64 spelling (a pad-bit flip that decodes byte-identically) which
   the reference verifier accepted and the draft did not address
   (Sections 3 and 4, with a corpus vector), the under-specified legacy
   member set behind the schema 0.3 production shape (Section 6), and
   the bare-versus-enveloped presentation divergence (Section 3).  The
   first two also produced kit fixes ahead of this revision (aer1-verify
   0.2.10).

   Skitter also exercised an independent validator against the corpus
   fixture whose anchor record cannot be resolved and showed that the
   validator's response could not distinguish an anchor it had not
   evaluated from one it had evaluated and failed to resolve: the
   response carried no "not checked" state. a-messenger stated the
   reporting rule the finding implies: "not checked" is not "attempted
   but unresolved".  The -23 revision adopts the rule in Section 6; the
   kit implements it (anchor-vectors.json in the corpus; aer1-verify
   0.2.13) ahead of this text.

   Longcat proposed the enumerated id verdict of Section 6, and then the
   two refinements that make it binding rather than decorative: the
   states MUST bind verifier behavior, with one corpus vector per state,
   and the resolution order between the structural layer and the id
   layer MUST be stated.  Both refinements are adopted. ronin_audit's
   field note, "print the reason next to the rule", is adopted in
   Section 6 as a reporting requirement.

Appendix A.  Mapping Note: EU AI Act Article 12 (Informative)

   This appendix is informative and non-normative.  Article 12 of the EU
   AI Act addresses record-keeping for high-risk AI systems: such
   systems are to be designed so that events are recorded automatically
   over the system's lifetime, at a level of traceability appropriate to
   the intended purpose.  An AER-1 receipt is created automatically at
   execution time and records the execution with a timestamp, the

Zambo                     Expires 22 April 2027                [Page 49]
Internet-Draft                    AER-1                     October 2026

   recorded bytes, and tamper evidence, so a receipt can form part of
   the records such a system keeps.  A receipt alone does not satisfy
   Article 12 or any other legal obligation: what must be recorded, how
   long records are kept, and who may access them are deployment and
   legal questions outside this specification.

Author's Address

   Brennan Zambo
   Zambo
   Email: brennanzambo@zambo.dev
   URI:   https://zambo.dev/aer-1

Zambo                     Expires 22 April 2027                [Page 50]