<?xml version="1.0" encoding="utf-8"?>
<?xml-model href="rfc7991bis.rnc"?>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude"
     docName="draft-saha-stage-receipts-00"
     category="std"
     ipr="trust200902"
     submissionType="IETF"
     tocInclude="true"
     sortRefs="true"
     symRefs="true"
     version="3">

  <front>
    <title abbrev="Stage Receipts">Stage Receipts: A Verifiable Record Format for Staged Pipelines</title>
    <seriesInfo name="Internet-Draft" value="draft-saha-stage-receipts-00"/>
    <author fullname="Shamik Saha" initials="S." surname="Saha">
      <organization>Independent</organization>
      <address>
        <postal>
          <city>Amsterdam</city>
          <country>Netherlands</country>
        </postal>
        <email>shamik.saha.rcciit@gmail.com</email>
      </address>
    </author>
    <date year="2026" month="September" day="8"/>
    <area>sec</area>
    <keyword>provenance</keyword>
    <keyword>pipelines</keyword>
    <keyword>AI agents</keyword>
    <keyword>verification</keyword>
    <keyword>canonical JSON</keyword>

    <abstract>
      <t>A staged pipeline -- a document-ingestion flow, a retrieval-augmented
      generation chain, an agent workflow, a benchmark -- produces results that
      are hard to reproduce, hard to diff between two runs, and hard to
      localize when they go wrong. This document defines the stage receipt: a
      small, canonically serialized JSON record that each stage of such a
      pipeline emits, describing exactly what went in, what came out, under
      which pinned instrument, with which outcome, and linked by digest to the
      receipt before it. A chain of stage receipts lets a developer reproduce a
      run, diff two runs to the first stage that differs, and localize a fault
      to the stage where it entered; the same chain lets an independent party,
      later and offline, establish what the records assert without trusting
      whoever produced them. The document specifies the record, its canonical
      form, the chain manifest, the coverage and emission declarations that
      make a chain honest about its own edges, the anchoring declaration that
      separates consistency from originality, and the behaviour required of a
      conforming verifier. Golden conformance vectors -- records that must be
      accepted and records that must be refused, each with its reason -- are
      part of the specification.</t>
    </abstract>
  </front>

  <middle>

    <section anchor="intro">
      <name>Introduction</name>
      <t>Most pipelines that transform data through several stages keep logs.
      Logs are prose about what happened; they are written for the operator,
      in the operator's vocabulary, and they are only as complete as the
      operator remembered to make them. When a run produces a wrong answer,
      the questions that follow -- which stage changed its output since the
      last good run; can this run be repeated; where exactly did the bad data
      enter; is what is deployed the same thing that was approved -- are
      answered, if at all, by reading logs and guessing.</t>
      <t>A stage receipt is the alternative this document proposes: a record
      each stage emits, in a fixed shape, containing digests of the bytes that
      entered and left it, the identity and pinned version of the component
      that ran, the constants its assertions depend on, its outcome, and the
      digest of the receipt that preceded it. The record is serialized in a
      canonical form so that its digest is the same on every platform, and it
      never contains its own digest, so that the chain rather than the record
      is the proof of its final state.</t>
      <t>The immediate beneficiary is the developer. Given two chains, the
      first receipt whose input digests, instrument version, configuration
      digest or output digest differ is the stage where two runs diverged.
      Given one chain and the pipeline's code, the stages that declare
      themselves re-derivable can be run again from their recorded inputs and
      their outputs compared byte for byte. Given a chain with a bad result,
      the first receipt whose outcome is not "ok", or whose recorded output
      does not match what the next stage consumed, is where the fault entered.
      None of these operations requires trusting the producer, a network, a
      key, or a service.</t>
      <t>The same properties serve a second reader: someone who was not
      present, holds only the records, and needs to establish what they
      assert. This document is careful about what such a reader can and
      cannot establish. A chain whose links all verify is consistent with
      itself; it is not thereby shown to be the chain that was made, because
      an operator holding every copy can rewrite one record and recompute
      every later link. Only anchoring to a commitment the operator cannot
      rewrite converts consistency into originality, and this document
      requires every record to say which of the two it offers.</t>

      <section anchor="scope">
        <name>Scope and Applicability</name>
        <t>This document specifies the receipt (<xref target="receipt"/>),
        its canonical serialization and digest (<xref target="canon"/>), the
        chain manifest (<xref target="chain"/>), the subjects a digest may
        stand for (<xref target="subjects"/>), coverage, emission and anchoring
        declarations (Sections <xref target="coverage" format="counter"/>,
        <xref target="emission" format="counter"/> and <xref target="anchoring"
        format="counter"/>), verifier behaviour (<xref target="verifier"/>),
        conformance (<xref target="conformance"/>) and golden vectors
        (<xref target="vectors"/>).</t>
        <t>This revision applies to linear chains: a run whose stages form a
        sequence, in which each receipt has at most one predecessor and each
        retry of a stage is recorded as a distinct attempt with its own
        receipt. Fan-out, fan-in, branches, loops, compensation and partial
        commits, exactly-once versus at-least-once delivery, out-of-order
        arrival, and an ordering model for stages whose clocks disagree are
        not specified here. They are a recognized requirement of the format
        and the largest thing it does not yet do; a producer whose pipeline
        has such a topology MUST declare the boundary (<xref
        target="coverage"/>) rather than flatten the topology into a sequence
        that did not occur.</t>
        <t>This document does not specify a transport, a storage system, a
        signature envelope, a key lifecycle, an anchoring mechanism, or a
        service. A receipt is bytes in a file; anything that moves or keeps
        those bytes is out of scope provided it does not alter them.</t>
      </section>

      <section anchor="related">
        <name>Relationship to Other Work</name>
        <t>Canonical JSON serialization has been specified before, notably
        the JSON Canonicalization Scheme <xref target="RFC8785"/>. The
        canonical form in this document (<xref target="canon"/>) is
        deliberately narrower: it forbids JSON numbers outright, because a
        format that serializes 500.00 as a number has already lost the
        distinction between "500.00" and "500", and that distinction has cost
        a real defect. A JCS serializer produces the same bytes as this
        document's canonical form for any object that contains no numbers,
        which is every conforming receipt.</t>
        <t>Provenance is an established discipline, and this document is an
        application of it rather than a replacement for it. The PROV data
        model <xref target="PROV-DM"/> describes entities, activities and agents as a graph; a chain
        of receipts is a linear instance of that graph in which every entity
        is identified by the digest of its bytes and every activity by a
        pinned instrument, and a receipt chain can be projected into PROV
        without loss. Lineage-event conventions used by data platforms emit
        run and dataset events to a collecting service; a receipt is instead
        a file whose checkability depends on no service, which <xref
        target="v-constraints"/> requires. Software-supply-chain attestation
        frameworks, of which in-toto <xref target="INTOTO"/> is the
        reference, record, for each build step, digests of the materials
        consumed and the products produced, signed by the party that ran the
        step and checked against a layout that names the expected steps;
        that is the nearest relative of a stage receipt. A receipt applies
        the same idea to a runtime data pipeline and adds what a build step
        does not need: an outcome class in which refusal is a result, a
        coverage declaration that states where the chain does not see, an
        emission policy, an anchor declaration, and trust classes on
        artifacts -- while leaving signatures to a later revision rather than
        making them a precondition of checkability.</t>
        <t>Observability tooling -- traces, spans, metrics and logs -- records
        what a system is doing for the people who operate it, sampled and
        retained for a period, in the operator's vocabulary. A receipt records
        what a run did to specific bytes, unsampled, for a reader who was not
        present and need not trust the operator. The two are complementary,
        and a producer that runs both SHOULD record the trace and span
        identifiers of the stage in the receipt's "assertions" and the
        receipt's digest as an attribute of the span, so that either record
        leads to the other.</t>
        <t>Software bill-of-materials formats describe what a component is
        made of. A receipt's instrument declaration (<xref
        target="instrument"/>) names and pins the component that ran a stage
        and is intended to carry, in a later revision, a per-receipt
        dependency record aligned with those formats; it does not replace
        them.</t>
        <t>Transparency logs and timestamping services provide commitments an
        operator cannot rewrite. This document does not select one; it
        requires a record to declare whether it is anchored to any such
        commitment and, if so, to what (<xref target="anchoring"/>).</t>
        <t>Per-action authorization of agent actions -- whether a proposed
        action may be performed now -- is a decision made before an action
        runs. A stage receipt is a record made after a stage ran. The two
        compose: an authorization decision's evidence can be recorded as an
        input to the stage it governed, and the stage's receipt can be the
        report that closes the decision. Neither depends on the other.</t>
      </section>

      <section anchor="reqlang">
        <name>Requirements Language</name>
        <t>The key words "<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>",
        "<bcp14>REQUIRED</bcp14>", "<bcp14>SHALL</bcp14>", "<bcp14>SHALL
        NOT</bcp14>", "<bcp14>SHOULD</bcp14>", "<bcp14>SHOULD NOT</bcp14>",
        "<bcp14>RECOMMENDED</bcp14>", "<bcp14>NOT RECOMMENDED</bcp14>",
        "<bcp14>MAY</bcp14>", and "<bcp14>OPTIONAL</bcp14>" in this document
        are to be interpreted as described in BCP 14
        <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only
        when, they appear in all capitals, as shown here.</t>
      </section>
    </section>

    <section anchor="terms">
      <name>Terminology</name>
      <dl newline="false" spacing="normal">
        <dt>Run:</dt>
        <dd>One execution of a pipeline, identified by a run identifier chosen
        by the producer.</dd>
        <dt>Stage:</dt>
        <dd>One step of a run that consumes inputs and produces outputs under
        a single instrument. A retry of a stage is a distinct stage
        attempt.</dd>
        <dt>Receipt:</dt>
        <dd>The record a stage emits, as specified in <xref
        target="receipt"/>. "Stage receipt" and "receipt" are used
        interchangeably.</dd>
        <dt>Chain:</dt>
        <dd>The ordered receipts of one run, each linked to its predecessor
        by digest, together with the chain manifest.</dd>
        <dt>Manifest:</dt>
        <dd>The record that lists a chain's receipts, their digests and the
        chain head (<xref target="chain"/>). Distinct from the pipeline
        manifest, below.</dd>
        <dt>Pipeline manifest:</dt>
        <dd>The producer's description of the approved pipeline -- its stages
        and the pinned components expected to run them -- whose digest each
        receipt cites. Its format is not specified here; its digest is.</dd>
        <dt>Instrument:</dt>
        <dd>The component that ran a stage: a converter, a chunker, a
        retriever, a model, a verifier, a benchmark harness. An instrument is
        named and pinned or the stage's receipt is invalid.</dd>
        <dt>Producer:</dt>
        <dd>The party, and by extension the software, that emits
        receipts.</dd>
        <dt>Verifier:</dt>
        <dd>Software that checks receipts and chains against this document,
        reporting PASS, FAIL or NOT RUN for each property (<xref
        target="verifier"/>).</dd>
        <dt>Consumer:</dt>
        <dd>Any reader of receipts other than a verifier: a diff tool, a
        replay tool, a person, a model.</dd>
        <dt>Artifact:</dt>
        <dd>Bytes that entered or left a stage. A receipt carries an
        artifact's digest, size, media type, name and trust class, never the
        artifact itself.</dd>
        <dt>Trust class:</dt>
        <dd>The declared origin of an artifact's content: operator-authored,
        model-generated, or externally-sourced (<xref target="artifacts"/>).</dd>
        <dt>Re-derivable stage:</dt>
        <dd>A stage that, run again from its recorded inputs under its pinned
        instrument, produces the same output bytes. Its receipt is a receipt
        in the full sense.</dd>
        <dt>Declared stage:</dt>
        <dd>A stage that cannot promise repeatability -- a call to a hosted
        model, an external system answering from world state -- whose record
        freezes exactly what went in and came out and says on its face that
        replay is not promised. A declaration is weaker than a receipt and is
        labelled as weaker.</dd>
        <dt>Coverage:</dt>
        <dd>The relation between the stages a run declared it would emit and
        the stages that emitted; and the declared boundaries beyond which the
        chain does not see (<xref target="coverage"/>).</dd>
        <dt>Anchor:</dt>
        <dd>A commitment, outside the producer's control, to a chain head or
        a root over many chain heads, made at a stated cadence (<xref
        target="anchoring"/>).</dd>
        <dt>Digest:</dt>
        <dd>The SHA-256 <xref target="RFC6234"/> hash of a sequence of bytes,
        written as the string "sha256:" followed by 64 lowercase hexadecimal
        digits.</dd>
      </dl>
    </section>

    <section anchor="principles">
      <name>Design Principles</name>
      <t>The rules in later sections follow from a small number of
      principles, stated here so that a case this document does not
      anticipate can be decided the same way.</t>
      <ol spacing="normal">
        <li><t><strong>A record describes itself.</strong> Every receipt
        names its format, its run, its stage, its instrument, the constants
        its assertions depend on, and the zone of every time it carries. A
        reader needs nothing outside the record to know what the record
        claims.</t></li>
        <li><t><strong>Bytes are the record.</strong> A receipt is the exact
        bytes of its canonical serialization, not any equivalent of them. Its
        digest is over those bytes. A verifier compares bytes; it does not
        normalize nearly-canonical bytes into canonical ones.</t></li>
        <li><t><strong>A record never contains its own digest.</strong> A
        record cannot contain the proof of its own final state. The digest
        lives in the next receipt and in the manifest.</t></li>
        <li><t><strong>Absent, declared-none and recorded are three
        states.</strong> A field that is missing, a field that says there is
        nothing, and a field that records something are distinguishable and
        round-trip distinguishably. A failed measurement is not a measured
        zero.</t></li>
        <li><t><strong>A refusal is a result.</strong> A stage that declined
        to produce output records that it declined and why. A format that
        records only successes describes a happy path.</t></li>
        <li><t><strong>What cannot be established is reported, not
        implied.</strong> A verifier has three outcomes, never two. A record
        that is not anchored says so, and a verifier repeats it.</t></li>
        <li><t><strong>Checkability depends on no one.</strong> A conforming
        verifier needs no network, key, account, licence, or live third party.
        Evidence whose checkability needs a living authority inherits that
        authority's lifespan.</t></li>
        <li><t><strong>The verifier does not judge the work.</strong> A
        well-formed record of a wrong answer verifies. Whether the pipeline
        was correct is a question for a different tool, whose output is
        written beside the records and never into them.</t></li>
      </ol>
    </section>

    <section anchor="receipt">
      <name>The Stage Receipt</name>
      <t>A stage receipt is a JSON <xref target="RFC8259"/> object with
      exactly the thirteen members of <xref target="reqtable"/>, serialized in
      canonical form (<xref target="canon"/>). Every one of them is REQUIRED.
      A receipt lacking any of them is invalid.</t>
      <table anchor="reqtable">
        <name>Required members of a stage receipt</name>
        <thead>
          <tr><th>Member</th><th>Type</th><th>Defined in</th></tr>
        </thead>
        <tbody>
          <tr><td>format</td><td>string</td><td><xref target="m-format"/></td></tr>
          <tr><td>run_id</td><td>string</td><td><xref target="m-run"/></td></tr>
          <tr><td>stage</td><td>object</td><td><xref target="m-run"/></td></tr>
          <tr><td>prev</td><td>string or null</td><td><xref target="m-prev"/></td></tr>
          <tr><td>time</td><td>object</td><td><xref target="m-time"/></td></tr>
          <tr><td>coverage</td><td>object</td><td><xref target="coverage"/></td></tr>
          <tr><td>emission</td><td>object</td><td><xref target="emission"/></td></tr>
          <tr><td>anchor</td><td>object</td><td><xref target="anchoring"/></td></tr>
          <tr><td>instrument</td><td>object</td><td><xref target="instrument"/></td></tr>
          <tr><td>inputs</td><td>array</td><td><xref target="artifacts"/></td></tr>
          <tr><td>outputs</td><td>array</td><td><xref target="artifacts"/></td></tr>
          <tr><td>assertions</td><td>object</td><td><xref target="assertions"/></td></tr>
          <tr><td>outcome</td><td>object</td><td><xref target="outcome"/></td></tr>
        </tbody>
      </table>

      <section anchor="values">
        <name>Value Types</name>
        <t>Member values are JSON strings, objects, arrays, or the literal
        null where this document permits it. <strong>JSON numbers MUST NOT
        appear anywhere in a receipt.</strong> Every numeric quantity -- a
        byte count, a stage index, a threshold, a count -- is carried as a
        decimal string, exactly as the producer measured or configured it,
        with its precision intact. This document defines no member whose
        value is a JSON boolean; the members that carry a truth value carry
        the strings "true" and "false".</t>
        <t>Unknown members MAY appear. They are part of the bytes and
        therefore of the digest, but a verifier MUST NOT interpret them and a
        producer MUST NOT rely on them for any semantics this document
        assigns to a defined member. The member names "receipt_digest" and
        "receipt_id" are reserved and MUST NOT appear (<xref
        target="canon"/>).</t>
      </section>

      <section anchor="m-format">
        <name>format</name>
        <t>The string "stage-receipt/0.1". A verifier that encounters a
        different value proceeds as described in <xref
        target="versioning"/>.</t>
      </section>

      <section anchor="m-run">
        <name>run_id and stage</name>
        <t>"run_id" is a non-empty string chosen by the producer, unique
        among that producer's runs. Its structure is not specified.</t>
        <t>"stage" is an object with two REQUIRED members: "index", a decimal
        string giving the receipt's one-based position in the chain, and
        "name", a non-empty string naming the stage. The name of a stage
        SHOULD match the name the pipeline manifest gives it, since coverage
        (<xref target="coverage"/>) is computed over names. A retried stage
        is a new stage attempt with the next index; the producer MAY record
        the attempt number in "assertions" and SHOULD keep the name
        unchanged.</t>
      </section>

      <section anchor="m-prev">
        <name>prev</name>
        <t>The digest of the exact bytes of the preceding receipt in the
        chain, or the literal null for the first receipt of a run. A receipt
        with index "1" MUST carry null; every other receipt MUST carry a
        digest. This member is what makes the chain a chain: editing any
        earlier receipt changes its digest, which breaks the link in every
        later receipt.</t>
      </section>

      <section anchor="m-time">
        <name>time</name>
        <t>An object with two REQUIRED members, "started" and "ended", each a
        timestamp in the Internet profile of ISO 8601 <xref
        target="RFC3339"/> including its UTC offset or the designator "Z".
        A timestamp without its zone is half a timestamp; a verifier MUST
        reject it. Fractional seconds are permitted. "ended" MUST NOT precede
        "started".</t>
        <t>These are the producer's clock readings. Nothing in a receipt
        makes them true; anchoring (<xref target="anchoring"/>) is what lets
        a reader bound when a record existed.</t>
      </section>

      <section anchor="instrument">
        <name>instrument</name>
        <t>An object naming and pinning the component that ran the stage.
        The REQUIRED members are:</t>
        <dl newline="false" spacing="normal">
          <dt>id:</dt>
          <dd>A non-empty string naming the instrument.</dd>
          <dt>kind:</dt>
          <dd>A string classifying it (for example "retriever",
          "cross-encoder", "generator", "verifier"). Values are not
          enumerated by this document.</dd>
          <dt>version:</dt>
          <dd>A non-empty string. A version string that does not identify a
          single, immutable build of the instrument, such as "latest", does
          not pin it; a producer MUST NOT emit one.</dd>
          <dt>manifest_digest:</dt>
          <dd>The digest of the pipeline manifest under which the stage was
          approved to run. A receipt whose "manifest_digest" is empty or
          absent cannot be compared with anything and MUST be refused by a
          verifier; the conforming producer behaviour when the manifest is
          unknown is to refuse to emit, not to emit a blank.</dd>
          <dt>config_digest:</dt>
          <dd>The digest of the instrument's effective configuration for this
          stage, in a serialization the producer documents.</dd>
          <dt>rederivable:</dt>
          <dd>The string "true" if running the stage again from its recorded
          inputs under this instrument produces the same output bytes, or
          "false" if the producer cannot promise that. When "false", the
          member "rederivable_note" SHOULD state why, so that a reader knows
          the record is a declaration (<xref target="terms"/>) and a replay
          tool knows not to attempt it.</dd>
        </dl>
        <t>A record whose instrument cannot be named or pinned is not a weak
        record; it is not a record. The rejection vector R02 (<xref
        target="vectors"/>) exists for this case.</t>
      </section>

      <section anchor="artifacts">
        <name>inputs and outputs</name>
        <t>Each is an array, possibly empty, of artifact references. An empty
        array is a statement that the stage consumed, or produced, nothing --
        the declared-none state of <xref target="principles"/> -- and is
        distinct from the member being absent, which is invalid. The
        third golden receipt records a stage that produced no output and says
        so with an empty array and a "refused" outcome.</t>
        <t>An artifact reference is an object with the REQUIRED members:</t>
        <dl newline="false" spacing="normal">
          <dt>name:</dt>
          <dd>A string naming the artifact within the stage.</dd>
          <dt>media_type:</dt>
          <dd>The artifact's media type as a string.</dd>
          <dt>bytes:</dt>
          <dd>The artifact's size in bytes, as a decimal string.</dd>
          <dt>digest:</dt>
          <dd>The digest of the artifact's stored bytes, computed as <xref
          target="subjects"/> requires for the artifact's kind.</dd>
          <dt>trust_class:</dt>
          <dd>Exactly one of "operator-authored" (content the pipeline's
          operator or its code constructed), "model-generated" (content
          produced by a model), or "externally-sourced" (content that arrived
          from outside the pipeline, including user input and retrieved
          documents). Any other value, or the member's absence, MUST be
          refused.</dd>
        </dl>
        <t>The trust class does not make externally-sourced content safe. It
        makes its origin visible to every downstream reader, human or model,
        which is the most a record format can promise. A consumer that feeds
        artifact content to a model SHOULD carry the trust class with it.</t>
        <t>An output of one stage that is an input of the next SHOULD appear
        in both receipts with the same digest; the difference between the
        two, when there is one, is itself a finding (<xref
        target="localize"/>).</t>
      </section>

      <section anchor="assertions">
        <name>assertions</name>
        <t>An object in which the producer records what the stage asserts
        about its work: counts, thresholds, derived quantities, references to
        corpus manifests, prompt digests. Its members are not enumerated by
        this document, with one exception: if "assertions" is non-empty, it
        MUST contain a member "constants", an object naming every transform
        constant -- tokenizer, join rule, batch size, top-k, threshold,
        offset unit -- on which the other assertions depend. A relation that
        holds only under an unstated constant tests the constant, not the
        relation. The empty object is permitted and means the stage asserts
        nothing beyond its inputs, outputs and outcome.</t>
        <t>A count in "assertions" is testimony unless the receipt states how
        it was derived. A producer SHOULD record the derivation of any
        aggregate (as the fourth golden receipt does for a zero) so that a
        consumer can recompute it rather than believe it.</t>
      </section>

      <section anchor="outcome">
        <name>outcome</name>
        <t>An object whose REQUIRED member "class" is exactly one of:</t>
        <dl newline="false" spacing="normal">
          <dt>ok:</dt>
          <dd>The stage completed and its outputs are what it produced. A
          stage MUST NOT report "ok" for a check it did not perform; if a
          stage's purpose is to check something and the check could not be
          established, the class is "refused" or "error", never "ok".</dd>
          <dt>refused:</dt>
          <dd>The stage declined to produce a result, by its own contract.
          The members "reason" (a string) and, where useful, "detail" SHOULD
          say why. A refusal is a result; the chain continues.</dd>
          <dt>error:</dt>
          <dd>The stage failed. The members "status", "body" and "origin" are
          REQUIRED: what the failing component reported, the body of that
          report, and which component it was. An error without its body is a
          status code wearing an explanation, and a verifier MUST refuse it
          (vector R06).</dd>
        </dl>
        <t>Other members MAY be present. The class is the only member a
        verifier interprets.</t>
      </section>

      <section anchor="effects">
        <name>External Effects</name>
        <t>A stage that acts on the world -- sends a message, writes to an
        external system, places an order -- produces an effect whose state is
        not one of its output bytes. A receipt for such a stage SHOULD carry
        the OPTIONAL member "effects", an array of objects each with the
        REQUIRED members "target" (a string naming the external system) and
        "state", exactly one of "attempted", "returned-a-response", or
        "confirmed-by-the-external-system", and the OPTIONAL member
        "evidence", an artifact reference for the response or confirmation
        bytes.</t>
        <t>These are three states, not one state with three names. "attempted"
        says the request left; "returned-a-response" says something came
        back, whose bytes may be recorded; "confirmed-by-the-external-system"
        says the external system's own record agrees. A consumer MUST NOT
        read the first as the third, and a producer MUST NOT promote a state
        it did not observe. <cref anchor="effects-reread">Marked for re-read
        after the pathology fixtures: the exact evidence a confirmation
        requires is expected to be sharpened by them.</cref></t>
      </section>
    </section>

    <section anchor="canon">
      <name>Canonical Serialization and Digest</name>
      <t>A receipt, a chain manifest, and any other object this document
      digests is serialized in the following canonical form. A file holding
      a receipt contains exactly these bytes and nothing else.</t>
      <ol spacing="normal">
        <li>The encoding is UTF-8 without a byte-order mark.</li>
        <li>Object members are ordered by the Unicode code points of their
        names, ascending, comparing code point by code point.</li>
        <li>No whitespace appears outside string literals.</li>
        <li>No JSON numbers appear. Every numeric value is a decimal string
        (<xref target="values"/>).</li>
        <li>The values NaN, Infinity, negative Infinity and negative zero do
        not exist in this format and cannot be represented.</li>
        <li>String contents are encoded as UTF-8 and are not escaped beyond
        what JSON requires: the quotation mark, the reverse solidus, and the
        control characters U+0000 through U+001F. Non-ASCII characters appear
        as themselves, not as \u escapes.</li>
        <li>The serialization ends with the closing brace of the object. No
        trailing newline, no trailing whitespace.</li>
        <li>The object does not contain the members "receipt_digest" or
        "receipt_id", or any member whose value is the digest of the object
        itself.</li>
      </ol>
      <t>The digest of an object is SHA-256 <xref target="RFC6234"/> over its
      canonical bytes, written as "sha256:" followed by 64 lowercase
      hexadecimal digits. The digest of a file is SHA-256 over the file's
      bytes; for a conforming receipt these are the same thing, and a
      verifier establishes that they are (<xref target="v-serial"/>).</t>
      <t>A serializer that reads a JSON object, sorts its members, and writes
      it without whitespace produces this form, provided it refuses numbers.
      In particular, a serializer conforming to <xref target="RFC8785"/>
      produces identical bytes for any object that satisfies rules 4 and 8.
      The reference canonicalizer published with the golden vectors is
      twenty lines and is the normative statement of this section in
      executable form; where prose and code disagree, the disagreement is a
      defect in this document and the vectors decide.</t>
      <t>Line endings, byte-order marks, path length and file-system
      normalization are named traps. A producer that writes a receipt through
      a text layer that converts line endings has not written a receipt; a
      verifier that reads one through such a layer will report a false
      mismatch. Receipts are read and written as binary.</t>
    </section>

    <section anchor="chain">
      <name>The Chain Manifest</name>
      <t>A run's receipts are listed by a chain manifest: a JSON object in
      canonical form with the REQUIRED members:</t>
      <dl newline="false" spacing="normal">
        <dt>format:</dt>
        <dd>The string "stage-receipt-chain/0.1".</dd>
        <dt>run_id:</dt>
        <dd>The run identifier, equal to that of every receipt listed.</dd>
        <dt>chain:</dt>
        <dd>An array of objects in receipt order, each with the members
        "index" (decimal string), "stage" (the stage name), "file" (a path
        relative to the manifest, using "/" as separator) and "digest" (the
        digest of that file's bytes).</dd>
        <dt>chain_head:</dt>
        <dd>The digest of the last receipt in "chain".</dd>
        <dt>anchor:</dt>
        <dd>An anchor declaration for the chain as a whole, in the form of
        <xref target="anchoring"/>.</dd>
      </dl>
      <t>The manifest MAY carry other members. It is itself digested in
      canonical form when it is anchored or listed by a root over many
      chains.</t>
      <t>The chain is valid when, for every receipt, "prev" equals the digest
      listed for the preceding receipt (null for the first), the listed digest
      equals the digest of the file's bytes, and "chain_head" equals the
      digest of the last receipt. A chain with a missing receipt is not a
      chain with a gap; it is a chain that fails, and the emission
      declaration (<xref target="emission"/>) is how a producer records an
      absence it knew about rather than leaving a verifier to discover
      one.</t>
    </section>

    <section anchor="subjects">
      <name>What a Digest Stands For</name>
      <t>A digest in a receipt is only as meaningful as the rule that says
      which bytes it was computed over. This section fixes that rule for
      each kind of subject. A producer MUST digest each subject as stated and
      MUST record in "assertions.constants" any parameter this section says
      is declared.</t>
      <dl newline="true" spacing="normal">
        <dt>File bytes (binary artifacts: documents, images, packages, model
        weights).</dt>
        <dd>The file exactly as stored, with no transformation of any
        kind.</dd>
        <dt>Text artifacts (converted text, cleaned text, prompts,
        answers).</dt>
        <dd>Normalized once, at write time, to UTF-8 with LF line endings and
        no byte-order mark; written to the store; then digested as file
        bytes. The normalization is done when the artifact is written, never
        when it is verified. A receipt MAY note the normalization so that a
        reader who receives the text through a lossy channel can
        reconstitute the exact bytes.</dd>
        <dt>Chunks and spans (parts of a digested parent).</dt>
        <dd>A chunk's digest is over the UTF-8 bytes of the chunk text under
        the text rule. Its location is a pair of offsets into the parent's
        stored bytes, and the offset unit -- bytes or code points -- MUST be
        declared in "constants". A record that does not name its offset unit
        cannot be checked. A pipeline that records containment lineage
        instead of stored spans -- each chunk names its parent and is
        verifiably a substring of the parent under a declared join rule --
        MUST declare which of the two profiles it uses; the derivation of a
        span at check time is itself a stage with the three outcomes unique,
        ambiguous (with the occurrence count), and not found.</dd>
        <dt>Manifests and other set-valued outputs (chunk sets, ranked
        results, a census).</dt>
        <dd>Serialized in canonical form and digested. Arrays keep the
        stage's declared order -- sequence, rank -- because the order is part
        of what the stage asserts.</dd>
        <dt>Merkle roots (large sets; anchoring many chains).</dt>
        <dd>Leaves are item digests in manifest order; adjacent pairs are
        concatenated as raw 32-byte values and hashed; the process repeats to
        the root. The rule for an odd leaf MUST be declared; the reference
        rule promotes the odd leaf unchanged. Inclusion proofs and a
        tampered-member rejection vector are expected in a later revision
        (<xref target="open"/>).</dd>
        <dt>The receipt itself.</dt>
        <dd>Canonical form including "prev"; the digest is what the next
        receipt's "prev" and the manifest cite.</dd>
        <dt>Wire bytes (external calls: request and response).</dt>
        <dd>The raw bytes as sent and as received, captured at the transport
        boundary, before parsing, re-serialization or pretty-printing. The
        parsed object is not what was received; only the received bytes are
        evidence.</dd>
        <dt>Secrets, credentials and personal data.</dt>
        <dd>Never digested into anything. A digest of a secret is a
        commitment that can never be unwound once published, and a value
        inside a published preimage is frozen the moment the first hash is
        published (<xref target="security"/>).</dd>
      </dl>
    </section>

    <section anchor="coverage">
      <name>Coverage and Boundaries</name>
      <t>"coverage" is an object with the REQUIRED members:</t>
      <dl newline="false" spacing="normal">
        <dt>declared_stages:</dt>
        <dd>The ordered names of the stages the pipeline manifest expects
        the run to emit.</dd>
        <dt>emitting_stages:</dt>
        <dd>The names of the stages that have emitted a receipt in this run,
        as known at the time this receipt was emitted.</dd>
        <dt>boundaries:</dt>
        <dd>An array, possibly empty, of objects each naming a point beyond
        which the chain does not see: a stage that runs outside the
        producer's instrumentation, an upstream system whose output is taken
        on trust, a downstream consumer that is not receipted. Each has the
        REQUIRED members "name" and "kind" (a string; values not enumerated
        here) and MAY carry "note".</dd>
        <dt>completeness:</dt>
        <dd>Exactly one of "complete" or "incomplete". Never absent.</dd>
      </dl>
      <t>"complete" is a claim and a verifier checks it: every declared stage
      MUST appear among the emitting stages, and "boundaries" MUST be empty.
      A receipt that asserts "complete" while a declared stage is missing is
      lying about its own edges, and a verifier MUST fail it (vector R07),
      not warn.</t>
      <t>Coverage is derived by the producer from the manifest and the run,
      never typed by hand. Its purpose is the following rule, which binds
      every consumer of these records: <strong>where coverage is
      "incomplete", no consumer may assert a root cause across an undeclared
      boundary.</strong> A tool that cannot see the edge of its own chart
      will eventually report confidently about something it never observed.
      The claim this document permits a producer to make of a chain is,
      accordingly, bounded: for the receipted portion of a workflow, an
      independent verifier can determine whether the executed topology and
      component versions matched the approved manifest -- and nothing about
      the unreceipted portion.</t>
      <t>A run may legitimately be "incomplete": a pipeline with a
      non-linear region (<xref target="scope"/>) declares it as a boundary
      and receipts the linear portions on either side. That is the honest
      shape. Flattening the region into a sequence that did not run is
      not.</t>
    </section>

    <section anchor="emission">
      <name>Emission Semantics</name>
      <t>"emission" is an object with the REQUIRED members:</t>
      <dl newline="false" spacing="normal">
        <dt>policy:</dt>
        <dd>Exactly one of "fail-closed" (the stage does not run, or its
        result is discarded, if its receipt cannot be written) or
        "fail-open" (the stage runs and its result stands even if its
        receipt cannot be written).</dd>
        <dt>gaps:</dt>
        <dd>An array, possibly empty, of objects each recording a receipt the
        producer knows it failed to write: the REQUIRED members "stage" (the
        name), "index" (decimal string) and "reason" (a string).</dd>
      </dl>
      <t>The policy is chosen by the operator at configuration time and
      MUST be declared; a producer MUST NOT default it. A policy the operator
      did not choose is a policy they cannot be held to.</t>
      <t>Under either policy an absence is recorded as a declared gap, in the
      next receipt that is written and in the manifest. Fail-open does not
      mean that errors disappear; it means the pipeline continued and the
      record says where it did so unreceipted. A gap makes the run's coverage
      "incomplete" (<xref target="coverage"/>) with the gap as a
      boundary.</t>
    </section>

    <section anchor="anchoring">
      <name>Anchoring: Consistency and Originality</name>
      <t>"anchor" is an object with the REQUIRED member "state", exactly one
      of "anchored" or "unanchored". Absence is a failure (vector R08):
      "unanchored" is a state, not a silence.</t>
      <t>When "state" is "unanchored", the member "reason" SHOULD say why.
      When "state" is "anchored", the following members are REQUIRED:</t>
      <dl newline="false" spacing="normal">
        <dt>kind:</dt>
        <dd>A string naming the class of commitment: for example a commit or
        tag in a version-control history the producer does not control, an
        entry in an append-only transparency log (of which <xref target="RFC6962"/> is one kind), a timestamp attestation
        over a root. Values are not enumerated by this document.</dd>
        <dt>reference:</dt>
        <dd>A string by which a reader can locate the commitment.</dd>
        <dt>subject:</dt>
        <dd>The digest that was committed: this chain's head, or a root over
        many chain heads under the Merkle rule of <xref target="subjects"/>,
        in which case "proof" carries the inclusion path.</dd>
        <dt>cadence:</dt>
        <dd>A string stating how often the producer anchors. The cadence is
        the tamper window: a record can be rewritten without detection until
        the next anchor.</dd>
      </dl>
      <t>This section is the most important in the document, and it is
      short because what it says is simple. A chain whose links all verify
      proves that its records are consistent with one another. It does not
      prove that they are the records that were made: an operator who holds
      every copy can rewrite one, recompute every later "prev", and produce a
      chain that verifies. <strong>A hash proves a record is consistent with
      itself, never that it is the record that was made.</strong> Only a
      commitment the operator cannot rewrite converts consistency into
      originality, and only the anchor's cadence bounds how stale that
      conversion is.</t>
      <t>This revision specifies the declaration, not a mechanism. A
      declaration is the part a format can require and a verifier can test.
      Whether a given anchor is in fact unrewritable is a property of the
      system that holds it, is not testable from the records, and is not
      claimed by any conforming producer or verifier. A verifier reports
      originality as NOT RUN on every unanchored record, with that reason,
      so that a green chain can never be read as more than it is.</t>
    </section>

    <section anchor="verifier">
      <name>Verifier Behaviour</name>
      <t>A verifier answers one question: can a stranger, holding only these
      records, establish what they assert, without trusting whoever produced
      them? Everything in this section follows from that, including the
      refusals.</t>

      <section anchor="v-constraints">
        <name>Five Constraints</name>
        <t>A conforming verifier:</t>
        <ol spacing="normal">
          <li>requires no network access -- not for schemas, revocation,
          telemetry, or anything else;</li>
          <li>requires no key, account, or licence;</li>
          <li>requires no live third party;</li>
          <li>is implementable from this document and the golden vectors
          alone; and</li>
          <li>never mutates the records it checks.</li>
        </ol>
        <t>These are not implementation preferences. A verifier that violates
        any of them has re-created the dependence the format exists to
        remove. The publisher of a conforming verifier is correspondingly
        bound: it MUST NOT operate a certificate authority, key escrow, or
        any service on which a record's checkability depends.</t>
      </section>

      <section anchor="v-outcomes">
        <name>Three Outcomes</name>
        <t>For every property it checks, a verifier reports exactly one
        of:</t>
        <dl newline="false" spacing="normal">
          <dt>PASS:</dt>
          <dd>the property was established;</dd>
          <dt>FAIL:</dt>
          <dd>the property was contradicted, and the verifier emits what it
          found;</dd>
          <dt>NOT RUN, with reason:</dt>
          <dd>the property could not be established. The reason is
          REQUIRED; an unexplained skip is a failure of the verifier.</dd>
        </dl>
        <t>A verifier that reports only pass and fail will eventually report
        PASS for something it did not check. A verifier MUST NOT be
        silent about a property this section requires it to check.</t>
      </section>

      <section anchor="v-checks">
        <name>Required Checks</name>
        <section anchor="v-serial">
          <name>Serialization</name>
          <t>The file's bytes are the canonical serialization of the object
          they encode -- identical, not equivalent (vector R10). No JSON
          number appears (R01). The object contains no reserved
          self-referential member (R09).</t>
        </section>
        <section anchor="v-self">
          <name>Self-description</name>
          <t>Every required member is present. The instrument is named and
          pinned (R02). Every non-empty "assertions" names its constants
          (R04). Every timestamp carries its zone (R03). Every artifact
          reference declares a permitted trust class (R05).</t>
        </section>
        <section anchor="v-states">
          <name>States That Must Not Collapse</name>
          <t>The outcome class is one of the three permitted values. An
          "error" outcome carries status, body and origin (R06). An empty
          array and an absent member are distinguished, and the verifier
          reports which it found.</t>
        </section>
        <section anchor="v-cov">
          <name>Coverage</name>
          <t>"completeness" is present and is one of its two values. Where it
          is "complete", every declared stage is an emitting stage and there
          are no boundaries; a contradiction is a FAIL (R07). Where it is
          "incomplete", the verifier reports the boundaries and gaps it
          found and reports the originality of anything beyond them as NOT
          RUN.</t>
        </section>
        <section anchor="v-chain">
          <name>Chain</name>
          <t>Each receipt's "prev" equals the digest of the preceding
          receipt's bytes. Each digest in the manifest equals the digest of
          the named file's bytes. "chain_head" equals the last receipt's
          digest.</t>
        </section>
        <section anchor="v-anchor">
          <name>Anchoring</name>
          <t>"anchor.state" is present and is one of its two values (R08).
          Where it is "unanchored", the verifier MUST report originality as
          NOT RUN with the stated reason. Where it is "anchored", the
          verifier reports the declaration's presence and well-formedness and
          MUST NOT report the anchor as established unless it has itself
          resolved the reference -- which, under <xref
          target="v-constraints"/>, it cannot do online. A verifier MAY
          accept a locally supplied copy of the commitment and report
          against it, saying so.</t>
        </section>
      </section>

      <section anchor="v-not">
        <name>What a Verifier Must Not Do</name>
        <ul spacing="normal">
          <li><strong>Not infer.</strong> An absent member is absent, not
          defaulted.</li>
          <li><strong>Not repair.</strong> No normalization of
          nearly-canonical bytes into canonical ones.</li>
          <li><strong>Not rank, score or opine.</strong> It reports; it does
          not interpret. An interpreter's output is testimony and is written
          beside the records, never into them.</li>
          <li><strong>Not judge the work.</strong> A well-formed record of a
          wrong answer verifies. The verifier says nothing about whether the
          pipeline was correct, the retrieval relevant, or the answer
          true.</li>
          <li><strong>Not require its own producer.</strong> A verifier that
          accepts records only from one producer has certified an
          implementation, not a format. A verifier MUST NOT be able to tell,
          from the records alone, which producer emitted them, except where
          the instrument declaration deliberately says so.</li>
        </ul>
      </section>
    </section>

    <section anchor="ops">
      <name>Operations on Chains</name>
      <t>The verifier establishes that records are what they claim. The
      operations in this section are what a developer does with records that
      have been established. They are defined here so that two tools
      performing them on the same chains reach the same answers; they read
      only the records and, for replay, the pipeline's own code.</t>
      <section anchor="diff">
        <name>Diff</name>
        <t>Given two chains of the same pipeline, the diff is the first
        index at which the receipts differ in any of: the digests of their
        inputs, the instrument's "id", "version" or "config_digest", the
        "constants", or the digests of their outputs -- reported in that
        order, so that a changed input is not mistaken for a changed
        instrument. Timestamps, "run_id" and "prev" are excluded from the
        comparison. Two chains that differ nowhere but in those members ran
        the same pipeline on the same bytes and produced the same bytes.</t>
      </section>
      <section anchor="localize">
        <name>Localize</name>
        <t>Given one chain, localization walks it in order and reports the
        first receipt whose outcome class is not "ok"; whose declared output
        digest is not the input digest the next receipt records for the same
        artifact; or whose coverage records a gap or boundary. The report
        names the stage and which of the three conditions held. A
        localization that crosses a declared boundary stops there and says
        so (<xref target="coverage"/>).</t>
      </section>
      <section anchor="reproduce">
        <name>Reproduce</name>
        <t>Given one chain and the pipeline's code at the versions the
        receipts pin, reproduction runs each stage whose instrument declares
        "rederivable" as "true" from the artifacts its receipt records as
        inputs, and reports per stage whether the output bytes' digest equals
        the recorded output digest. Stages declared not re-derivable are
        reported as NOT RUN with the instrument's note as the reason. A
        reproduction that reaches an artifact it does not hold reports NOT
        RUN for that stage rather than substituting. Reproduction produces a
        new chain; it never rewrites the old one, and a corrected run is a
        new version of the result, never an undo of the previous one.</t>
      </section>
    </section>

    <section anchor="conformance">
      <name>Conformance</name>
      <t>A <strong>conforming producer</strong> emits receipts that contain
      exactly the required members with the value constraints of <xref
      target="receipt"/>, serialized as <xref target="canon"/> requires,
      digested as <xref target="subjects"/> requires, linked as <xref
      target="chain"/> requires, with coverage derived rather than typed,
      with an operator-declared emission policy, and with an anchor
      declaration on every receipt. It refuses to emit rather than emit a
      receipt whose instrument it cannot name and pin. Every receipt it emits
      MUST verify, and it MUST NOT emit any of the ten rejection vectors'
      defects.</t>
      <t>A <strong>conforming verifier</strong> satisfies the five
      constraints of <xref target="v-constraints"/>, reports the three
      outcomes of <xref target="v-outcomes"/>, performs every check of <xref
      target="v-checks"/>, and does none of the things in <xref
      target="v-not"/>. It MUST report PASS on the golden chain of <xref
      target="golden"/> with exactly the NOT RUN outcomes that chain's
      anchor declarations require, and it MUST refuse each of the ten
      rejection vectors of <xref target="rejections"/> <strong>for the stated
      reason</strong>. Refusing the right file for the wrong reason is a
      failing test that happens to look green.</t>
      <t>A verifier that requires knowledge of which framework or producer
      emitted a record, beyond what the instrument declaration states, does
      not conform. One verifier checking records from several independent
      producers, blind, is the bar this document is aimed at; if such a
      verifier cannot be written, the format has dialects and this document
      has failed.</t>
      <t>Conformance says nothing about whether a pipeline is correct, a
      model good, a system fast, a record tamper-resistant, or a deployment
      certified. None of those is tested by anything in this document and
      none may be claimed on its authority.</t>
    </section>

    <section anchor="versioning">
      <name>Versioning</name>
      <t>The "format" member carries "stage-receipt/MAJOR.MINOR". Within a
      major version, a minor revision MAY add optional members, permitted
      values of unenumerated strings, and required checks that only fail on
      records the earlier minor already forbade; it MUST NOT remove a
      required member, change a member's type, or change the canonical
      form. A verifier MUST accept any minor version of the major it
      implements and MUST report NOT RUN, with a version reason, for any
      check the record's minor version did not define. A major revision MAY
      change required semantics.</t>
      <t>A verifier that encounters a record whose "format" is a major
      version it does not implement -- including the pre-standard value
      "stage-receipt/0.0-preview", which corresponds to this document's
      golden chain before its format string was assigned -- MUST report NOT
      RUN with the version as the reason. It MUST NOT report PASS, since it
      did not check the record against the rules the record claims, and it
      MUST NOT report FAIL, since the record contradicted nothing the
      verifier knows.</t>
    </section>

    <section anchor="iana">
      <name>IANA Considerations</name>
      <t>This document has no IANA actions. A later revision may register
      the media type "application/stage-receipt+json" for receipts and
      "application/stage-receipt-chain+json" for chain manifests; nothing in
      this revision depends on such registration.</t>
    </section>

    <section anchor="security">
      <name>Security Considerations</name>
      <t><strong>Consistency is not originality.</strong> The central
      security property of this format is stated in <xref
      target="anchoring"/> and is repeated here because it is the one most
      likely to be misread: a chain that verifies is consistent with itself
      and nothing more. An operator can rewrite an unanchored chain without
      detection. A reader who treats verification as proof of history has
      been misled by the reader, not the record, and the format's defence is
      to require every record and every verifier to say so out loud. The
      anchor cadence is the tamper window; a producer choosing a cadence is
      choosing how long a rewrite can go unnoticed.</t>
      <t><strong>Digests are commitments.</strong> A published digest of a
      secret, a credential, or a personal record is a commitment to bytes
      that can never be withdrawn; anyone who later obtains the bytes can
      prove they existed at anchoring time. Artifacts MUST be reviewed as
      publishable before their digests are anchored, and secrets are never
      digested into anything (<xref target="subjects"/>). Low-entropy
      artifacts -- a short answer, a yes-or-no field, a small set of
      candidates -- can be recovered from their digests by enumeration; a
      producer that needs to record such a value without disclosing it MUST
      use a keyed or salted construction outside this document and record
      the construction's identity in "constants".</t>
      <t><strong>Records are data, not instructions.</strong> Artifact
      contents, names, notes and reasons in a receipt are written by the
      producer and, through externally-sourced inputs, by parties the
      producer does not control. A consumer that feeds any of them to a
      model MUST treat them as untrusted content and SHOULD carry the trust
      class alongside them. The trust class makes origin visible; it does
      not make content safe.</t>
      <t><strong>The verifier is a target.</strong> A verifier parses
      attacker-controlled bytes. It MUST bound the size of what it reads,
      MUST NOT follow paths in a manifest outside the manifest's directory,
      and MUST NOT execute, fetch, or resolve anything a record names. The
      constraint that it requires no network is also a defence: a verifier
      that cannot reach anything cannot be made to.</t>
      <t><strong>Signatures are not specified.</strong> This revision binds
      no record to an actor. A signature envelope and a key lifecycle are
      recognized requirements, sequenced behind actor identity (<xref
      target="open"/>). Until they exist, a receipt's "instrument" and a
      manifest's "anchor" say what ran and where the head was committed,
      not who vouches for either.</t>
      <t><strong>What is not defended.</strong> The format is tamper-evident
      to the extent of its anchoring and not tamper-resistant at all. It
      does not prevent a producer from emitting false records; it makes a
      false record cost a consistent lie across every later record and every
      anchor, and it makes the absence of an anchor visible. Deployment
      isolation between tenants, the integrity of the host, and the honesty
      of the operator are outside what any record can establish.</t>
    </section>

    <section anchor="privacy">
      <name>Privacy Considerations</name>
      <t>A receipt carries digests, sizes, names, media types, timestamps and
      operator-written notes; it does not carry artifact content. Names and
      notes are free text and a producer MUST NOT place personal data in
      them. Timestamps at millisecond precision, combined with stage names,
      can identify a person's interaction with a system; a producer that
      publishes chains SHOULD consider whether the run identifiers and times
      it publishes are themselves personal data.</t>
      <t>An anchored digest of an artifact that contains personal data is a
      permanent commitment to that data's existence, which may conflict with
      an obligation to erase it. Erasure of the artifact does not erase the
      commitment. Producers subject to such obligations SHOULD NOT anchor
      digests of artifacts that may need to be erased, or SHOULD digest them
      through a keyed construction whose key can be destroyed, recording the
      construction in "constants" so that the record remains
      self-describing.</t>
    </section>

  </middle>

  <back>
    <references>
      <name>References</name>
      <references>
        <name>Normative References</name>
        <reference anchor="RFC2119" target="https://www.rfc-editor.org/info/rfc2119">
          <front>
            <title>Key words for use in RFCs to Indicate Requirement Levels</title>
            <author initials="S." surname="Bradner" fullname="S. Bradner"/>
            <date year="1997" month="March"/>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="2119"/>
        </reference>
        <reference anchor="RFC8174" target="https://www.rfc-editor.org/info/rfc8174">
          <front>
            <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
            <author initials="B." surname="Leiba" fullname="B. Leiba"/>
            <date year="2017" month="May"/>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="8174"/>
        </reference>
        <reference anchor="RFC3339" target="https://www.rfc-editor.org/info/rfc3339">
          <front>
            <title>Date and Time on the Internet: Timestamps</title>
            <author initials="G." surname="Klyne" fullname="G. Klyne"/>
            <author initials="C." surname="Newman" fullname="C. Newman"/>
            <date year="2002" month="July"/>
          </front>
          <seriesInfo name="RFC" value="3339"/>
        </reference>
        <reference anchor="RFC8259" target="https://www.rfc-editor.org/info/rfc8259">
          <front>
            <title>The JavaScript Object Notation (JSON) Data Interchange Format</title>
            <author initials="T." surname="Bray" fullname="T. Bray" role="editor"/>
            <date year="2017" month="December"/>
          </front>
          <seriesInfo name="STD" value="90"/>
          <seriesInfo name="RFC" value="8259"/>
        </reference>
        <reference anchor="RFC6234" target="https://www.rfc-editor.org/info/rfc6234">
          <front>
            <title>US Secure Hash Algorithms (SHA and SHA-based HMAC and HKDF)</title>
            <author initials="D." surname="Eastlake 3rd" fullname="D. Eastlake 3rd"/>
            <author initials="T." surname="Hansen" fullname="T. Hansen"/>
            <date year="2011" month="May"/>
          </front>
          <seriesInfo name="RFC" value="6234"/>
        </reference>
        <reference anchor="RFC8792" target="https://www.rfc-editor.org/info/rfc8792">
          <front>
            <title>Handling Long Lines in Content of Internet-Drafts and RFCs</title>
            <author initials="K." surname="Watsen" fullname="K. Watsen"/>
            <author initials="E." surname="Auerswald" fullname="E. Auerswald"/>
            <author initials="A." surname="Farrel" fullname="A. Farrel"/>
            <author initials="Q." surname="Wu" fullname="Q. Wu"/>
            <date year="2020" month="June"/>
          </front>
          <seriesInfo name="RFC" value="8792"/>
        </reference>
      </references>
      <references>
        <name>Informative References</name>
        <reference anchor="RFC8785" target="https://www.rfc-editor.org/info/rfc8785">
          <front>
            <title>JSON Canonicalization Scheme (JCS)</title>
            <author initials="A." surname="Rundgren" fullname="A. Rundgren"/>
            <author initials="B." surname="Jordan" fullname="B. Jordan"/>
            <author initials="S." surname="Erdtman" fullname="S. Erdtman"/>
            <date year="2020" month="June"/>
          </front>
          <seriesInfo name="RFC" value="8785"/>
        </reference>
        <reference anchor="PROV-DM" target="https://www.w3.org/TR/prov-dm/">
          <front>
            <title>PROV-DM: The PROV Data Model</title>
            <author initials="L." surname="Moreau" fullname="Luc Moreau" role="editor"/>
            <author initials="P." surname="Missier" fullname="Paolo Missier" role="editor"/>
            <date year="2013" month="April"/>
          </front>
          <seriesInfo name="W3C" value="Recommendation"/>
        </reference>
        <reference anchor="INTOTO" target="https://www.usenix.org/conference/usenixsecurity19/presentation/torres-arias">
          <front>
            <title>in-toto: Providing farm-to-table guarantees for bits and bytes</title>
            <author initials="S." surname="Torres-Arias" fullname="Santiago Torres-Arias"/>
            <author initials="H." surname="Afzali" fullname="Hammad Afzali"/>
            <author initials="T. K." surname="Kuppusamy" fullname="Trishank Karthik Kuppusamy"/>
            <author initials="R." surname="Curtmola" fullname="Reza Curtmola"/>
            <author initials="J." surname="Cappos" fullname="Justin Cappos"/>
            <date year="2019" month="August"/>
          </front>
          <refcontent>Proceedings of the 28th USENIX Security Symposium</refcontent>
        </reference>
        <reference anchor="RFC6962" target="https://www.rfc-editor.org/info/rfc6962">
          <front>
            <title>Certificate Transparency</title>
            <author initials="B." surname="Laurie" fullname="B. Laurie"/>
            <author initials="A." surname="Langley" fullname="A. Langley"/>
            <author initials="E." surname="Kasper" fullname="E. Kasper"/>
            <date year="2013" month="June"/>
          </front>
          <seriesInfo name="RFC" value="6962"/>
        </reference>
      </references>
    </references>

    <section anchor="vectors">
      <name>Golden Vectors</name>
      <t>The files in this appendix are part of the specification. Long
      lines are folded as described in <xref target="RFC8792"/>; a receipt's
      bytes are recovered by unfolding, and the SHA-256 of the recovered
      bytes is given in each figure's title so that the unfolding can be
      checked before anything else is. The same objects were published on
      2026-09-11, before this document, as a preview under the format string
      "stage-receipt/0.0-preview"; that edition differs from this one only in
      the format strings and, consequently, in every digest.</t>

      <section anchor="golden">
        <name>A Chain That Verifies</name>
        <t>One run of a four-stage pipeline: retrieve, rerank, generate,
        verify. The third receipt records a refusal -- the generator
        produced no claim that could be bound to a retrieved passage -- and
        the fourth records zero claims examined and states how the zero was
        derived. Every receipt declares itself unanchored, so a conforming
        verifier reports PASS for every other property and NOT RUN, with
        that reason, for originality: on this chain, 103 PASS, 0 FAIL, 4 NOT
        RUN. The artifacts the digests reference are not published; the
        structure is the point.</t>

        <figure anchor="gv-01_retrieve"><name>receipts/01-retrieve.json (SHA-256 3a3e67631b62fbf8107a12b989a97f16072b487d54b18e64ac0eabbcb54fe673)</name><sourcecode type="json">========== NOTE: '\' line wrapping per RFC 8792 ===========

{"anchor":{"reason":"preview sample; epoch anchoring is a declared r\
equirement and is not implemented","state":"unanchored"},"assertions\
":{"candidate_count":"1500","constants":{"join":"blank-line","tokeni\
zer":"unicode-nfkc-lower","top_k":"1500"},"corpus_manifest":"sha256:\
b3d5f7a9c1e3d5b7f9a1c3e5d7b9f1a3c5e7d9b1f3a5c7e9d1b3f5a7c9e1d3b5"},"\
coverage":{"boundaries":[],"completeness":"complete","declared_stage\
s":["retrieve","rerank","generate","verify"],"emitting_stages":["ret\
rieve","rerank","generate","verify"]},"emission":{"gaps":[],"policy"\
:"fail-closed"},"format":"stage-receipt/0.1","inputs":[{"bytes":"57"\
,"digest":"sha256:9c56cc51b374c3ba189210d5b6d4bf57790d351c96c47c0219\
0ecf1e430635ab","media_type":"text/plain","name":"question","trust_c\
lass":"externally-sourced"}],"instrument":{"config_digest":"sha256:2\
a7d9e4b1c8f0356ae2d4b6c8f1a3e5d7b9c0f2a4e6d8b0c2f4a6e8d0b2c4f6a","id\
":"bm25+dense-hybrid","kind":"retriever","manifest_digest":"sha256:6\
f1b1c0d4a2e9d7c3b58ae0f21d4c6b98e7a5f30c1d2e4b6a8093f5c7e1d2b4a","re\
derivable":"true","version":"1.4.0"},"outcome":{"class":"ok"},"outpu\
ts":[{"bytes":"184213","digest":"sha256:0d5c1a8f3e7b2946d0c8a1f5e39b\
7d2c460a8e1f3b5d7c9a0e2f4b6d8c0a2e4f","media_type":"application/json\
","name":"candidates","trust_class":"operator-authored"}],"prev":nul\
l,"run_id":"run-2026-09-11-0001","stage":{"index":"1","name":"retrie\
ve"},"time":{"ended":"2026-09-11T09:14:02.774+02:00","started":"2026\
-09-11T09:14:02.118+02:00"}}</sourcecode></figure>
        <figure anchor="gv-02_rerank"><name>receipts/02-rerank.json (SHA-256 0765685137f1d693a9532e91e0bf691d258977c688b2a941eaa5da35b65cdf76)</name><sourcecode type="json">========== NOTE: '\' line wrapping per RFC 8792 ===========

{"anchor":{"reason":"preview sample; epoch anchoring is a declared r\
equirement and is not implemented","state":"unanchored"},"assertions\
":{"chance_floor":"3.88","constants":{"batch_size":"32","max_input_t\
okens":"512","score_order":"descending","truncation":"auto"},"scored\
_pairs":"1500"},"coverage":{"boundaries":[],"completeness":"complete\
","declared_stages":["retrieve","rerank","generate","verify"],"emitt\
ing_stages":["retrieve","rerank","generate","verify"]},"emission":{"\
gaps":[],"policy":"fail-closed"},"format":"stage-receipt/0.1","input\
s":[{"bytes":"184213","digest":"sha256:0d5c1a8f3e7b2946d0c8a1f5e39b7\
d2c460a8e1f3b5d7c9a0e2f4b6d8c0a2e4f","media_type":"application/json"\
,"name":"candidates","trust_class":"operator-authored"}],"instrument\
":{"config_digest":"sha256:5e7c9a1f3d5b7e9c1a3f5d7b9e1c3a5f7d9b1e3c5\
a7f9d1b3e5c7a9f1d3b5e7c","id":"reranker-a","kind":"cross-encoder","m\
anifest_digest":"sha256:233902d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8\
f0a2c4e6b8d0f2a4c6e8","rederivable":"true","version":"pinned"},"outc\
ome":{"class":"ok"},"outputs":[{"bytes":"41120","digest":"sha256:7a9\
c1e3f5b7d9a1c3e5f7b9d1a3c5e7f9b1d3a5c7e9f1b3d5a7c9e1f3b5d7a9c","medi\
a_type":"application/json","name":"ranked","trust_class":"operator-a\
uthored"}],"prev":"sha256:3a3e67631b62fbf8107a12b989a97f16072b487d54\
b18e64ac0eabbcb54fe673","run_id":"run-2026-09-11-0001","stage":{"ind\
ex":"2","name":"rerank"},"time":{"ended":"2026-09-11T09:14:02.774+02\
:00","started":"2026-09-11T09:14:02.118+02:00"}}</sourcecode></figure>
        <figure anchor="gv-03_generate"><name>receipts/03-generate.json (SHA-256 f1e74907f1c47ff905f2860d9213d00f084c1632d652580f8bde036ff80522b0)</name><sourcecode type="json">========== NOTE: '\' line wrapping per RFC 8792 ===========

{"anchor":{"reason":"preview sample; epoch anchoring is a declared r\
equirement and is not implemented","state":"unanchored"},"assertions\
":{"claims":[],"constants":{"prompt_digest":"sha256:3b5d7f9a1c3e5b7d\
9f1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d"}},"coverage":{"bou\
ndaries":[],"completeness":"complete","declared_stages":["retrieve",\
"rerank","generate","verify"],"emitting_stages":["retrieve","rerank"\
,"generate","verify"]},"emission":{"gaps":[],"policy":"fail-closed"}\
,"format":"stage-receipt/0.1","inputs":[{"bytes":"41120","digest":"s\
ha256:7a9c1e3f5b7d9a1c3e5f7b9d1a3c5e7f9b1d3a5c7e9f1b3d5a7c9e1f3b5d7a\
9c","media_type":"application/json","name":"ranked","trust_class":"o\
perator-authored"},{"bytes":"12904","digest":"sha256:e5c7a9f1d3b5e7c\
9a1f3d5b7e9c1a3f5d7b9e1c3a5f7d9b1e3c5a7f9d1b3e5c7","media_type":"tex\
t/plain","name":"evidence_passages","trust_class":"externally-source\
d"}],"instrument":{"config_digest":"sha256:8d0f2a4c6e8b0d2f4a6c8e0b2\
d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f","id":"instrument-b","kind":\
"generator","manifest_digest":"sha256:c1e3a5f7d9b1c3e5a7f9d1b3c5e7a9\
f1d3b5c7e9a1f3d5b7c9e1a3f5d7b9c1e3","rederivable":"false","rederivab\
le_note":"generation is not bit-reproducible; the instrument is decl\
ared, the output is recorded, replay is not promised","version":"pin\
ned"},"outcome":{"class":"refused","detail":"the generator produce\
d no claim that could be bound to a retrieved passage; a refusal i\
s recorded, not an empty answer","reason":"contract: no claim surviv\
ed evidence binding"},"outputs":[],"prev":"sha256:0765685137f1d693a9\
532e91e0bf691d258977c688b2a941eaa5da35b65cdf76","run_id":"run-2026-0\
9-11-0001","stage":{"index":"3","name":"generate"},"time":{"ended":"\
2026-09-11T09:14:02.774+02:00","started":"2026-09-11T09:14:02.118+02\
:00"}}</sourcecode></figure>
        <figure anchor="gv-04_verify"><name>receipts/04-verify.json (SHA-256 1549e9c85091af54d7fce8c2d2832427be9eeda26ed5a0b7af49352d44a74e1a)</name><sourcecode type="json">========== NOTE: '\' line wrapping per RFC 8792 ===========

{"anchor":{"reason":"preview sample; epoch anchoring is a declared r\
equirement and is not implemented","state":"unanchored"},"assertions\
":{"claims_contradicted":"0","claims_examined":"0","claims_supported\
":"0","constants":{"contradiction_threshold":"0.60","support_thresho\
ld":"0.30"},"derivation":"counts recomputed from stage 3 outcome; ze\
ro claims were emitted, therefore zero were examined"},"coverage":{"\
boundaries":[],"completeness":"complete","declared_stages":["retriev\
e","rerank","generate","verify"],"emitting_stages":["retrieve","rera\
nk","generate","verify"]},"emission":{"gaps":[],"policy":"fail-close\
d"},"format":"stage-receipt/0.1","inputs":[],"instrument":{"config_d\
igest":"sha256:f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a3c\
5e7b9d1f3a5","id":"claim-binder","kind":"verifier","manifest_digest"\
:"sha256:a1c3e5b7d9f1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f\
9a1c3","rederivable":"true","version":"0.3.1"},"outcome":{"class":"o\
k","note":"nothing to verify is a result, not an absence"},"outputs"\
:[],"prev":"sha256:f1e74907f1c47ff905f2860d9213d00f084c1632d652580f8\
bde036ff80522b0","run_id":"run-2026-09-11-0001","stage":{"index":"4"\
,"name":"verify"},"time":{"ended":"2026-09-11T09:14:02.774+02:00","s\
tarted":"2026-09-11T09:14:02.118+02:00"}}</sourcecode></figure>
        <figure anchor="gv-MANIFEST"><name>MANIFEST.json (SHA-256 3e797cdb4882368d7016df8f44782f597e128d2366a6a4596bce4e3f2c8bc1b8)</name><sourcecode type="json">========== NOTE: '\' line wrapping per RFC 8792 ===========

{"anchor":{"reason":"preview sample; epoch anchoring is a declared r\
equirement and is not implemented","state":"unanchored"},"chain":[{"\
digest":"sha256:3a3e67631b62fbf8107a12b989a97f16072b487d54b18e64ac0e\
abbcb54fe673","file":"receipts/01-retrieve.json","index":"1","stage"\
:"retrieve"},{"digest":"sha256:0765685137f1d693a9532e91e0bf691d25897\
7c688b2a941eaa5da35b65cdf76","file":"receipts/02-rerank.json","index\
":"2","stage":"rerank"},{"digest":"sha256:f1e74907f1c47ff905f2860d92\
13d00f084c1632d652580f8bde036ff80522b0","file":"receipts/03-generate\
.json","index":"3","stage":"generate"},{"digest":"sha256:1549e9c8509\
1af54d7fce8c2d2832427be9eeda26ed5a0b7af49352d44a74e1a","file":"recei\
pts/04-verify.json","index":"4","stage":"verify"}],"chain_head":"sha\
256:1549e9c85091af54d7fce8c2d2832427be9eeda26ed5a0b7af49352d44a74e1a\
","format":"stage-receipt-chain/0.1","note":"Golden chain of draft-s\
aha-stage-receipts-00. Digests are over each file's exact bytes.","r\
un_id":"run-2026-09-11-0001"}</sourcecode></figure>

      </section>

      <section anchor="rejections">
        <name>Ten Records That Must Be Refused</name>
        <t>Each of the following is the first golden receipt with one
        defect introduced. A conforming verifier MUST refuse each one and
        MUST state the reason given. The exact bytes of each vector are
        obtained by applying the stated change to the first golden receipt
        and re-serializing in canonical form (except R10, whose defect is
        its serialization); the SHA-256 of the resulting file is given so
        that an implementer can confirm the vector was reconstructed
        correctly.</t>
        <dl newline="true" spacing="normal">
          <dt>R01 (R01-json-number.json):</dt>
          <dd><t>Change: &quot;assertions.candidate_count&quot; becomes the JSON number 1500.</t><t>Reason: a JSON number where a decimal string is required (&#x27;500.00&#x27; and &#x27;500&#x27; must stay distinct).</t><t>SHA-256 of the file: a331ddb798be868f0769ffcfecb9e50b 5979ed57be92b3ff9dab62934b4f8ee7 (one string; shown with a space for line width).</t></dd>
          <dt>R02 (R02-null-instrument.json):</dt>
          <dd><t>Change: &quot;instrument.manifest_digest&quot; becomes the empty string.</t><t>Reason: instrument cannot be named or pinned; refusal is required, not a blank field.</t><t>SHA-256 of the file: c1cc9258fa8f4c6e1969278a5dea85f9 db6c3afb1ffbe94e3e810051824ea1bb (one string; shown with a space for line width).</t></dd>
          <dt>R03 (R03-timestamp-no-zone.json):</dt>
          <dd><t>Change: &quot;time.started&quot; becomes &quot;2026-09-11T09:14:02.118&quot;, with no offset.</t><t>Reason: a timestamp without its zone is half a timestamp.</t><t>SHA-256 of the file: ff99a81cd7c8320b840efbb1496f91cd 29c8cdd40643a290800bd859e182eb38 (one string; shown with a space for line width).</t></dd>
          <dt>R04 (R04-missing-constants.json):</dt>
          <dd><t>Change: &quot;assertions.constants&quot; is removed.</t><t>Reason: an assertion that does not name its transform constants.</t><t>SHA-256 of the file: 8f87aa87ca7731c5d131076f98d648da a5b01eddcee687e348e413594f0cd476 (one string; shown with a space for line width).</t></dd>
          <dt>R05 (R05-untrusted-class.json):</dt>
          <dd><t>Change: &quot;inputs[0].trust_class&quot; becomes &quot;unknown&quot;.</t><t>Reason: an input with no declared trust class.</t><t>SHA-256 of the file: 37be84ab9b559f0a919205964bf48b4e a8d7472cbbbeb007d4ba4df72e24785a (one string; shown with a space for line width).</t></dd>
          <dt>R06 (R06-error-without-body.json):</dt>
          <dd><t>Change: &quot;outcome&quot; becomes {&quot;class&quot;:&quot;error&quot;,&quot;status&quot;:&quot;403&quot;}.</t><t>Reason: an HTTP error without its body is a status code wearing an explanation.</t><t>SHA-256 of the file: fdddfe162027eac5fb57b0751a7cdf1e 1ad9738f3570c66c928472641d19ad0a (one string; shown with a space for line width).</t></dd>
          <dt>R07 (R07-coverage-lie.json):</dt>
          <dd><t>Change: &quot;coverage.emitting_stages&quot; becomes [&quot;retrieve&quot;,&quot;rerank&quot;].</t><t>Reason: &#x27;complete&#x27; asserted while declared stages are missing from the emitting list.</t><t>SHA-256 of the file: 6e678e5da16a5e3e7cd00bc9e69500c5 793e47e04f18e9451898df9fbbd2576c (one string; shown with a space for line width).</t></dd>
          <dt>R08 (R08-anchor-absent.json):</dt>
          <dd><t>Change: &quot;anchor&quot; is removed.</t><t>Reason: anchor state absent rather than declared; unanchored is a state, not a silence.</t><t>SHA-256 of the file: a5ae3bd9148df44e1848a31d3b3aa81d 6aaaf209ef451eff710d7feb58d30429 (one string; shown with a space for line width).</t></dd>
          <dt>R09 (R09-self-digest.json):</dt>
          <dd><t>Change: a member &quot;receipt_digest&quot; with the value &quot;sha256:00&quot; is added.</t><t>Reason: a record may not contain the proof of its own final state.</t><t>SHA-256 of the file: 9a068cc45f41a94981da22d8db97218f b34d9eedbd88bdd0e5144b97119037d4 (one string; shown with a space for line width).</t></dd>
          <dt>R10 (R10-not-canonical.json):</dt>
          <dd><t>Change: the object is serialized with two-space indentation and newlines instead of in canonical form.</t><t>Reason: pretty-printed; file bytes are not the canonical serialization.</t><t>SHA-256 of the file: 891a20d03391b01112ade85dea864478 99e139d6908a71cd49111b77457d77f4 (one string; shown with a space for line width).</t></dd>
        </dl>
        <t>A format with no rejection vectors has not specified anything;
        it has described a happy path and left every implementer to guess at
        the edges. Implementers are asked to publish the results of their
        verifier against both appendices, including any disagreement with
        the reference implementation. A disagreement between two independent
        verifiers is the most valuable report this document can receive,
        because it means the specification is ambiguous and the ambiguity
        was found before anyone depended on it.</t>
      </section>
    </section>

    <section anchor="open">
      <name>Open Requirements</name>
      <t>The format was specified against a register of thirteen
      requirements, each raised by a defect or a reviewer, and the register
      is published with the format's validation battery. This revision
      satisfies some, declares some, and leaves some standing. Naming the
      last group is the point of this appendix.</t>
      <table anchor="opentable">
        <name>Disposition of the thirteen requirements in this revision</name>
        <thead><tr><th>#</th><th>Requirement</th><th>This revision</th></tr></thead>
        <tbody>
          <tr><td>1</td><td>Merkle corpus manifest</td><td>Root construction specified (<xref target="subjects"/>); inclusion proofs and a tampered-member vector deferred.</td></tr>
          <tr><td>2</td><td>Epoch anchoring</td><td>Declaration specified (<xref target="anchoring"/>); mechanism not specified.</td></tr>
          <tr><td>3</td><td>Tenant isolation</td><td>Not specified; a tenant identifier is expected in a later revision.</td></tr>
          <tr><td>4</td><td>Signature envelope</td><td>Not specified; sequenced behind actor identity.</td></tr>
          <tr><td>5</td><td>Per-receipt dependency record</td><td>Not specified; intended to align with existing bill-of-materials formats.</td></tr>
          <tr><td>6</td><td>Signing-key lifecycle</td><td>Not specified; follows 4.</td></tr>
          <tr><td>7</td><td>Receipt topology</td><td>Linear chains and retries as attempts (<xref target="scope"/>); everything else declared as a boundary. The largest open item.</td></tr>
          <tr><td>8</td><td>Disclosure layer</td><td>Partially met: a chain verifies with artifact contents withheld, since receipts carry digests only.</td></tr>
          <tr><td>9</td><td>Coverage attestation</td><td>Specified (<xref target="coverage"/>).</td></tr>
          <tr><td>10</td><td>Content trust class</td><td>Specified (<xref target="artifacts"/>).</td></tr>
          <tr><td>11</td><td>Emission failure semantics</td><td>Specified (<xref target="emission"/>).</td></tr>
          <tr><td>12</td><td>Schema evolution</td><td>Specified minimally (<xref target="versioning"/>).</td></tr>
          <tr><td>13</td><td>External effect records</td><td>Specified as an optional member (<xref target="effects"/>).</td></tr>
        </tbody>
      </table>
    </section>

    <section anchor="editnotes">
      <name>Editor's Notes for This Revision</name>
      <t>This section will be removed before publication as an RFC.</t>
      <t>The format was specified after its validation battery and before
      its reference implementation, in that order deliberately: the exam is
      published before the code it judges. The sections most likely to
      change when the battery's pathology fixtures are written against real
      code are <xref target="effects"/>, the error body requirements in
      <xref target="outcome"/>, the boundary object in <xref
      target="coverage"/>, and the gap object in <xref
      target="emission"/>. Each is marked in the text. Nothing in the
      canonical form, the required members, or the rejection vectors is
      expected to change.</t>
      <t>The preview verifier published with the samples predates this
      document and does not yet perform every check this document
      requires: it does not check that "complete" implies an empty
      "boundaries", that "ended" does not precede "started", that "prev"
      is null exactly when "index" is "1", that "rederivable" is one of
      its two values, or that the manifest's "run_id" equals every
      receipt's. A conforming verifier performs all of them. Rejection
      vectors for each are expected in the next revision, since a
      requirement without a vector that fails is a requirement nobody has
      tested.</t>
    </section>

    <section anchor="ack" numbered="false">
      <name>Acknowledgements</name>
      <t>Three independent reviewers read the requirement register and the
      battery before this document was written. The coverage requirement and
      the wording of the bounded claim in <xref target="coverage"/> came from
      two of them separately; the topology requirement, the external-effect
      states and the observation that a format nobody wants on a Tuesday
      will not be installed came from the third. The defects that motivated
      the rejection vectors were the author's own.</t>
    </section>
  </back>
</rfc>
