<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-gruszka-audit-decision-receipts-05" category="info" tocInclude="true" tocDepth="2" sortRefs="true" symRefs="true" version="3">
  <front>
    <title abbrev="AUDIT Decision Receipts">Decision Receipts for Approvals, Declined Actions and Executed Actions in Agent Audit Records</title>
    <seriesInfo name="Internet-Draft" value="draft-gruszka-audit-decision-receipts-05"/>
    <author initials="K." surname="Gruszka" fullname="Konrad Gruszka">
      <organization>b7n0de</organization>
      <address>
        <postal>
          <country>Germany</country>
        </postal>
        <email>kontakt@b7n0de.com</email>
      </address>
    </author>
    <date year="2026" month="November" day="2"/>
    <area>Security</area>
    <keyword>AUDIT</keyword>
    <keyword>agent</keyword>
    <keyword>decision receipt</keyword>
    <keyword>in-toto</keyword>
    <keyword>DSSE</keyword>
    <abstract>
<t>The architecture for auditing agent delegation and interactions proposed for
the AUDIT effort names Interaction Records, Action Records and Authorization
Transition Records, and leaves their encoding open. This document shows how an
existing signed record, the decision receipt of the open-source proofbundle
project, together with its companion outcome receipt, gives three such records
exact bytes, a signature and digest bindings that a third party can check offline.
The three cases are a human approval, a declined action and an executed action
with its result. For each case the document maps the receipt members onto the
record types of the architecture, states what the receipt adds and what it does
not show, and gives an offline verification procedure. It states one requirement
for approvals, that an approval is honoured at most once, also after the record
of consumed approvals is rotated. Test vectors for all three cases, each with a
counterexample, are included. The document also describes, informatively, how a receipt can be registered with a Transparency Service under RFC 9943 and what a SCITT Receipt then shows and does not show. This document defines no new format, predicate or
registry.</t>
    </abstract>
  </front>
  <middle>

<section anchor="introduction">
      <name>Introduction</name>
      <t>The architecture of <xref target="AUDIT-ARCH"/> asks that auditing link user
intent, delegation, authorization and execution, and treats authorization as a state
that changes over time. Three of its four record types (its Section 5) matter here.
Interaction Records capture user-facing events such as approvals and refusals, Action
Records capture events at the boundary where an action took effect, and Authorization
Transition Records capture changes in permission state. Its field names are
placeholders (its Section 7), and a canonical data model is a work item (WI-1).</t>
      <t>An Auditor in that architecture does not trust the Agent (its Section 8), so a
record helps only when a third party can check it. That needs exact bytes, a signature
over them and bindings to inputs and evidence by digest. This document shows that the
decision receipt of proofbundle <xref target="PB-DECISION"/>, an in-toto Statement
<xref target="INTOTO-STATEMENT"/> in a DSSE envelope <xref target="DSSE"/>, signed with
Ed25519 <xref target="RFC8032"/> over a payload in the serialization of
<xref target="RFC8785"/>, supplies them together with its companion outcome receipt
<xref target="PB-OUTCOME"/>. It does so for three cases that Agent Guard, the gate of
the proofbundle plugin for two coding agent hosts, produces
(<xref target="implementation-status"/>):</t>
      <ol>
        <li>a human approval of one action (an Interaction Record of an approval and an
Authorization Transition Record with the trigger user_approval);</li>
        <li>a declined action, with its reason and without an effect;</li>
        <li>an executed action with its result (an Action Record).</li>
      </ol>
      <t>The document maps and verifies. It does not propose the decision receipt as the data model of the architecture and does not change the receipts it describes. The mapping of <xref target="mapping"/> follows revision -01 of <xref target="AUDIT-ARCH"/>; a later revision of the architecture can change it.</t>
      <section anchor="requirements-language">
        <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&nbsp;14 <xref target="RFC2119"/> <xref target="RFC8174"/> when, and only when, they
appear in all capitals, as shown here.</t>
        <t>In this document, these key words apply to a verifier in <xref target="evaluation-receipts"/> and in the procedure of <xref target="verification"/>, to an Auditor that performs the checks of <xref target="sets"/>, to a relying party that lets an action run because of an approval in <xref target="approvals-once"/>, and to the use of the test keys of <xref target="vectors"/>.</t>
      </section>
      <section anchor="terms">
        <name>Terms</name>
        <dl newline="false" spacing="compact">
          <dt>Decision receipt, outcome receipt:</dt>
          <dd>A DSSE envelope whose payload is an in-toto Statement v1 with the predicate
type https://b7n0de.com/proofbundle/predicates/decision-receipt/v0.1 or
https://b7n0de.com/proofbundle/predicates/action-outcome/v0.1.</dd>
          <dt>Payload bytes:</dt>
          <dd>The bytes obtained by base64 decoding the payload member of the envelope. A DSSE signature covers the pre-authentication encoding of payloadType and these bytes.</dd>
          <dt>Content root:</dt>
          <dd>SHA-256 <xref target="RFC6234"/> over the payload bytes. Other digests commit to the byte strings identified by their respective fields.</dd>
          <dt>Approval record:</dt>
          <dd>The record of one human act that approves one action
(<xref target="case-approval"/>).</dd>
          <dt>Relying party:</dt>
          <dd>The component that lets an action run because of a decision.</dd>
          <dt>Consumption record:</dt>
          <dd>The durable record in which a relying party notes each approval it has
honoured.</dd>
        </dl>
      </section>
    </section>

<section anchor="mapping">
      <name>Mapping the Three Cases onto AUDIT Records</name>
      <t>All decision receipts here use the decisionType preActionAuthorization and
carry validity with audience, nonce and expiresAt. A decision receipt is the gate's
signed view of an event; the human act itself is the approval record, bound by digest.
In the tables, IR stands for Interaction Record, ATR for Authorization Transition Record
and AR for Action Record, followed by a placeholder field of the architecture. The
fields common to all cases map as follows.</t>
      <dl newline="false" spacing="compact" indent="26">
        <dt>event_id</dt><dd>decisionId (outcomeId in an outcome receipt)</dd>
        <dt>trace_id, parent_id</dt><dd>traceContext.traceId, traceContext.parentId</dd>
        <dt>timestamp</dt><dd>decidedAt (performedAt in an outcome receipt)</dd>
        <dt>actor, on_behalf_of</dt><dd>agent.id, principal.id</dd>
        <dt>action</dt><dd>proposedAction (actionType, target, method)</dd>
        <dt>exact action bytes</dt><dd>proposedAction.parametersDigest</dd>
        <dt>authorization.expires_at</dt><dd>validity.expiresAt</dd>
        <dt>delegation_chain</dt><dd>none (delegationRefs is not used here)</dd>
        <dt>record signer</dt><dd>decisionMaker.id, bound to the key by a trust policy</dd>
      </dl>

      <section anchor="case-approval">
        <name>Case 1, a Human Approval</name>
        <t>A gate asks a person before an action and records the answer. An earlier receipt for the same request, such as one with the verdict ESCALATE, is a separate record; this receipt does not reference it. After the answer the gate decides ALLOW for exactly the approved action. The approval record carries approvalId, approver, session, actionDigest (SHA-256 of the approved action bytes), approvedAt and validUntil. The decision receipt names it in inputSnapshot under the name "approval record".</t>
        <table anchor="tab-approval">
          <name>Case 1</name>
          <thead><tr><th>Record, field</th><th>Decision receipt</th></tr></thead>
          <tbody>
            <tr><td>IR, approval</td><td>approval record, by its digest in inputSnapshot</td></tr>
            <tr><td>IR, actor</td><td>approver in the approval record, equal to principal.id</td></tr>
            <tr><td>ATR, previous_state</td><td>not recorded in this receipt; preceding state must be established separately</td></tr>
            <tr><td>ATR, new_state</td><td>verdict ALLOW for parametersDigest</td></tr>
            <tr><td>ATR, trigger</td><td>reasonCodes contains user_approval</td></tr>
            <tr><td>ATR, actor</td><td>approver in the approval record</td></tr>
          </tbody>
        </table>
        <t>The scope of the new state is one action, identified by its bytes. A second
action, even one with the same name and target, needs a new approval.</t>
      </section>

      <section anchor="case-declined">
        <name>Case 2, a Declined Action</name>
        <t>A gate declines an action because a rule or a person says no. The receipt
records the verdict DENY with its reasons. It may say in actionOutcome that the
call was blocked, which is the decision maker's own statement.</t>
        <table anchor="tab-declined">
          <name>Case 2</name>
          <thead><tr><th>Record, field</th><th>Decision receipt</th></tr></thead>
          <tbody>
            <tr><td>IR, refusal</td><td>verdict DENY or REFUSE</td></tr>
            <tr><td>reason</td><td>reasonCodes</td></tr>
            <tr><td>action</td><td>proposedAction with parametersDigest</td></tr>
            <tr><td>no effect</td><td>actionOutcome.status blocked (self-asserted); no outcome with status executed names this decision in the supplied set</td></tr>
            <tr><td>ATR</td><td>none; the state is unchanged</td></tr>
          </tbody>
        </table>
        <t>A receipt cannot prove that something did not happen. An observer at the boundary can separately report that it observed no effect. The check in <xref target="sets"/> detects a conflicting executed outcome in the supplied set; it does not establish absence of an effect.</t>
      </section>

      <section anchor="case-executed">
        <name>Case 3, an Executed Action and Its Result</name>
        <t>A gate allows an action, the action runs, and an executor or an observer at
the boundary records what happened in an outcome receipt signed with its own key.
The outcome receipt names the decision by its content root in decisionRef.</t>
        <table anchor="tab-executed">
          <name>Case 3</name>
          <thead><tr><th>Record, field</th><th>Outcome and decision receipt</th></tr></thead>
          <tbody>
            <tr><td>AR, event_id</td><td>outcomeId</td></tr>
            <tr><td>AR, parent_id</td><td>traceContext.parentId of the referenced decision</td></tr>
            <tr><td>decision binding</td><td>decisionRef, the content root of the decision</td></tr>
            <tr><td>AR, timestamp</td><td>performedAt</td></tr>
            <tr><td>AR, actor</td><td>executor.id</td></tr>
            <tr><td>AR, action</td><td>requestedActionDigest, equal to parametersDigest</td></tr>
            <tr><td>result</td><td>status executed, effectDigest</td></tr>
            <tr><td>authorization</td><td>the decision (ALLOW, validity.expiresAt)</td></tr>
            <tr><td>evidence</td><td>evidenceRefs of the decision</td></tr>
          </tbody>
        </table>
        <t>The architecture asks that Action Records be produced at the boundary where the action took effect. Its WI-1-3 distinguishes the Recorder's signing identity from the recorded Agent's identity where they are operationally separate. <xref target="verify-outcome"/> checks that the outcome and decision use different keys and that executor.id differs from decisionMaker.id. Those checks alone do not establish operational separation or that the outcome signer observed the boundary.</t>
      </section>

      <section anchor="adds">
        <name>What the Receipt Adds</name>
        <ul>
          <li>Exact bytes. The payload is its own serialization under <xref target="RFC8785"/>. A verifier uses the received payload bytes for the signature input and content root. Canonical serialization is used to check equality and to derive the predicate's subject digest, never to repair or replace the received payload.</li>
          <li>A signature. Ed25519 over the DSSE pre-authentication encoding of the payload
type and the payload bytes.</li>
          <li>Binding by digest. The action bytes (parametersDigest), the approval record and
other inputs (inputSnapshot), the policy (policyBoundary.policyDigest), evidence
(evidenceRefs), the decision itself (decisionRef in the outcome) and the observed
effect (effectDigest) are named by SHA-256.</li>
          <li>Stated limits. The member notChecked lists what the decision maker did not
check, and decisionChangeConditions lists what would change the decision.</li>
        </ul>
      </section>

      <section anchor="not-adds">
        <name>What the Receipt Does Not Do</name>
        <ul>
          <li>It does not show that a decision was correct, safe or lawful.</li>
          <li>It does not authenticate the approval. The approval record in this document is not signed by the person it names. A deployment can additionally cite a separately signed approval in inputSnapshot. Validating that signature and establishing its correspondence to the approval record require rules beyond this document. The signed approvals of <xref target="IZMAYLOV"/> are one possible source of such evidence.</li>
          <li>It does not show that an effect happened. An outcome receipt shows that its
signer stated an effect with a given digest. A digest that cannot be resolved
to bytes shows only that a value was written.</li>
          <li>It does not register anything. Transparency in the sense of <xref target="RFC9943"/> needs a separate registration and a SCITT Receipt; <xref target="registration"/> describes how a receipt of this document can be registered.</li>
          <li>It does not detect a receipt that was never written, unless an observer or a
sequence counter is added.</li>
          <li>Its times are the signer's clock.</li>
          <li>It is not an access token. A verified ALLOW is a record of a decision, and the
executing system makes its own authorization check.</li>
        </ul>
      </section>

      <section anchor="evaluation-receipts">
        <name>Evaluation Receipts Are Evidence, Never Authorization</name>
        <t>A decision may rest on an evaluation result, such as a test suite that
passed. A Signed Evaluation Receipt <xref target="SER"/> records such a result. It
appears in a decision receipt only as an entry of evidenceRefs whose digest is the
receipt digest, SHA-256 over its payload bytes, as in
<xref target="SER-MAPPINGS"/>. A verifier <bcp14>MUST NOT</bcp14> treat a valid
Signed Evaluation Receipt, or its presence in evidenceRefs, as permission for an
action. In the records of this document only a decision receipt with the verdict
ALLOW, from a key the relying party trusts for decisions, records a permission.</t>
      </section>
      <section anchor="observations">
        <name>Observations for the Architecture</name>
        <t>This section is informative. At the places below, the mapping of this section needed a reading of revision -01 of <xref target="AUDIT-ARCH"/>. They are offered as observations and questions, not as requirements.</t>
        <ul>
          <li>Evidence for a human approval. <xref target="AUDIT-ARCH" section="3"/> associates Interaction Records with the User; Section <xref target="AUDIT-ARCH" section="3.1" sectionFormat="bare"/> says that user-facing systems produce records of prompts and approvals, and Section <xref target="AUDIT-ARCH" section="4.2" sectionFormat="bare"/> has the Auditing Service sign records under its own identity. In Case 1, the gate's decision receipt binds an approval record that names a person but is not signed by that person (<xref target="case-approval"/> and <xref target="not-adds"/>). What evidence is needed to bind such a record to that person's act of approval, and when is the person's own signature required?</li>
          <li>Previous state. The Authorization Transition Record of <xref target="AUDIT-ARCH" section="7.4"/>, and its work item WI-1-4 (<xref target="AUDIT-ARCH" section="6"/>), carries a previous state, a new state, a trigger and an actor in one record. A decision receipt records only the new state for one action and leaves the previous state to other records (<xref target="case-approval"/>). <xref target="AUDIT-ARCH" section="5"/> reconstructs authorization from the ordered sequence of such records; is a record without the previous state enough for that?</li>
          <li>Binding an Action Record to its authorization. In <xref target="AUDIT-ARCH" section="7.2"/> the parent_id of an Action Record references the Interaction Record that motivated the action, and the authorization appears as scope and expiry. The outcome receipt of Case 3 names the decision receipt by its content root in decisionRef and takes parent_id from that decision (<xref target="case-executed"/>). The examples of <xref target="AUDIT-ARCH"/> have no member that binds an Action Record to the authorizing decision by digest.</li>
          <li>Refusals before execution. <xref target="AUDIT-ARCH" section="5"/> includes model responses and agent-to-agent dialogue among Interaction Records. Its work item WI-1-2 (<xref target="AUDIT-ARCH" section="6"/>) also includes system events and does not preclude profiles for non-conversational interactions. In Case 2, a gate can decline a proposed action under a rule before execution (<xref target="case-declined"/>). When such a denial is internal to a workflow and is not part of a conversation, is it an Interaction Record, an Action Record of an attempted request, or a different event type?</li>
          <li>Who records an action. <xref target="AUDIT-ARCH" section="3"/> has Action Records generated by the Agent, while <xref target="AUDIT-ARCH" section="5"/> places them at the boundary where the action took effect. Its work item WI-1-3 (<xref target="AUDIT-ARCH" section="6"/>) already distinguishes the Recorder's signing identity from the recorded Agent's identity where they are operationally separated. In Case 3 the outcome signer can be an observer that attests the executor's identifier (<xref target="verify-inputs"/> and <xref target="verify-outcome"/>). How should an Action Record and the Auditor's trust policy identify the Recorder separately from the actor whose action is recorded?</li>
        </ul>
      </section>
    </section>

<section anchor="verification">
      <name>Offline Verification</name>
      <t>The procedure below needs no network access. Each step either passes or ends
the procedure with a failure named by the step. A later step never repairs an
earlier failure.</t>
      <section anchor="verify-inputs">
        <name>Inputs</name>
        <t>The verifier needs the envelope bytes of each receipt and the Ed25519 public keys selected by its trust policy for the decision signer and, for Case 3, the outcome signer. It also needs the expected decisionMaker.id and, for Case 3, the expected executor.id whose assertion that policy permits under the outcome-signing key. An outcome signer may be an observer rather than the executor.</t>
        <t>The verifier supplies an evaluation time T in UTC; it does not take T from a receipt. Expected audience and nonce and the action and effect byte strings are optional inputs. Case 1 requires the approval record bytes. Inputs or evidence whose bytes are not checked remain digest references, not verified contents.</t>
      </section>
      <section anchor="verify-decision">
        <name>Decision Receipt</name>
        <ol>
          <li>Envelope. The envelope <bcp14>MUST</bcp14> be valid UTF-8 and parse as one JSON text of <xref target="RFC8259"/> that is an object, with no duplicate member names in any object. The envelope bytes <bcp14>MUST NOT</bcp14> begin with the byte order mark U+FEFF, which <xref target="RFC8259" section="8.1"/> forbids adding. It <bcp14>MUST</bcp14> contain payload, payloadType and signatures. payloadType <bcp14>MUST</bcp14> be application/vnd.in-toto+json.</li>
          <li>Payload bytes. Decode payload as base64 <xref target="RFC4648"/> into the
payload bytes P.</li>
          <li>Signature. Form PAE = "DSSEv1" SP LEN(type) SP type SP LEN(P) SP P, where SP
is one space, LEN is the length in bytes as ASCII decimal without leading zeros, and
type is the payloadType. At least one entry of signatures <bcp14>MUST</bcp14> carry a
base64 sig that verifies as an Ed25519 signature over PAE under the expected key. The
keyid member is not used to select a key.</li>
          <li>Canonical form. P <bcp14>MUST</bcp14> be valid UTF-8 and parse as one JSON
value with no duplicate member names. The serialization of the parsed value under
<xref target="RFC8785"/> <bcp14>MUST</bcp14> be byte for byte equal to P. A verifier
<bcp14>MUST NOT</bcp14> continue with a re-serialized form.</li>
          <li>Content root. Compute R = SHA-256(P).</li>
          <li>Statement. _type <bcp14>MUST</bcp14> be https://in-toto.io/Statement/v1 and predicateType the decision receipt type of <xref target="terms"/>. subject <bcp14>MUST</bcp14> contain exactly one entry, whose digest.sha256 is SHA-256 over the <xref target="RFC8785"/> serialization of predicate; it <bcp14>MUST NOT</bcp14> contain other entries.</li>
          <li><t>Members. predicate <bcp14>MUST</bcp14> be a JSON object satisfying the field rules of <xref target="field-rules"/>. It <bcp14>MUST</bcp14> contain schemaVersion, decisionId, decisionType, decidedAt, decisionMaker, agent, principal, proposedAction, inputSnapshot, policyBoundary (with policyDigest), evidenceRefs, decision, notChecked, decisionChangeConditions, privacy and validity. Other predicate members are limited to recordedAt, delegationRefs, actionOutcome and traceContext.</t><t>decisionMaker, agent, principal, proposedAction, policyBoundary, decision, privacy and validity <bcp14>MUST</bcp14> be objects. decisionId, decisionMaker.id, agent.id and principal.id <bcp14>MUST</bcp14> be non-empty strings. inputSnapshot, evidenceRefs, notChecked and decisionChangeConditions <bcp14>MUST</bcp14> be arrays. decision.reasonCodes <bcp14>MUST</bcp14> be a non-empty array of non-empty strings.</t><t>schemaVersion <bcp14>MUST</bcp14> consist of "0.1." followed by one or more ASCII decimal digits. decisionType <bcp14>MUST</bcp14> be preActionAuthorization. Every timestamp, when non-null, <bcp14>MUST</bcp14> be an <xref target="RFC3339"/> UTC timestamp with a trailing "Z". Every non-null digest <bcp14>MUST</bcp14> be an object with exactly one member, sha256, whose value is 64 lowercase hexadecimal digits. A null is allowed only where the applicable field rules or <xref target="verify-cases"/> explicitly permit it.</t><t>The digests of a decision receipt are the members listed below, each with its full path in predicate, where [] stands for each entry of an array.</t><ul spacing="compact"><li>agent.configurationDigest</li><li>principal.authnContextRef.digest</li><li>proposedAction.target.digest</li><li>proposedAction.parametersDigest</li><li>proposedAction.parametersSchemaRef.digest</li><li>inputSnapshot[].digest</li><li>policyBoundary.policyDigest</li><li>evidenceRefs[].digest</li><li>evidenceRefs[].artifactDigest</li><li>actionOutcome.outcomeRef.digest</li></ul><t>The timestamps of a decision receipt are the members listed below.</t><ul spacing="compact"><li>decidedAt</li><li>recordedAt</li><li>policyBoundary.validFrom</li><li>policyBoundary.validUntil</li><li>actionOutcome.performedAt</li><li>validity.expiresAt</li></ul><t>actionOutcome.outcomeRef is an object whose member digest is a digest; it is not itself a digest. evidenceRefs[].typedDigest, where present, is not a digest in this sense either. It <bcp14>MUST</bcp14> be an object whose members are type, digestAlgorithm and digest and optionally purpose; type and purpose <bcp14>MUST</bcp14> be non-empty strings, digestAlgorithm <bcp14>MUST</bcp14> be jcs-sha256-v1, and digest <bcp14>MUST</bcp14> be 64 lowercase hexadecimal digits.</t></li>
          <li>Signer. decisionMaker.id <bcp14>MUST</bcp14> be the identifier the trust
policy binds to the key of step 3.</li>
          <li>Validity. validity <bcp14>MUST</bcp14> carry a non-empty array of non-empty audience strings, a non-empty nonce string and an expiresAt timestamp. decidedAt <bcp14>MUST NOT</bcp14> be later than T, and T <bcp14>MUST</bcp14> be strictly earlier than expiresAt. Where an expected audience is given, audience <bcp14>MUST</bcp14> contain it; where an expected nonce is given, nonce <bcp14>MUST</bcp14> equal it.</li>
          <li>Action bytes. Where the action bytes are given, their SHA-256
<bcp14>MUST</bcp14> equal proposedAction.parametersDigest.sha256.</li>
        </ol>
      </section>
      <section anchor="verify-cases">
        <name>Checks per Case</name>
        <dl newline="true" spacing="normal">
          <dt>Case 1, approval.</dt>
          <dd><t>decision.verdict <bcp14>MUST</bcp14> be ALLOW and decision.reasonCodes <bcp14>MUST</bcp14> contain user_approval. inputSnapshot <bcp14>MUST</bcp14> contain exactly one entry whose name is "approval record"; it may contain other entries. The approval record bytes A <bcp14>MUST</bcp14> be supplied, <bcp14>MUST</bcp14> hash to that entry's digest, and <bcp14>MUST</bcp14> be their own <xref target="RFC8785"/> serialization.</t><t>A <bcp14>MUST</bcp14> be a JSON object containing approvalId, approver, session, actionDigest, approvedAt and validUntil. approvalId, approver and session <bcp14>MUST</bcp14> be non-empty strings. actionDigest <bcp14>MUST</bcp14> have the digest form of <xref target="verify-decision"/> and <bcp14>MUST</bcp14> equal proposedAction.parametersDigest. approver <bcp14>MUST</bcp14> equal principal.id. approvedAt and validUntil <bcp14>MUST</bcp14> be <xref target="RFC3339"/> UTC timestamps with a trailing "Z". The bounds approvedAt &lt;= decidedAt &lt;= T &lt; validity.expiresAt &lt;= validUntil <bcp14>MUST</bcp14> hold.</t></dd>
          <dt>Case 2, declined.</dt>
          <dd>decision.verdict <bcp14>MUST</bcp14> be DENY or REFUSE. Where
actionOutcome is present, its status <bcp14>MUST</bcp14> be notAttempted, blocked
or refused, and performedAt and outcomeRef <bcp14>MUST</bcp14> be absent or
null.</dd>
          <dt>Case 3, executed.</dt>
          <dd>decision.verdict <bcp14>MUST</bcp14> be ALLOW. The outcome receipt <bcp14>MUST</bcp14> have status executed and <bcp14>MUST</bcp14> pass <xref target="verify-outcome"/> against this decision.</dd>
        </dl>
      </section>
      <section anchor="verify-outcome">
        <name>Outcome Receipt</name>
        <ol>
          <li>Apply steps 1 to 5 of <xref target="verify-decision"/> separately to the outcome envelope with the expected outcome-signing key, obtaining payload bytes Q. Retain the decision receipt's content root R for the binding check below.</li>
          <li>_type <bcp14>MUST</bcp14> be https://in-toto.io/Statement/v1 and predicateType the outcome receipt type. subject <bcp14>MUST</bcp14> contain exactly one entry, whose digest.sha256 is SHA-256 over the <xref target="RFC8785"/> serialization of predicate; it <bcp14>MUST NOT</bcp14> contain other entries, as in step 6 of <xref target="verify-decision"/>.</li>
          <li><t>Members. predicate <bcp14>MUST</bcp14> be a JSON object satisfying the field rules of <xref target="field-rules"/>. It <bcp14>MUST</bcp14> contain schemaVersion, outcomeId, decisionRef, executor, requestedActionDigest, status and performedAt. Other predicate members are limited to effectDigest, actualActionDigest, responseDigest, policyPurpose, receiverRefs, sequence, recordedAt, limitations, traceContext and validity.</t><t>schemaVersion <bcp14>MUST</bcp14> consist of "0.1." followed by one or more ASCII decimal digits. outcomeId <bcp14>MUST</bcp14> be a non-empty string. executor <bcp14>MUST</bcp14> be an object with a non-empty id string. status <bcp14>MUST</bcp14> be executed, refused, failed or partial. Each non-null timestamp <bcp14>MUST</bcp14> be an <xref target="RFC3339"/> UTC timestamp with a trailing "Z". Each non-null digest <bcp14>MUST</bcp14> be an object with exactly one member, sha256, whose value is 64 lowercase hexadecimal digits. A null is allowed only where the applicable field rules permit it.</t><t>The digests of an outcome receipt are the members listed below, each with its full path in predicate, where [] stands for each entry of an array.</t><ul spacing="compact"><li>decisionRef</li><li>requestedActionDigest</li><li>actualActionDigest</li><li>responseDigest</li><li>effectDigest</li><li>receiverRefs[].digest</li><li>receiverRefs[].artifactDigest</li></ul><t>The timestamps of an outcome receipt are the members listed below.</t><ul spacing="compact"><li>performedAt</li><li>recordedAt</li></ul></li>
          <li>Binding. decisionRef.sha256 <bcp14>MUST</bcp14> equal the content root R of the decision receipt that passed <xref target="verify-decision"/>, and requestedActionDigest <bcp14>MUST</bcp14> equal its parametersDigest.</li>
          <li>Identity and separation. executor.id <bcp14>MUST</bcp14> equal the expected executor identifier supplied under <xref target="verify-inputs"/>. The verifier's trust policy <bcp14>MUST</bcp14> permit the outcome-signing key to attest that identifier. That key <bcp14>MUST</bcp14> differ from the decision maker's key, and executor.id <bcp14>MUST</bcp14> differ from decisionMaker.id. These checks do not establish that the two keys are controlled by operationally independent parties.</li>
          <li>Result. status executed <bcp14>MUST</bcp14> come with a non-null effectDigest. Where effect bytes are supplied, effectDigest <bcp14>MUST</bcp14> be present, whatever the status, and their SHA-256 <bcp14>MUST</bcp14> equal effectDigest.sha256.</li>
          <li>Time. performedAt <bcp14>MUST NOT</bcp14> be earlier than the decision's decidedAt and <bcp14>MUST</bcp14> be strictly earlier than its validity.expiresAt.</li>
        </ol>
      </section>
      <section anchor="sets">
        <name>Checks over a Set of Receipts</name>
        <t>An Auditor that holds the receipts and approval records of a run can check two properties that no single receipt shows. The Auditor <bcp14>MUST</bcp14> obtain the relying party's consumption scope from its audit context or trust policy; that scope is not inferred from an approvalId alone. First, within that scope, no two distinct ALLOW decision payloads, identified by different content roots, may cite approval records with the same identity (approvalId, actionDigest and session). Such a pair violates <xref target="approvals-once"/>; additional copies or signatures of one payload do not.</t>
        <t>Second, no outcome receipt with status executed may name, in decisionRef, the content root of a receipt with the verdict DENY or REFUSE. Both checks are only as complete as the set of receipts the Auditor holds. The first check does not detect two executions that reuse one ALLOW receipt without producing another decision receipt.</t>
      </section>
      <section anchor="verify-meaning">
        <name>What a Pass Shows</name>
        <t>A pass shows that the holder of the decision maker's key signed exactly these payload bytes. Where action bytes are supplied under <xref target="verify-inputs"/>, their SHA-256 matches proposedAction.parametersDigest.sha256. In Case 1, the SHA-256 of the required approval record bytes matches the digest.sha256 value of the unique inputSnapshot entry whose name is "approval record". For Case 3, a pass also shows that the holder of a different key, which the trust policy permits to attest the expected executor.id, signed an outcome with status executed bound to that decision. It does not show that the signer's statements are true, that the approval came from the named person, that the outcome signer observed the boundary, that no other receipt exists, or that the keys were not misused. Those questions belong to the trust policy, to signed approvals, to observers and to transparency registration (<xref target="registration"/>).</t>
      </section>
      <section anchor="registration">
        <name>Registering a Receipt with a Transparency Service</name>
        <t>This section is informative. It describes how the receipts of this document can be registered with a Transparency Service under <xref target="RFC9943"/>. It defines no format, predicate type, media type or registry and adds no requirement to those of <xref target="RFC9943"/>.</t>
        <t>Registration. In SCITT a Signed Statement is a COSE_Sign1 message whose protected header carries CWT Claims with an Issuer Claim and a Subject Claim (<xref target="RFC9943" section="6"/>). A decision receipt or an outcome receipt can be registered in two ways. Its envelope bytes can be the payload of a Signed Statement. Or, as <xref target="RFC9943" section="6.2"/> allows for Statements too large or too sensitive to send to a Transparency Service, the Signed Statement can be made over a hash, here the content root of the receipt. This document does not define how a Signed Statement indicates the hash, its algorithm or its content type; that belongs to a deployment's profile and to the Registration Policy of the Transparency Service (<xref target="RFC9943" section="5.1.1"/>).</t>
        <t><xref target="vectors-registration"/> gives one example Signed Statement for each of the two ways, with a SCITT Receipt for each.</t>
        <t>Issuer. The Issuer of the Signed Statement is the entity identified by its iss Claim, whose key signs the COSE_Sign1 (Sections <xref target="RFC9943" section="3" sectionFormat="bare"/> and <xref target="RFC9943" section="6" sectionFormat="bare"/> of <xref target="RFC9943"/>). It can be the decision maker or the outcome signer, or another party such as the Auditing Service of <xref target="AUDIT-ARCH" section="4.2"/>. The Client that registers a Signed Statement need not be its Issuer (<xref target="RFC9943" section="7"/>). The Issuer's COSE signature is separate from the DSSE signature of the receipt. The COSE signature authenticates the Signed Statement's protected header and payload. The DSSE signature covers the pre-authentication encoding of the receipt's payloadType and decoded payload bytes, not the DSSE envelope as a whole. <xref target="verify-decision"/> or <xref target="verify-outcome"/> checks that DSSE signature and its signer.</t>
        <t>What a SCITT Receipt shows. During Registration the Transparency Service verifies the Issuer's signature and applies its Registration Policy (Sections <xref target="RFC9943" section="5.1.1.1" sectionFormat="bare"/> and <xref target="RFC9943" section="6.3" sectionFormat="bare"/> of <xref target="RFC9943"/>). It registers the Signed Statement before it releases a Receipt (<xref target="RFC9943" section="6.3"/>), and the Receipt demonstrates inclusion of the Signed Statement in the Verifiable Data Structure of the Transparency Service and can be verified without online access to it (<xref target="RFC9943" section="4"/>). The Transparency Service records the Registration time when it adds the Signed Statement (<xref target="RFC9943" section="7"/>).</t>
        <t>What it does not show. Registering a Statement proves only that it was produced by an Issuer, not that it is accurate (<xref target="RFC9943" section="9.2"/>). Issuers can register some Statements and not others (<xref target="RFC9943" section="9.3"/>), so a Receipt for one receipt says nothing about a receipt that was never registered. The Subject Claim lets Relying Parties identify the Transparent Statements registered for a Subject (<xref target="RFC9943" section="3"/>), not receipts that were never registered. Unless the Registration Policy says otherwise, the order of the Verifiable Data Structure need not be the order of issuance (<xref target="RFC9943" section="9.1"/>). A Receipt does not change what the checks of <xref target="verification"/> show, and it does not make an ALLOW an authorization.</t>
        <t>Verification. A verifier checks the SCITT Receipt for the particular Signed Statement, including its inclusion proof, using the verification key of a Receipt Issuer it trusts and the verification rules for the applicable Verifiable Data Structure (Sections <xref target="RFC9943" section="7" sectionFormat="bare"/> and <xref target="RFC9943" section="7.1" sectionFormat="bare"/> of <xref target="RFC9943"/>). It establishes the binding from the registered Signed Statement to the envelope bytes or content root used in the following checks. If the Signed Statement's COSE payload is detached and this binding depends on the Issuer's signature, it verifies that signature. It then applies <xref target="verification"/> of this document to the receipt. Where the envelope bytes are the Signed Statement's payload, it checks those bytes; where the Signed Statement is made over the content root, it checks an envelope whose computed content root equals the registered value. This latter comparison binds the decoded DSSE payload, not the envelope bytes or the DSSE signature, and does not establish that the DSSE signature existed when the content root was registered. <xref target="RFC9943" section="7.1"/> permits verification of a Receipt without rechecking the Issuer's signature on the Signed Statement; this does not dispense with the binding just described. The signatures of the decision maker and of the outcome signer are checked by <xref target="verification"/> in either case.</t>
      </section>
      <section anchor="field-rules">
        <name>Field Rules</name>
        <t>Step 7 of <xref target="verify-decision"/> and step 3 of <xref target="verify-outcome"/> apply the rules of this section. <xref target="tab-fields-decision"/> lists every member of the predicate of a decision receipt that this document admits, and <xref target="tab-fields-outcome"/> every member of the predicate of an outcome receipt, each with its full path in predicate, where [] stands for each entry of an array. The rules follow the strict v0.1 form of <xref target="PB-DECISION"/> and <xref target="PB-OUTCOME"/> and their machine schemas, restricted to the members this document admits; where <xref target="verify-decision"/> is stricter, the table gives the stricter rule. This section states these rules itself, and its tables follow those documents as they stand at commit e1fec86351b216af369a2e6ac106dcc41aaf4b4c of <xref target="PB-REPO"/>, where the machine schemas are the same as in version 6.4.0.</t>
        <t>In the column Type, a digest is an object with exactly one member, sha256, whose value is 64 lowercase hexadecimal digits; a timestamp is an <xref target="RFC3339"/> UTC timestamp with a trailing "Z"; typedDigest has the form given in step 7 of <xref target="verify-decision"/>; a string is any JSON string, and a non-empty string has at least one character; a boolean is one of the JSON values true or false; any value is any JSON value. The type object admits only the members listed for it, and the type open object admits any members. The type names preActionAuthorization and outcome allow only the JSON strings "preActionAuthorization" and "outcome", respectively. The type "0.1." and one or more digits means a string consisting of "0.1." followed by one or more ASCII decimal digits. The notes (1) to (4) follow the tables.</t>
        <t>Required yes means that the member <bcp14>MUST</bcp14> be present whenever the object or array entry that contains it is present. Null yes means that the member may be null. Everywhere else a null is not allowed, also inside an open object and in an array of any values. A member that the table does not list for an object that is not open is not allowed, at the top level of predicate as well.</t>
        <table anchor="tab-fields-decision">
          <name>Members of the predicate of a decision receipt</name>
          <thead><tr><th>Member</th><th>Type</th><th>Required</th><th>Null</th></tr></thead>
          <tbody><tr><td>schemaVersion</td><td>"0.1." and one or more digits</td><td>yes</td><td>no</td></tr><tr><td>decisionId</td><td>non-empty string</td><td>yes</td><td>no</td></tr><tr><td>decisionType</td><td>preActionAuthorization</td><td>yes</td><td>no</td></tr><tr><td>decidedAt</td><td>timestamp</td><td>yes</td><td>no</td></tr><tr><td>recordedAt</td><td>timestamp</td><td>no</td><td>no</td></tr><tr><td>decisionMaker</td><td>object</td><td>yes</td><td>no</td></tr><tr><td>decisionMaker.id</td><td>non-empty string</td><td>yes</td><td>no</td></tr><tr><td>decisionMaker.version</td><td>any value</td><td>no</td><td>yes</td></tr><tr><td>agent</td><td>object</td><td>yes</td><td>no</td></tr><tr><td>agent.id</td><td>non-empty string</td><td>yes</td><td>no</td></tr><tr><td>agent.version</td><td>string</td><td>no</td><td>no</td></tr><tr><td>agent.configurationDigest</td><td>digest</td><td>no</td><td>no</td></tr><tr><td>principal</td><td>object</td><td>yes</td><td>no</td></tr><tr><td>principal.id</td><td>non-empty string</td><td>yes</td><td>no</td></tr><tr><td>principal.authnContextRef</td><td>object</td><td>no</td><td>no</td></tr><tr><td>principal.authnContextRef.<br/>uri</td><td>string</td><td>no</td><td>no</td></tr><tr><td>principal.authnContextRef.<br/>digest</td><td>digest</td><td>no</td><td>no</td></tr><tr><td>delegationRefs</td><td>array of any values</td><td>no</td><td>no</td></tr><tr><td>proposedAction</td><td>object</td><td>yes</td><td>no</td></tr><tr><td>proposedAction.actionType</td><td>string</td><td>yes</td><td>no</td></tr><tr><td>proposedAction.target</td><td>object</td><td>no</td><td>no</td></tr><tr><td>proposedAction.target.name</td><td>string</td><td>no</td><td>no</td></tr><tr><td>proposedAction.target.uri</td><td>string</td><td>no</td><td>no</td></tr><tr><td>proposedAction.target.<br/>digest</td><td>digest</td><td>no</td><td>no</td></tr><tr><td>proposedAction.method</td><td>string</td><td>no</td><td>no</td></tr><tr><td>proposedAction.<br/>parametersDigest</td><td>digest</td><td>(1)</td><td>no</td></tr><tr><td>proposedAction.<br/>parametersRef</td><td>open object</td><td>(1)</td><td>no</td></tr><tr><td>proposedAction.<br/>parametersSchemaRef</td><td>object</td><td>no</td><td>no</td></tr><tr><td>proposedAction.<br/>parametersSchemaRef.uri</td><td>string</td><td>no</td><td>no</td></tr><tr><td>proposedAction.<br/>parametersSchemaRef.digest</td><td>digest</td><td>no</td><td>no</td></tr><tr><td>inputSnapshot</td><td>array of objects</td><td>yes</td><td>no</td></tr><tr><td>inputSnapshot[].name</td><td>string</td><td>no</td><td>no</td></tr><tr><td>inputSnapshot[].uri</td><td>string</td><td>no</td><td>no</td></tr><tr><td>inputSnapshot[].digest</td><td>digest</td><td>yes</td><td>no</td></tr><tr><td>inputSnapshot[].mediaType</td><td>string</td><td>no</td><td>no</td></tr><tr><td>policyBoundary</td><td>object</td><td>yes</td><td>no</td></tr><tr><td>policyBoundary.<br/>policyEngine</td><td>non-empty string</td><td>yes</td><td>no</td></tr><tr><td>policyBoundary.policyId</td><td>non-empty string</td><td>yes</td><td>no</td></tr><tr><td>policyBoundary.<br/>decisionPath</td><td>non-empty string</td><td>yes</td><td>no</td></tr><tr><td>policyBoundary.<br/>policyDigest</td><td>digest</td><td>yes</td><td>no</td></tr><tr><td>policyBoundary.<br/>bundleRevision</td><td>string</td><td>no</td><td>no</td></tr><tr><td>policyBoundary.validFrom</td><td>timestamp</td><td>no</td><td>no</td></tr><tr><td>policyBoundary.validUntil</td><td>timestamp</td><td>no</td><td>no</td></tr><tr><td>evidenceRefs</td><td>array of objects</td><td>yes</td><td>no</td></tr><tr><td>evidenceRefs[].relation</td><td>string</td><td>yes</td><td>no</td></tr><tr><td>evidenceRefs[].digest</td><td>digest</td><td>yes</td><td>no</td></tr><tr><td>evidenceRefs[].<br/>artifactDigest</td><td>digest</td><td>no</td><td>no</td></tr><tr><td>evidenceRefs[].uri</td><td>string</td><td>no</td><td>no</td></tr><tr><td>evidenceRefs[].<br/>predicateType</td><td>string</td><td>no</td><td>no</td></tr><tr><td>evidenceRefs[].typedDigest</td><td>typedDigest</td><td>no</td><td>no</td></tr><tr><td>decision</td><td>object</td><td>yes</td><td>no</td></tr><tr><td>decision.verdict</td><td>(2)</td><td>yes</td><td>no</td></tr><tr><td>decision.reasonCodes</td><td>non-empty array of non-empty strings</td><td>yes</td><td>no</td></tr><tr><td>decision.<br/>humanReadableSummary</td><td>string</td><td>no</td><td>no</td></tr><tr><td>decision.obligations</td><td>array of any values</td><td>no</td><td>no</td></tr><tr><td>decision.allowedScope</td><td>array of any values</td><td>no</td><td>no</td></tr><tr><td>notChecked</td><td>array of objects or strings</td><td>yes</td><td>no</td></tr><tr><td>notChecked[].field</td><td>string</td><td>no</td><td>no</td></tr><tr><td>notChecked[].reason</td><td>string</td><td>no</td><td>no</td></tr><tr><td>notChecked[].impact</td><td>string</td><td>no</td><td>no</td></tr><tr><td>decisionChangeConditions</td><td>array of objects</td><td>yes</td><td>no</td></tr><tr><td>decisionChangeConditions[].<br/>conditionType</td><td>string</td><td>no</td><td>no</td></tr><tr><td>decisionChangeConditions[].<br/>description</td><td>string</td><td>no</td><td>no</td></tr><tr><td>decisionChangeConditions[].<br/>requiredEvidenceType</td><td>string</td><td>no</td><td>no</td></tr><tr><td>actionOutcome</td><td>object</td><td>no</td><td>no</td></tr><tr><td>actionOutcome.status</td><td>(3)</td><td>no</td><td>no</td></tr><tr><td>actionOutcome.performedAt</td><td>timestamp</td><td>no</td><td>yes</td></tr><tr><td>actionOutcome.outcomeRef</td><td>object</td><td>no</td><td>yes</td></tr><tr><td>actionOutcome.outcomeRef.<br/>uri</td><td>string</td><td>no</td><td>no</td></tr><tr><td>actionOutcome.outcomeRef.<br/>digest</td><td>digest</td><td>no</td><td>no</td></tr><tr><td>traceContext</td><td>open object</td><td>no</td><td>no</td></tr><tr><td>privacy</td><td>object</td><td>yes</td><td>no</td></tr><tr><td>privacy.rawInputsIncluded</td><td>boolean</td><td>yes</td><td>no</td></tr><tr><td>privacy.redactionProfile</td><td>string</td><td>no</td><td>no</td></tr><tr><td>privacy.erased</td><td>array of any values</td><td>no</td><td>no</td></tr><tr><td>privacy.masked</td><td>array of any values</td><td>no</td><td>no</td></tr><tr><td>validity</td><td>object</td><td>yes</td><td>no</td></tr><tr><td>validity.audience</td><td>non-empty array of non-empty strings</td><td>yes</td><td>no</td></tr><tr><td>validity.nonce</td><td>non-empty string</td><td>yes</td><td>no</td></tr><tr><td>validity.expiresAt</td><td>timestamp</td><td>yes</td><td>no</td></tr></tbody>
        </table>
        <table anchor="tab-fields-outcome">
          <name>Members of the predicate of an outcome receipt</name>
          <thead><tr><th>Member</th><th>Type</th><th>Required</th><th>Null</th></tr></thead>
          <tbody><tr><td>schemaVersion</td><td>"0.1." and one or more digits</td><td>yes</td><td>no</td></tr><tr><td>outcomeId</td><td>non-empty string</td><td>yes</td><td>no</td></tr><tr><td>decisionRef</td><td>digest</td><td>yes</td><td>no</td></tr><tr><td>executor</td><td>object</td><td>yes</td><td>no</td></tr><tr><td>executor.id</td><td>non-empty string</td><td>yes</td><td>no</td></tr><tr><td>executor.keyId</td><td>string</td><td>no</td><td>no</td></tr><tr><td>requestedActionDigest</td><td>digest</td><td>yes</td><td>no</td></tr><tr><td>status</td><td>(4)</td><td>yes</td><td>no</td></tr><tr><td>performedAt</td><td>timestamp</td><td>yes</td><td>no</td></tr><tr><td>effectDigest</td><td>digest</td><td>no</td><td>no</td></tr><tr><td>actualActionDigest</td><td>digest</td><td>no</td><td>no</td></tr><tr><td>responseDigest</td><td>digest</td><td>no</td><td>no</td></tr><tr><td>policyPurpose</td><td>outcome</td><td>no</td><td>no</td></tr><tr><td>receiverRefs</td><td>array of objects</td><td>no</td><td>no</td></tr><tr><td>receiverRefs[].relation</td><td>non-empty string</td><td>yes</td><td>no</td></tr><tr><td>receiverRefs[].digest</td><td>digest</td><td>yes</td><td>no</td></tr><tr><td>receiverRefs[].receiverId</td><td>string</td><td>no</td><td>no</td></tr><tr><td>receiverRefs[].<br/>receiverKeyId</td><td>string</td><td>no</td><td>no</td></tr><tr><td>receiverRefs[].<br/>artifactDigest</td><td>digest</td><td>no</td><td>no</td></tr><tr><td>sequence</td><td>object</td><td>no</td><td>no</td></tr><tr><td>sequence.runId</td><td>non-empty string</td><td>yes</td><td>no</td></tr><tr><td>sequence.seq</td><td>integer, 0 or more</td><td>yes</td><td>no</td></tr><tr><td>recordedAt</td><td>timestamp</td><td>no</td><td>no</td></tr><tr><td>limitations</td><td>array of strings</td><td>no</td><td>no</td></tr><tr><td>traceContext</td><td>object</td><td>no</td><td>no</td></tr><tr><td>traceContext.traceparent</td><td>string</td><td>no</td><td>no</td></tr><tr><td>validity</td><td>object</td><td>no</td><td>no</td></tr><tr><td>validity.audience</td><td>array of any values</td><td>no</td><td>no</td></tr><tr><td>validity.nonce</td><td>string</td><td>no</td><td>no</td></tr></tbody>
        </table>
        <t>The notes of the tables are as follows. (1) proposedAction <bcp14>MUST</bcp14> carry parametersDigest, parametersRef or both. (2) decision.verdict is ALLOW, DENY, REFUSE, ESCALATE, DEFER or OBSERVE. (3) actionOutcome.status is notAttempted, blocked, refused, attempted, executed, failed or unknown. (4) status is executed, refused, failed or partial. <xref target="verify-cases"/> adds rules per case, and steps 8 to 10 of <xref target="verify-decision"/> and steps 4 to 7 of <xref target="verify-outcome"/> add rules across members.</t>
      </section>
    </section>

<section anchor="approvals-once">
      <name>Approvals Are Honoured At Most Once</name>
      <t>An approval in Case 1 frees one action once. For live use, the relying party <bcp14>MUST</bcp14> apply the time bounds of <xref target="verify-cases"/> with its own current time as T. A historical audit time <bcp14>MUST NOT</bcp14> make an expired approval usable. A relying party that lets an action run because of an approval:</t>
      <ol>
        <li><bcp14>MUST</bcp14> honour each approval at most once;</li>
        <li><bcp14>MUST</bcp14> key its consumption state by the identity of the approval (approvalId, actionDigest and session), not by the bytes of one copy of the approval record. Copies or reissues with other metadata count as the same approval and <bcp14>MUST NOT</bcp14> extend its original validUntil. Extending that validity requires a new approval act and a new approvalId;</li>
        <li><bcp14>MUST</bcp14> mark the approval as consumed durably before it either allows the action to run or releases a signed ALLOW that cites the approval;</li>
        <li><bcp14>MUST</bcp14> treat an approval recorded as consumed in any current, rotated, archived or compacted representation as consumed for as long as item 6 requires that state to be retained;</li>
        <li><bcp14>MUST NOT</bcp14> honour an approval unless it can consult a complete, durable view of the consumption state required by this section. Rotation, archiving or compaction <bcp14>MAY</bcp14> replace earlier generations if all entries still required by item 6 are preserved. Missing or unreadable state whose required entries have not been preserved elsewhere <bcp14>MUST</bcp14> cause refusal;</li>
        <li><bcp14>MAY</bcp14> drop an entry only after the approval's original validUntil, plus the clock skew the relying party allows, has passed and no copy of that approval can still be honoured.</li>
      </ol>
      <t>Rotation is the step where this requirement is most easily lost. A record that is full is moved aside so that new approvals can be written; if the relying party then reads only the new generation, approvals of the old one may become usable again. Items 4 and 5 preserve the consumed state without requiring a particular storage format. A decision receipt for Case 1 binds the approval record by digest, so <xref target="sets"/> can expose distinct ALLOW decisions for the same approval identity. Preventing reuse of an approval or of an already issued ALLOW remains the relying party's duty.</t>
    </section>

<section anchor="implementation-status">
      <name>Implementation Status</name>
      <t>This section is given per <xref target="RFC7942"/> and is to be removed by the RFC
Editor before publication.</t>
      <t>proofbundle 6.4.0 is on PyPI <xref target="PB-PYPI"/> with the classifier "Development Status :: 4 - Beta"; its tag v6.4.0 is commit 699545521ec5ef479bb84e61fe7461fc79ed558c of <xref target="PB-REPO"/>. There the decision receipt predicate is described as shipped since version 2.1.0 and the outcome predicate as experimental. In the seven command line runs reported in <xref target="vectors"/>, the four passing vectors returned exit code 0, the invalid signature of V1-bad returned 1, and the non-canonical payload of V2-bad and the decision binding mismatch of V3-bad each returned 2. These results do not specify the command line interface's complete exit-code contract.</t>
      <t>Agent Guard is the name used here for the preview in plugins/proofbundle of the same repository, inspected at commit 8bb289c8b41d32c54734155fc00756231093bc2a. This inspected revision is not the release tag v6.4.0. Its public README names the preview the proofbundle plugin for Claude Code and Codex.</t>
      <t>In the inspected code, the configured receipt pilot uses a separate signing service for preActionAuthorization decisions with verdict ALLOW, DENY or ESCALATE for the writes it supports. An observer signs outcome receipts for effects it matches to decisions. The runbook assigns the observer to an operator account separate from the agent session. The approval path requires an explicit operator configuration and is not enabled under Codex. It binds an approval to the command bytes and its session. Its time check accepts the approval from 60 seconds before the recorded answer, to allow for clock skew, through 15 minutes after it. For a write covered by the receipt pilot, the hook obtains a signed ALLOW before recording its own use of the approval and allowing the command. These are observations of the source and runbook, not a live Agent Guard execution measured for this document.</t>
      <t>The seven DSSE test vectors described in <xref target="vectors-table"/> were produced with proofbundle 6.4.0 from PyPI and test keys, not by Agent Guard. For an approval, the inspected pilot writes released_by_owner among its reason codes where those vectors write user_approval. It does not put the approval record's digest into inputSnapshot, may add the digest of configured closing rules there, sets no traceContext or actionOutcome, and leaves evidenceRefs empty. Those vectors therefore do not demonstrate that the preview produces Case 1 receipts conforming to this document.</t>
      <t>At the inspected commit, the signing service keeps its record of honoured approvals without eviction and refuses a new approval when the record holds 4096. The runbook has an operator rotate a full record, with the service stopped, by copying it into the folder honoured-releases of the records and then removing it. The service treats an approval named in the current record or in any file of that folder as honoured, before its decision and again under its lock before it releases the signature. If that folder or a file in it is a symbolic link, is owned by an account other than root or the service's own, or is writable by another account, or if a file there does not read as a record, the service releases no signature in the configuration in which it honours approvals.</t>
      <t>The hook keeps its own record of the approvals it has used, keyed by an identity that excludes the answer time, and treats a copy of a used approval as used whatever answer time it carries. When the record holds 1024 uses, the hook removes only uses recorded more than 15 minutes and 60 seconds earlier, after which the copy that was used is no longer within its window, and keeps a digest of each removed identity, which it does not remove; a copy of such an identity is refused. If the record is still full, would exceed 512 KiB, contains a field the hook does not know, or cannot be read or written, the hook does not honour the approval.</t>
      <t>In both layers the validity window is taken from the answer time of the copy in use, and neither keeps an original validity per identity. For an identity that has not yet been used, a copy with a later answer time therefore opens a later window; item 2 of <xref target="approvals-once"/> does not permit that.</t>
      <t>At the earlier commit ba8466d1a04334a5d83b3eaa12e30a464cc9d686, the signing service did not read archived records and the hook removed its oldest use without checking that entry's age; both were gaps relative to <xref target="approvals-once"/>.</t>
      <t>No conformance of Agent Guard to <xref target="approvals-once"/> and no enforcement of single use in a running host is claimed from these source-level observations.</t>
      <t>The separate Go checker supplied with the vectors and the proofbundle 6.4.0 command line interface agree on acceptance or rejection of all seven vectors. This comparison does not establish complete equivalence of the verifiers, conformance of Agent Guard to Sections 3 and 4, or enforcement of single use in a running host. No later implementation revision is assessed here.</t>
      <t>This information is given per <xref target="RFC7942"/> and does not constitute endorsement.</t>
    </section>

<section anchor="related">
      <name>Relation to Other Work</name>
      <t><xref target="GILDA"/> defines one in-toto predicate type, signed in DSSE with <xref target="RFC8785"/> canonical bytes, that carries an authorization decision and the observed effect together with a derived agreement between them, and offers it as a data model for AUDIT records. This document keeps decision and outcome in two receipts signed under different keys and maps three cases onto the architecture; the consumption-state input that <xref target="GILDA"/> names concerns the same kind of state as <xref target="approvals-once"/>. <xref target="GILDA"/> lets records carry a sequence number, so that a record withheld from a party that holds a later record of the same series can be detected (<xref target="GILDA" section="6.3"/>); the decision receipts of this document carry no such member (<xref target="verify-decision"/>). <xref target="GILDA"/> also derives the agreement between decision and effect inside one record (<xref target="GILDA" section="5.3"/>), where this document compares two receipts through decisionRef (<xref target="verify-outcome"/>).</t>
      <t><xref target="IZMAYLOV"/> specifies permissions that a principal signs with a passkey and action receipts signed by the agent, linked to earlier receipts and appended to a log by a recorder. It also defines a passkey-signed approval of one action. Such an approval could supply additional evidence for Case 1. Citing it by digest does not replace the approval record or the checks of <xref target="verify-cases"/>; this document defines no mapping from that format to the approval record. In <xref target="IZMAYLOV"/> each action receipt carries its place in a chain; every receipt after the first also names the preceding receipt by digest. It is signed with the agent's keys or, for a helper, with the keys in the to member of its delegation (<xref target="IZMAYLOV" section="6"/>). Here the decision maker signs a decision receipt and the executor or an observer signs an outcome receipt (<xref target="verify-inputs"/>); a verifier checks that executor.id differs from decisionMaker.id (<xref target="verify-outcome"/>). <xref target="verify-decision"/> does not define a chain of decision receipts.</t>
      <t><xref target="WRIGHT"/> defines a verdict record that states a result on a claim and
cites its evidence by digest, in any receipt format. A decision or outcome receipt of
this document can be such evidence, and a verdict record can state the result of the
procedure of <xref target="verification"/>. Following <xref target="WRIGHT" section="7"/>, a verdict record cites a receipt of this document as an evidence item by the SHA-256 over its exact envelope bytes; the content root R of step 5 of <xref target="verify-decision"/> is a different digest, over the payload bytes, which a verdict record cites at most by citing those payload bytes as an item of its own.</t>
      <t><xref target="BIRKHOLZ"/> defines a data format for agent conversation records protected by COSE signatures, which <xref target="AUDIT-ARCH"/> names as a candidate for Interaction Records. A signed conversation record can be cited by digest as additional input. Establishing which entry records a human approval and how it corresponds to the action, approver, session and validity of Case 1 requires a mapping not defined here. The approval record and the checks of <xref target="verify-cases"/> still apply.</t>
      <t>SCITT <xref target="RFC9943"/> registers Signed Statements with a Transparency Service, which returns Receipts. <xref target="registration"/> describes how a decision or outcome receipt can be registered and what a Receipt then shows.</t>
    </section>

<section anchor="security-considerations">
      <name>Security Considerations</name>
      <t>Key binding. A receipt is only as trustworthy as the verifier's choice of keys and its policy for the identities those keys may attest. <xref target="verify-decision"/> checks decisionMaker.id; <xref target="verify-outcome"/> checks the expected executor.id under the outcome-signing key. An observer's signature over an executor identifier is not the executor's own signature. A key held in the recorded Agent's process gives an Auditor that does not trust that Agent little assurance. The inspected Agent Guard design uses separate service accounts as described in <xref target="implementation-status"/>.</t>
      <t>Key compromise. Whoever holds the signing key of a decision maker or of an outcome signer can produce receipts with any decidedAt or performedAt, since these times come from the signer's clock, as the paragraph on clocks below says. A check under <xref target="verification"/> does not tell such a receipt from one signed before the key was compromised or replaced. Which keys are accepted for which identity and for which period is set by the verifier's trust policy, not by this document; <xref target="RFC9943"/> likewise leaves revocation strategies for compromised keys out of its scope (<xref target="RFC9943" section="9.4.2"/>). A time anchor outside the signer helps, if it was set before the compromise. Where the envelope bytes are the payload of a registered Signed Statement (<xref target="registration"/>), a Receipt for it shows that the DSSE signature existed when that Signed Statement was registered, and the Transparency Service records the Registration time (<xref target="RFC9943" section="7"/>). Where the Signed Statement is made over the content root, the comparison binds the decoded DSSE payload, not the envelope bytes or the DSSE signature, and does not establish that the DSSE signature existed when the content root was registered (<xref target="registration"/>). The rules of <xref target="approvals-once"/> keep a relying party from honouring one approval more than once; they do not prevent the holder of a compromised decision maker key from signing receipts that cite approvals with new identities.</t>
      <t>Exact bytes. A verifier that re-serializes a payload before checking it can be
led to accept bytes that were never signed, or to compute another content root.
Step 4 refuses such payloads, and vector V2-bad tests it.</t>
      <t>Replay. An ALLOW for one action must not free another, and an outcome that names another decision must not count as the result of this one. parametersDigest binds the action bytes, validity binds audience, nonce and expiry, decisionRef binds the outcome, and <xref target="approvals-once"/> requires the relying party to prevent reuse of an approval. V1-bad tests rejection of changed payload bytes under an unchanged signature. V3-bad tests rejection of an outcome bound to a different decision. The seven vectors do not test consumption-state retention or rotation; F13 in <xref target="vectors-failure"/> tests rotation.</t>
      <t>Self-assertion. actionOutcome in a decision receipt and an outcome receipt whose
effect cannot be resolved are statements of their signers. A digest that is present
but cannot be resolved to bytes was chosen by the signer.</t>
      <t>Suppression. A decision maker can fail to write a receipt for a decision it does not want seen. Independent observers at the boundary, as the architecture requires for Action Records, reduce this risk. Registration with a Transparency Service helps address selective registration when Relying Parties accept a Signed Statement only if they can discover and verify a Receipt for that Signed Statement from a Transparency Service they trust (Sections <xref target="RFC9943" section="7.1" sectionFormat="bare"/> and <xref target="RFC9943" section="9.3" sectionFormat="bare"/> of <xref target="RFC9943"/>). This document does not ensure that a receipt is produced for every decision. A SCITT Receipt shows inclusion of the registered Signed Statement, not that every receipt was registered (<xref target="registration"/>). Completeness presupposes an expectation of which receipts ought to exist, and this document does not define that expectation.</t>
      <t>Gaps. For outcome receipts, <xref target="PB-OUTCOME"/> defines an optional member sequence, with a run identifier and a counter that an executor can opt into (its sections 4 and 7); <xref target="verify-outcome"/> admits that member. A verifier that holds numbered outcome receipts of a run can report a gap in the numbers it has. Such a gap can reflect withholding or delivery delay; the numbers alone do not establish its cause. Those sequence numbers alone do not show whether receipts above the highest observed number have been withheld, and a run without the member leaves no such trace (compare <xref target="GILDA" section="6.3"/>). The profile of <xref target="verify-decision"/> defines no sequence counter or chain of decision receipts. Records that a Service or Tool emits at the boundary where an action took effect (<xref target="AUDIT-ARCH" section="4.1"/>) can expose an effect for which the Auditor has no matching decision receipt.</t>
      <t>Clocks. decidedAt and performedAt come from the signers' clocks. Ordering against outside events needs a timestamp or a transparency registration. A verified time-stamp token under <xref target="RFC3161"/> for a hash of the envelope bytes is, like a registration (<xref target="registration"/>), an anchor outside the signer for a verifier that trusts the time-stamping authority. It supports the assertion that those bytes existed no later than genTime plus the applicable accuracy (<xref target="RFC3161" section="2.4.2"/>). If the accuracy field is absent, the accuracy may be available through other means, such as the TSA policy; its absence does not establish zero uncertainty.</t>
    </section>

<section anchor="privacy-considerations">
      <name>Privacy Considerations</name>
      <t>The example receipts in <xref target="vectors"/> carry digests of action bytes, approval records and effects rather than those bytes, and the example decision receipts set privacy.rawInputsIncluded to false. The field rules of <xref target="field-rules"/> allow that member to be true and permit raw content in other admitted members, such as a decision receipt's open traceContext object. A successful check under <xref target="verification"/> does not establish that raw inputs are absent. A digest of a short or predictable input, such as a command line, can be found by trying candidate inputs; a deployment that must hide such inputs keeps the receipts as private as the inputs, or adds a secret salt to the digested bytes. Identifiers such as principal.id, agent.id and traceContext link a person's actions across services, as <xref target="AUDIT-ARCH" section="9"/> describes; pairwise or opaque identifiers reduce that linkage. Registration shows that the registered Signed Statement existed by the time of registration, not when the decision was taken. Where that Statement is made over the content root, it does not establish that the receipt's DSSE signature existed at that time (<xref target="registration"/>). Where the envelope bytes are the payload of a registered Signed Statement (<xref target="registration"/>), readers of that payload can read the receipt with its identifiers and digests. Registering a Statement over the content root avoids including the receipt's envelope bytes in that Statement, but the Signed Statement still carries its Issuer and Subject Claims and the Transparency Service records the Registration time (Sections <xref target="RFC9943" section="6" sectionFormat="bare"/> and <xref target="RFC9943" section="7" sectionFormat="bare"/> of <xref target="RFC9943"/>). Access to the registered data and any detached payload depends on the Transparency Service and any Adjacent Services; Issuers and Clients assess their privacy and security posture before registration (<xref target="RFC9943" section="8"/>).</t>
    </section>

<section anchor="iana-considerations">
      <name>IANA Considerations</name>
      <t>This document has no IANA actions.</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"><organization/></author>
            <date year="1997" month="March"/>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="2119"/>
          <seriesInfo name="DOI" value="10.17487/RFC2119"/>
        </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"><organization/></author>
            <date year="2017" month="May"/>
          </front>
          <seriesInfo name="BCP" value="14"/>
          <seriesInfo name="RFC" value="8174"/>
          <seriesInfo name="DOI" value="10.17487/RFC8174"/>
        </reference>
        <reference anchor="RFC8785" target="https://www.rfc-editor.org/info/rfc8785">
          <front>
            <title>JSON Canonicalization Scheme (JCS)</title>
            <author initials="A." surname="Rundgren"><organization/></author>
            <author initials="B." surname="Jordan"><organization/></author>
            <author initials="S." surname="Erdtman"><organization/></author>
            <date year="2020" month="June"/>
          </front>
          <seriesInfo name="RFC" value="8785"/>
          <seriesInfo name="DOI" value="10.17487/RFC8785"/>
        </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"><organization/></author>
            <date year="2017" month="December"/>
          </front>
          <seriesInfo name="STD" value="90"/>
          <seriesInfo name="RFC" value="8259"/>
          <seriesInfo name="DOI" value="10.17487/RFC8259"/>
        </reference>
        <reference anchor="RFC8032" target="https://www.rfc-editor.org/info/rfc8032">
          <front>
            <title>Edwards-Curve Digital Signature Algorithm (EdDSA)</title>
            <author initials="S." surname="Josefsson"><organization/></author>
            <author initials="I." surname="Liusvaara"><organization/></author>
            <date year="2017" month="January"/>
          </front>
          <seriesInfo name="RFC" value="8032"/>
          <seriesInfo name="DOI" value="10.17487/RFC8032"/>
        </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"><organization/></author>
            <author initials="T." surname="Hansen"><organization/></author>
            <date year="2011" month="May"/>
          </front>
          <seriesInfo name="RFC" value="6234"/>
          <seriesInfo name="DOI" value="10.17487/RFC6234"/>
        </reference>
        <reference anchor="RFC4648" target="https://www.rfc-editor.org/info/rfc4648">
          <front>
            <title>The Base16, Base32, and Base64 Data Encodings</title>
            <author initials="S." surname="Josefsson"><organization/></author>
            <date year="2006" month="October"/>
          </front>
          <seriesInfo name="RFC" value="4648"/>
          <seriesInfo name="DOI" value="10.17487/RFC4648"/>
        </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"><organization/></author>
            <author initials="C." surname="Newman"><organization/></author>
            <date year="2002" month="July"/>
          </front>
          <seriesInfo name="RFC" value="3339"/>
          <seriesInfo name="DOI" value="10.17487/RFC3339"/>
        </reference>
        <reference anchor="DSSE" target="https://github.com/secure-systems-lab/dsse/blob/v1.0.2/protocol.md">
          <front>
            <title>DSSE: Dead Simple Signing Envelope, protocol specification, version 1.0.2</title>
            <author><organization>Secure Systems Lab</organization></author>
            <date year="2024" month="May" day="28"/>
          </front>
        </reference>
        <reference anchor="INTOTO-STATEMENT" target="https://github.com/in-toto/attestation/blob/v1.2.0/spec/v1/statement.md">
          <front>
            <title>in-toto Attestation Framework: Statement layer, v1 (release v1.2.0)</title>
            <author><organization>in-toto project</organization></author>
            <date year="2026" month="March" day="18"/>
          </front>
        </reference>
      </references>
      <references>
        <name>Informative References</name>
        <reference anchor="AUDIT-ARCH" target="https://datatracker.ietf.org/doc/html/draft-kuehlewind-audit-architecture-01">
          <front>
            <title>An Architecture for Auditing Agent Delegation and Interactions</title>
            <author initials="M." surname="Kuehlewind"><organization/></author>
            <author initials="H." surname="Birkholz"><organization/></author>
            <date year="2026" month="September" day="7"/>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-kuehlewind-audit-architecture-01"/>
        </reference>
        <reference anchor="GILDA" target="https://datatracker.ietf.org/doc/html/draft-gilda-audit-agent-audit-record-03">
          <front>
            <title>An Audit Record Format for AI Agent Authorization Decisions</title>
            <author initials="S." surname="Gilda"><organization/></author>
            <date year="2026" month="October" day="29"/>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-gilda-audit-agent-audit-record-03"/>
        </reference>
        <reference anchor="IZMAYLOV" target="https://datatracker.ietf.org/doc/html/draft-izmaylov-agent-permission-receipts-02">
          <front>
            <title>Signed Permissions and Action Receipts for Automated Agents</title>
            <author initials="P." surname="Izmaylov"><organization/></author>
            <date year="2026" month="October" day="31"/>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-izmaylov-agent-permission-receipts-02"/>
        </reference>
        <reference anchor="WRIGHT" target="https://datatracker.ietf.org/doc/html/draft-wright-verdict-record-02">
          <front>
            <title>Verdict Records: Results on Claims that Cite Receipts as Evidence</title>
            <author initials="D." surname="Wright"><organization/></author>
            <date year="2026" month="November" day="2"/>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-wright-verdict-record-02"/>
        </reference>
        <reference anchor="BIRKHOLZ" target="https://datatracker.ietf.org/doc/html/draft-birkholz-verifiable-agent-conversations-01">
          <front>
            <title>Verifiable Agent Conversation Records</title>
            <author initials="H." surname="Birkholz"><organization/></author>
            <author initials="T." surname="Heldt"><organization/></author>
            <author initials="O." surname="Steele"><organization/></author>
            <date year="2026" month="August" day="31"/>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-birkholz-verifiable-agent-conversations-01"/>
        </reference>
        <reference anchor="SER" target="https://datatracker.ietf.org/doc/html/draft-gruszka-signed-evaluation-receipts-04">
          <front>
            <title>Signed Evaluation Receipts</title>
            <author initials="K." surname="Gruszka"><organization/></author>
            <date year="2026" month="October" day="26"/>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-gruszka-signed-evaluation-receipts-04"/>
        </reference>
        <reference anchor="SER-MAPPINGS" target="https://datatracker.ietf.org/doc/html/draft-gruszka-evaluation-receipt-mappings-04">
          <front>
            <title>Citing Signed Evaluation Receipts from Existing Envelopes</title>
            <author initials="K." surname="Gruszka"><organization/></author>
            <date year="2026" month="October" day="26"/>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-gruszka-evaluation-receipt-mappings-04"/>
        </reference>
        <reference anchor="RFC9943" target="https://www.rfc-editor.org/info/rfc9943">
          <front>
            <title>An Architecture for Trustworthy and Transparent Digital Supply Chains</title>
            <author initials="H." surname="Birkholz"><organization/></author>
            <author initials="A." surname="Delignat-Lavaud"><organization/></author>
            <author initials="C." surname="Fournet"><organization/></author>
            <author initials="Y." surname="Deshpande"><organization/></author>
            <author initials="S." surname="Lasker"><organization/></author>
            <date year="2026" month="June"/>
          </front>
          <seriesInfo name="RFC" value="9943"/>
          <seriesInfo name="DOI" value="10.17487/RFC9943"/>
        </reference>
        <reference anchor="RFC3161" target="https://www.rfc-editor.org/info/rfc3161">
          <front>
            <title>Internet X.509 Public Key Infrastructure Time-Stamp Protocol (TSP)</title>
            <author initials="C." surname="Adams"><organization/></author>
            <author initials="P." surname="Cain"><organization/></author>
            <author initials="D." surname="Pinkas"><organization/></author>
            <author initials="R." surname="Zuccherato"><organization/></author>
            <date year="2001" month="August"/>
          </front>
          <seriesInfo name="RFC" value="3161"/>
          <seriesInfo name="DOI" value="10.17487/RFC3161"/>
        </reference>
        <reference anchor="RFC8949" target="https://www.rfc-editor.org/info/rfc8949">
          <front>
            <title>Concise Binary Object Representation (CBOR)</title>
            <author initials="C." surname="Bormann"><organization/></author>
            <author initials="P." surname="Hoffman"><organization/></author>
            <date year="2020" month="December"/>
          </front>
          <seriesInfo name="STD" value="94"/>
          <seriesInfo name="RFC" value="8949"/>
          <seriesInfo name="DOI" value="10.17487/RFC8949"/>
        </reference>
        <reference anchor="RFC9052" target="https://www.rfc-editor.org/info/rfc9052">
          <front>
            <title>CBOR Object Signing and Encryption (COSE): Structures and Process</title>
            <author initials="J." surname="Schaad"><organization/></author>
            <date year="2022" month="August"/>
          </front>
          <seriesInfo name="STD" value="96"/>
          <seriesInfo name="RFC" value="9052"/>
          <seriesInfo name="DOI" value="10.17487/RFC9052"/>
        </reference>
        <reference anchor="RFC9053" target="https://www.rfc-editor.org/info/rfc9053">
          <front>
            <title>CBOR Object Signing and Encryption (COSE): Initial Algorithms</title>
            <author initials="J." surname="Schaad"><organization/></author>
            <date year="2022" month="August"/>
          </front>
          <seriesInfo name="RFC" value="9053"/>
          <seriesInfo name="DOI" value="10.17487/RFC9053"/>
        </reference>
        <reference anchor="RFC9597" target="https://www.rfc-editor.org/info/rfc9597">
          <front>
            <title>CBOR Web Token (CWT) Claims in COSE Headers</title>
            <author initials="T." surname="Looker"><organization/></author>
            <author initials="M.B." surname="Jones"><organization/></author>
            <date year="2024" month="June"/>
          </front>
          <seriesInfo name="RFC" value="9597"/>
          <seriesInfo name="DOI" value="10.17487/RFC9597"/>
        </reference>
        <reference anchor="RFC9679" target="https://www.rfc-editor.org/info/rfc9679">
          <front>
            <title>CBOR Object Signing and Encryption (COSE) Key Thumbprint</title>
            <author initials="K." surname="Isobe"><organization/></author>
            <author initials="H." surname="Tschofenig"><organization/></author>
            <author initials="O." surname="Steele"><organization/></author>
            <date year="2024" month="December"/>
          </front>
          <seriesInfo name="RFC" value="9679"/>
          <seriesInfo name="DOI" value="10.17487/RFC9679"/>
        </reference>
        <reference anchor="RFC9995" target="https://www.rfc-editor.org/info/rfc9995">
          <front>
            <title>CBOR Object Signing and Encryption (COSE) Hash Envelope</title>
            <author initials="O." surname="Steele"><organization/></author>
            <author initials="S." surname="Lasker"><organization/></author>
            <author initials="H." surname="Birkholz"><organization/></author>
            <date year="2026" month="July"/>
          </front>
          <seriesInfo name="RFC" value="9995"/>
          <seriesInfo name="DOI" value="10.17487/RFC9995"/>
        </reference>
        <reference anchor="RFC9162" target="https://www.rfc-editor.org/info/rfc9162">
          <front>
            <title>Certificate Transparency Version 2.0</title>
            <author initials="B." surname="Laurie"><organization/></author>
            <author initials="E." surname="Messeri"><organization/></author>
            <author initials="R." surname="Stradling"><organization/></author>
            <date year="2021" month="December"/>
          </front>
          <seriesInfo name="RFC" value="9162"/>
          <seriesInfo name="DOI" value="10.17487/RFC9162"/>
        </reference>
        <reference anchor="RFC9942" target="https://www.rfc-editor.org/info/rfc9942">
          <front>
            <title>CBOR Object Signing and Encryption (COSE) Receipts</title>
            <author initials="O." surname="Steele"><organization/></author>
            <author initials="H." surname="Birkholz"><organization/></author>
            <author initials="A." surname="Delignat-Lavaud"><organization/></author>
            <author initials="C." surname="Fournet"><organization/></author>
            <date year="2026" month="June"/>
          </front>
          <seriesInfo name="RFC" value="9942"/>
          <seriesInfo name="DOI" value="10.17487/RFC9942"/>
        </reference>
        <reference anchor="RFC7942" target="https://www.rfc-editor.org/info/rfc7942">
          <front>
            <title>Improving Awareness of Running Code: The Implementation Status Section</title>
            <author initials="Y." surname="Sheffer"><organization/></author>
            <author initials="A." surname="Farrel"><organization/></author>
            <date year="2016" month="July"/>
          </front>
          <seriesInfo name="BCP" value="205"/>
          <seriesInfo name="RFC" value="7942"/>
          <seriesInfo name="DOI" value="10.17487/RFC7942"/>
        </reference>
        <reference anchor="PB-DECISION" target="https://github.com/b7n0de/proofbundle/blob/v6.4.0/docs/predicates/decision-receipt.md">
          <front>
            <title>Decision Receipt predicate decision-receipt/v0.1</title>
            <author><organization>proofbundle project</organization></author>
            <date year="2026" month="October"/>
          </front>
          <refcontent>proofbundle, tag v6.4.0, docs/predicates/decision-receipt.md</refcontent>
        </reference>
        <reference anchor="PB-OUTCOME" target="https://github.com/b7n0de/proofbundle/blob/v6.4.0/docs/predicates/action-outcome.md">
          <front>
            <title>Action Outcome predicate action-outcome/v0.1</title>
            <author><organization>proofbundle project</organization></author>
            <date year="2026" month="October"/>
          </front>
          <refcontent>proofbundle, tag v6.4.0, docs/predicates/action-outcome.md</refcontent>
        </reference>
        <reference anchor="PB-PYPI" target="https://pypi.org/project/proofbundle/6.4.0/">
          <front>
            <title>proofbundle 6.4.0</title>
            <author><organization>Python Package Index</organization></author>
            <date year="2026" month="October" day="28"/>
          </front>
        </reference>
        <reference anchor="SCITT-COSE" target="https://pypi.org/project/scitt-cose/0.5.0/">
          <front>
            <title>scitt-cose 0.5.0</title>
            <author><organization>Action State Group</organization></author>
            <date year="2026" month="October" day="21"/>
          </front>
        </reference>
        <reference anchor="PB-REPO" target="https://github.com/b7n0de/proofbundle">
          <front>
            <title>proofbundle source repository</title>
            <author><organization>proofbundle project</organization></author>
            <date year="2026" month="November" day="2"/>
          </front>
        </reference>
        <reference anchor="JCS-JS" target="https://www.npmjs.com/package/canonicalize/v/2.1.0">
          <front>
            <title>canonicalize 2.1.0, a JavaScript implementation of RFC 8785</title>
            <author initials="S." surname="Erdtman"><organization/></author>
            <date year="2025" month="March" day="18"/>
          </front>
        </reference>
      </references>
    </references>

<section anchor="vectors">
      <name>Test Vectors</name>
      <t>The seven DSSE vectors described in <xref target="vectors-table"/> were generated with proofbundle 6.4.0 from PyPI. All vectors and keys in this appendix are for testing only. Each key seed is SHA-256 over a public ASCII label, so that every byte can be rebuilt; these keys <bcp14>MUST NOT</bcp14> be used for any real receipt. Ed25519 is deterministic, so the signatures below follow from the seeds and the payloads.</t>
      <section anchor="vectors-keys">
        <name>Test Keys and Inputs</name>
        <t>Each key is given by its label, Ed25519 seed (hex), public key (base64) and keyid. The key labelled gate-1 signs the decision receipts; the key labelled observer-1 signs the outcome receipts. For these tests, the trust policy accepts decisionMaker.id gate-1 under the gate-1 key and permits the observer-1 key to attest executor.id forge:agent-42-bot. The key label observer-1 does not assert that the observer is the executing account.</t>
        <artwork><![CDATA[
gate-1
draft-gruszka-audit-decision-receipts test key gate-1
100fa92fa6464c141f791a96327f555c1c0cfbf3095af986537e50c3c4335f8c
TWfs75IN1In3CNI8TnyIOUHgtwilOPGcRFQLJ670CJc=
SHA256:NjZMAelLq9XON3pxV5tR5hZjX99NkQyw4gGJSRc2gP8

observer-1
draft-gruszka-audit-decision-receipts test key observer-1
f03ad5b668ad225ea15fd9fd272fc8df84be59f467da86b0f2ad0a5ad26f4ddd
4hDsi5TCL+A+9SB7k2l4EkY7XePUheE+zE9mBazt2Fs=
SHA256:q/d0VZCREBObUFi8PWKWXEF4lVNeYPuGn0GuOqd1ij0
]]></artwork>
        <t>Each input is given by a name, its bytes, its size and its SHA-256. "\n" stands
for one line feed byte. The bytes of ap, a3 and e3 are the serialization under
<xref target="RFC8785"/> of the JSON value shown, on one line and without white space.
In ap, SHA-256(a1) stands for the JSON string of the 64
lowercase hexadecimal digits of the SHA-256 of a1. pol is the policy named by every
policyDigest. B is the payload of vector P1 of
<xref target="SER"/>, Appendix A.2.1, cited by V3-decision.</t>
        <artwork><![CDATA[
a1 "git push origin refs/heads/topic:refs/heads/topic\n"
50 bytes, SHA-256
dec54f771352454097310ae4bd6608c0070ebebb3955c6be013c1b3a8e310bd0
]]></artwork>
        <artwork><![CDATA[
a1x "git push --force origin refs/heads/topic:refs/heads/main\n"
57 bytes, SHA-256
b683418806875ff79c6fa190c50edab0b96577ad8062de5ba7b41dc1d9c363fb
]]></artwork>
        <artwork><![CDATA[
a2 "gh pr merge 7 --repo acme/widgets --merge\n"
42 bytes, SHA-256
5a7549948a1441addb710f5ada59e06dbce25cc5a59accf14f140379f47adb5b
]]></artwork>
        <artwork><![CDATA[
pol "example gate rules, revision 1\n"
31 bytes, SHA-256
43789b41915ae0febcd13263d293101af5ab041eb7c234e1cbe625d6312815f6
]]></artwork>
        <artwork><![CDATA[
ap, 231 bytes, SHA-256
88e5b6d69b3e4bc250a42aeffea0414d406e5f04ba4f991ee432a78231da1170
{
 "actionDigest": {
  "sha256": SHA-256(a1)
 },
 "approvalId": "appr-001",
 "approvedAt": "2026-10-15T09:00:00Z",
 "approver": "user-123",
 "session": "sess-1",
 "validUntil": "2026-10-15T09:15:00Z"
}
]]></artwork>
        <artwork><![CDATA[
a3, 81 bytes, SHA-256
9165c850b7e03cd59578efa1769be74c5386cff5ce96df6b59e25d38ad6f88b4
{
 "body": "All required checks passed for 4f1c2a9.",
 "pull": 7,
 "repo": "acme/widgets"
}
]]></artwork>
        <artwork><![CDATA[
e3, 93 bytes, SHA-256
d3d824cf55168298c0f651244853ec9d9620ea09087abe899243ceb8f9df3a6d
{
 "author": "agent-42-bot",
 "body": "All required checks passed for 4f1c2a9.",
 "id": 9001,
 "pull": 7
}
]]></artwork>
        <artwork><![CDATA[
B, 458 bytes, SHA-256
8cd849a6dcce08aee334511d7b2f31c54e478885dda1795d3c8f972dd0d4811c
]]></artwork>
      </section>
      <section anchor="vectors-statements">
        <name>Statements</name>
        <t>The payload bytes of each vector are the serialization under
<xref target="RFC8785"/> of a Statement {"_type": "https://in-toto.io/Statement/v1",
"predicateType": P, "predicate": D, "subject": [{"name": N, "digest": {"sha256": H}}]},
where H is SHA-256 over the serialization of D. For a decision receipt P is the
decision receipt type and N is "decision:" followed by decisionId; for an outcome
receipt P is the outcome receipt type and N is "outcome:" followed by outcomeId. </t>
        <t>Each predicate is given as a list of assignments that starts from the
predicate named in its first line, {} being the empty object. An assignment sets the
member at the path to the JSON value shown. A path is a sequence of member names joined by dots, where a decimal index i in square brackets after a name selects element i of an array; missing objects on the path are created, and an assignment to element i of an array with i elements appends it. Members not named keep their value. SHA-256(x) stands for the JSON string of the 64
lowercase hexadecimal digits of the SHA-256 of input x, and R(V) for that of the
payload bytes of vector V.</t>
        <artwork><![CDATA[
V1-good, from {}
agent.id = "agent-42"
decidedAt = "2026-10-15T09:00:05Z"
decision.reasonCodes = ["user_approval"]
decision.verdict = "ALLOW"
decisionChangeConditions = []
decisionChangeConditions[0].conditionType = "ruleChange"
decisionChangeConditions[0].description =
 "a changed gate, mode or rule of the gate"
decisionId = "dec-0001"
decisionMaker.id = "gate-1"
decisionType = "preActionAuthorization"
evidenceRefs = []
inputSnapshot = []
inputSnapshot[0].digest.sha256 = SHA-256(a1)
inputSnapshot[0].mediaType = "text/plain"
inputSnapshot[0].name = "approved bytes"
inputSnapshot[1].digest.sha256 = SHA-256(ap)
inputSnapshot[1].mediaType = "application/json"
inputSnapshot[1].name = "approval record"
notChecked = []
notChecked[0].field = "content"
notChecked[0].impact = "an approved text can be wrong"
notChecked[0].reason =
 "the gate does not judge whether the text is true"
policyBoundary.bundleRevision = "1"
policyBoundary.decisionPath = "outbound-gate/allow-write"
policyBoundary.policyDigest.sha256 = SHA-256(pol)
policyBoundary.policyEngine = "proofbundle-pilot/github-write"
policyBoundary.policyId = "outbound-gate-rules"
principal.id = "user-123"
privacy.rawInputsIncluded = false
proposedAction.actionType = "git.push"
proposedAction.method = "write"
proposedAction.parametersDigest.sha256 = SHA-256(a1)
proposedAction.target.name =
 "https://git.example/acme/widgets refs/heads/topic"
proposedAction.target.uri = "https://git.example/acme/widgets"
schemaVersion = "0.1.0"
traceContext.parentId = "int-002"
traceContext.traceId = "trace-abc"
validity.audience = ["observer-1"]
validity.expiresAt = "2026-10-15T09:05:05Z"
validity.nonce = "dec-0001"
]]></artwork>
        <artwork><![CDATA[
V2-good, from V1-good
actionOutcome.outcomeRef = null
actionOutcome.performedAt = null
actionOutcome.status = "blocked"
decidedAt = "2026-10-15T09:05:00Z"
decision.reasonCodes = ["required_check_failed"]
decision.verdict = "DENY"
decisionId = "dec-0002"
inputSnapshot = []
inputSnapshot[0].digest.sha256 = SHA-256(a2)
inputSnapshot[0].mediaType = "text/plain"
inputSnapshot[0].name = "proposed bytes"
policyBoundary.decisionPath = "outbound-gate/deny-write"
proposedAction.actionType = "github.merge"
proposedAction.parametersDigest.sha256 = SHA-256(a2)
proposedAction.target.name =
 "https://git.example/acme/widgets/pull/7"
proposedAction.target.uri = "https://git.example/acme/widgets/pull/7"
traceContext.parentId = "int-003"
validity.expiresAt = "2026-10-15T09:10:00Z"
validity.nonce = "dec-0002"
]]></artwork>
        <artwork><![CDATA[
V3-decision, from V1-good
decidedAt = "2026-10-15T09:10:00Z"
decision.reasonCodes = ["evidence_verified"]
decisionId = "dec-0003"
evidenceRefs = []
evidenceRefs[0].digest.sha256 = SHA-256(B)
evidenceRefs[0].relation = "evaluationResult"
inputSnapshot = []
inputSnapshot[0].digest.sha256 = SHA-256(a3)
inputSnapshot[0].mediaType = "application/json"
inputSnapshot[0].name = "approved bytes"
proposedAction.actionType = "github.conversationComment"
proposedAction.parametersDigest.sha256 = SHA-256(a3)
proposedAction.target.name =
 "https://git.example/acme/widgets/pull/7"
proposedAction.target.uri = "https://git.example/acme/widgets/pull/7"
traceContext.parentId = "int-004"
validity.expiresAt = "2026-10-15T09:15:00Z"
validity.nonce = "dec-0003"
]]></artwork>
        <artwork><![CDATA[
V3-good, from {}
decisionRef.sha256 = R(V3-decision)
effectDigest.sha256 = SHA-256(e3)
executor.id = "forge:agent-42-bot"
outcomeId = "out-0001"
performedAt = "2026-10-15T09:10:02Z"
requestedActionDigest.sha256 = SHA-256(a3)
schemaVersion = "0.1.0"
status = "executed"
]]></artwork>
        <artwork><![CDATA[
V3-bad, from V3-good
decisionRef.sha256 = R(V1-good)
outcomeId = "out-0002"
]]></artwork>
        <t>V1-bad has the payload bytes of V1-good with every occurrence of the
hexadecimal SHA-256 of a1 replaced by that of a1x, and keeps the signature of V1-good.
V2-bad has as payload bytes the output of Python's json.dumps(s, sort_keys=True) for
the Statement s of V2-good, with a space after each comma and colon, and is validly
signed over them by gate-1.</t>
      </section>
      <section anchor="vectors-table">
        <name>Results</name>
        <t>Every envelope is {"payload": base64 of the payload bytes, "payloadType":
"application/vnd.in-toto+json", "signatures": [{"keyid": keyid of the signer,
"sig": signature}]}. Each block below gives the vector, the evaluation time T, the
expected result with the exit code of the proofbundle 6.4.0 command line interface,
the payload size and signer, the SHA-256 of the payload bytes (the content root where
the payload is canonical) and the signature in base64 on two lines. The expected
audience is observer-1 and the expected nonce is the decisionId. decision verify ran
with --strict, --aud, --nonce and --verification-time T; outcome verify with --strict,
--expected-decision-ref R(V3-decision) and --decision-maker-id gate-1.</t>
        <artwork><![CDATA[
V1-good, T 2026-10-15T09:01:00Z, pass, exit 0
1829 bytes, signed by gate-1
b9dfd26537542632013d0df166141a788551b4987dfa33b060d5b5ebba78dfb1
GkvzPjklV5ZbtomNRXbS4+O4MIOSw8xGmA0diAEYKEm0
s4Q9qLkL1j7+e5RZnT9l56tfB2utDoNycACsSvSoDw==
]]></artwork>
        <artwork><![CDATA[
V1-bad, T 2026-10-15T09:01:00Z, fail at step 3, exit 1
1829 bytes, signed by gate-1
69eb87fb33a29153182b0e0c89a444023cc00c82fe7c8db1c7e0893363b2c926
GkvzPjklV5ZbtomNRXbS4+O4MIOSw8xGmA0diAEYKEm0
s4Q9qLkL1j7+e5RZnT9l56tfB2utDoNycACsSvSoDw==
]]></artwork>
        <artwork><![CDATA[
V2-good, T 2026-10-15T09:06:00Z, pass, exit 0
1765 bytes, signed by gate-1
ed149a1c7383842eebf8304001da9de97d130b0b15080d1315ab8fbf1274ed44
66CUa1kz6aOm6gbdctRg4l97fW8x185nxpsB5rkCFj+a
HZVjRjc5hDnQu6v4J/bHzaufyHhPCPdM6XUAWiylAQ==
]]></artwork>
        <artwork><![CDATA[
V2-bad, T 2026-10-15T09:06:00Z, fail at step 4, exit 2
1866 bytes, signed by gate-1
646d4b2229a55c54848361030bf6d57816597a96bd7d1fb00d7da0f03b009bd2
2yjE3MxaVXdureYhh50+d3XdDAsJDhW3nacud4WCbzBM
R/NLHyxeqIvbsDKQTabl+X+5O4CSXu17rA7lFYN0Cw==
]]></artwork>
        <artwork><![CDATA[
V3-decision, T 2026-10-15T09:11:00Z, pass, exit 0
1827 bytes, signed by gate-1
0014b1c419798125c3984e85a4b322ee619a3227978840cac5f9d282b189521f
DDLIUtX6uk5A3AqcvYP9f9zYeHJAWNTrdBZwpXmEQq4y
u0bivvsiNEjx4u2Kw2U6Mr11lcWoRZnSo1w5MX2PCA==
]]></artwork>
        <artwork><![CDATA[
V3-good, pass, exit 0
694 bytes, signed by observer-1
f0ff90cf25e2db1e989fa79869d4b3b46899112e8c2269d9a18a64b751aa7274
MCUgSY+fGUO2cm5DnxBVKEC/BBSyeS359aj2rYowwkHT
j+CskAgraX5TirUBic2i2KyUUaxBYMMdVafhu3tcAQ==
]]></artwork>
        <artwork><![CDATA[
V3-bad, fail at binding, exit 2
694 bytes, signed by observer-1
48be708cf3f959556323474f4a5c9193b417d2bfea5c88bb852daf00b64827b4
uEgT4TFv7jEgmH7pwJcPBEEZM+n2wGjic6U6yYWOU3Dh
Ta0tMuimQ8q4Ha1lgw4zWNR9YBag4GmVt9SdsfzwCQ==
]]></artwork>
        <t>The payload bytes of V1-good, V2-good, V3-decision, V3-good and V3-bad and the
inputs ap, a3, e3 and B are each equal to three serializations of their parsed value:
Python's json.dumps with sort_keys=True, separators=(",", ":") and either setting of
ensure_ascii; the rfc8785 package 0.1.4 for Python; and the independent JavaScript
implementation <xref target="JCS-JS"/>. The values contain no floating-point numbers
and no characters outside ASCII, which keeps these serializations equal. The payload
of V2-bad differs from all of them, as intended.</t>
        <t>Each result is that of one procedure. V1-good is judged by <xref target="verify-decision"/> with Case 1 of <xref target="verify-cases"/>, using a1 and ap; V1-bad fails at step 3 of <xref target="verify-decision"/>, before any check of Case 1. V2-good is judged by <xref target="verify-decision"/> with Case 2, using a2; V2-bad fails at step 4 of <xref target="verify-decision"/>. V3-good is judged as Case 3, by <xref target="verify-decision"/> for V3-decision and <xref target="verify-outcome"/> for V3-good, with e3 as effect bytes and forge:agent-42-bot as expected executor.id; V3-bad fails at step 4 of <xref target="verify-outcome"/>. V3-decision is judged by the same Case 3 procedure as V3-good and passes. The exit code of proofbundle decision verify for V3-decision reflects <xref target="verify-decision"/> alone.</t>
      </section>
      <section anchor="vectors-registration">
        <name>Signed Statements for Registration</name>
        <t>This appendix gives one Signed Statement for each way of registration in <xref target="registration"/>, both for V2-good. Statement A carries the envelope bytes as its payload. Statement B is made over the content root and uses, as one example of a profile, the COSE Hash Envelope of <xref target="RFC9995"/> with a detached payload; other profiles are possible. These Signed Statements were built from the specifications cited here, not with proofbundle. The SCITT Receipts for A and B at the end of this appendix were generated for illustration with the library scitt-cose 0.5.0 <xref target="SCITT-COSE"/>, and no Transparency Service issued them.</t>
        <t>The envelope bytes are the serialization under <xref target="RFC8785"/> of the V2-good envelope of <xref target="vectors-table"/>, 2590 bytes with SHA-256 0e60fbbf36ddc6691cdf0fb2b1faea70d23d02d0da7653f449ec60f2f820e71e. The test key issuer-1 of the Issuer is built like the keys of <xref target="vectors-keys"/> and given by its label, Ed25519 seed (hex) and public key (base64). Its kid is the COSE Key Thumbprint of <xref target="RFC9679"/> with SHA-256 over the required parameters kty 1 (OKP), crv 6 (Ed25519) and x.</t>
        <artwork><![CDATA[
issuer-1
draft-gruszka-audit-decision-receipts test key issuer-1
cce9d25f7abceebfb8d50ce46c19b948d354906ecdbe6b72d53973bed5614e30
fS1sCQ+XTgtuMzxOnSRz0IMbzm+iFb6bVcB6lEMy8e8=
kid
f823e78e15df312ae66be2b2d4a8c035873f68d22abb1b2f52fcc6708cce62b0
]]></artwork>
        <t>Both Signed Statements are COSE_Sign1 messages of <xref target="RFC9052"/> with tag 18, an empty unprotected header and an EdDSA (-8) signature of <xref target="RFC9053"/> by issuer-1 over the Sig_structure of <xref target="RFC9052" section="4.4"/>. Their CBOR uses the core deterministic encoding of <xref target="RFC8949" section="4.2.1"/>. The protected headers carry the CWT Claims (label 15) of <xref target="RFC9597"/> with iss "https://issuer-1.example" and sub "decision:dec-0002", the subject name of V2-good. They are shown below in diagnostic notation, with kid standing for the value above.</t>
        <artwork><![CDATA[
A  {1: -8, 3: "application/json", 4: kid,
    15: {1: "https://issuer-1.example", 2: "decision:dec-0002"}}
B  {1: -8, 4: kid,
    15: {1: "https://issuer-1.example", 2: "decision:dec-0002"},
    258: -16, 259: "application/vnd.in-toto+json"}
]]></artwork>
        <t>In B, label 258 (payload_hash_alg) is -16 (SHA-256) and label 259 (payload_preimage_content_type) is the payloadType of the envelope, whose decoded payload is the preimage. B carries no content type (label 3), as <xref target="RFC9995" section="4"/> requires for a Hash Envelope.</t>
        <t>A is encoded as the bytes given below, followed by the envelope bytes, the two bytes 0x58 0x40 and the signature. B has a detached payload, the content root R(V2-good) of <xref target="vectors-table"/>, and is given in full.</t>
        <artwork><![CDATA[
A, 2768 bytes, SHA-256
ec0255d32b2e96aee414728dfa10995f4742849e9d71bb4d8710223765062517
bytes before the payload, 112 bytes
d2845868a4012703706170706c69636174696f6e2f6a736f6e045820f823e78e
15df312ae66be2b2d4a8c035873f68d22abb1b2f52fcc6708cce62b00fa20178
1868747470733a2f2f6973737565722d312e6578616d706c6502716465636973
696f6e3a6465632d30303032a0590a1e
signature
16181711ba8148149489c7a52f4c97ac44dfd91b83bcbab4ba2f048ef3da6612
52a508a3aecbe32f3e531e8cf8023fa381a10e51e1a5de468196a21ab208e40c

B, 195 bytes, SHA-256
3a814dfc59ddbe6da6f0ab7950db07801b3c60e917808febad5978c0ec90e83b
d284587ba50127045820f823e78e15df312ae66be2b2d4a8c035873f68d22abb
1b2f52fcc6708cce62b00fa201781868747470733a2f2f6973737565722d312e
6578616d706c6502716465636973696f6e3a6465632d303030321901022f1901
03781c6170706c69636174696f6e2f766e642e696e2d746f746f2b6a736f6ea0
f65840caec06ad5338ad0b9479190cd34c92eca213074ccfa02fcda1c5af70d8
3342e3d93819b07b983e8771ebf8c201fe95cc30bdded5a8c6da658d494c3fb2
4cb603
]]></artwork>
        <t>A verifier that holds the issuer-1 key decodes each Signed Statement, checks that alg is EdDSA, that kid is the thumbprint of that key and that iss is as expected, and verifies the signature, for B over the detached payload. Both pass. Two counterexamples fail at the signature. In the first, the byte at offset 12 of the envelope bytes in A, the first character "e" of the base64 payload, is replaced by "f". In the second, B is checked with a detached payload whose first byte is 0xec instead of 0xed. The binding of <xref target="registration"/> then holds for V2-good. The payload of A equals its envelope bytes, and the payload of B equals its content root and differs from R(V2-bad). On those envelope bytes, proofbundle 6.4.0 decision verify with the arguments of <xref target="vectors-table"/> exits 0.</t>
        <t>For these Receipts, a local registration in the manner of <xref target="RFC9943" section="6.3"/> first verified the Issuer signature of each Signed Statement, for B over the detached payload, and checked that its protected header carries kid and CWT Claims with iss and sub (<xref target="RFC9943" section="6"/>). It accepted A and then B as the two entries of a Merkle Tree of <xref target="RFC9162"/>, each entry being the bytes of the Signed Statement. Neither <xref target="RFC9942"/> nor <xref target="RFC9943"/> defines what a Transparency Service takes as an entry; the bytes of the Signed Statement are the choice of this example, and other services enter, for example, a hash of them. It rejected A with the changed byte, B with the changed detached payload, and a variant of A without sub. The Receipts are COSE_Sign1 messages of <xref target="RFC9942"/> with vds 1 (RFC9162_SHA256), a detached payload, the root of that tree, and an EdDSA signature by the test key receipt-issuer-1, built like the keys of <xref target="vectors-keys"/>. Their CWT Claims carry the iss given below and the sub of the Signed Statement, and their kid is the COSE Key Thumbprint of the receipt-issuer-1 key. Both Signed Statements have the same sub and both Receipts sign the same root, so the two Receipts share their protected header and signature and differ only in their inclusion proofs. Their protected header keeps the label order in which scitt-cose writes it (395, 15, 4, 1), not the deterministic order of <xref target="RFC8949" section="4.2.1"/>; the signature covers the bytes as given.</t>
        <artwork><![CDATA[
receipt-issuer-1
draft-gruszka-audit-decision-receipts test key receipt-issuer-1
b71a939bfbc162586fffa8b45a0d89d312e7102297906c3174fa6efab2b497fd
WpbTJ2CMpw5ELCFLr7kLdAjpZInhGIUzQQ5lzCXs0po=
kid
4277c54764b34816bb1836860d570849105f452369e4e5c741f5891d9fb25040
iss
https://receipt-issuer-1.example

root, tree size 2
f541c1ee787f59133666bd6907cb0174abb2460d8fdcce8deec05beb1a7ddd6d

Receipt for A, leaf index 0, 216 bytes, SHA-256
1525b5ab39b77b0283825673bb7ee6ec699b9940ab4730d2118d66fd1a7cfce8
d2845862a419018b010fa201782068747470733a2f2f726563656970742d6973
737565722d312e6578616d706c6502716465636973696f6e3a6465632d303030
320458204277c54764b34816bb1836860d570849105f452369e4e5c741f5891d
9fb250400127a119018ca120815826830200815820047d8ac95c86ec315a5419
b62eeeb68a6b7d94b0654ea372d72ec5ee418a9710f658400682628ba41d0364
9206c1a7c7294f1f878b44208bb37b08027319a196906f67d4b0ad8d70bce9cd
36d141c289bc3ba0a7933bceb71af802e7b2db2a28d6db0b

Receipt for B, leaf index 1, 216 bytes, SHA-256
50a0ed768b8e9482f0d4f3f821109fbe7704b4235ca56e7c5a8c5a4f5ae36a21
d2845862a419018b010fa201782068747470733a2f2f726563656970742d6973
737565722d312e6578616d706c6502716465636973696f6e3a6465632d303030
320458204277c54764b34816bb1836860d570849105f452369e4e5c741f5891d
9fb250400127a119018ca12081582683020181582031277502318f2fb4197043
c51cb6895267e7c48d48ab55aa0c2370745b1cdcf9f658400682628ba41d0364
9206c1a7c7294f1f878b44208bb37b08027319a196906f67d4b0ad8d70bce9cd
36d141c289bc3ba0a7933bceb71af802e7b2db2a28d6db0b
]]></artwork>
        <t>A verifier computes the leaf hash, SHA-256 over the byte 0x00 followed by the entry (<xref target="RFC9162" section="2.1.1"/>), applies the inclusion path of the Receipt to obtain the root (<xref target="RFC9162" section="2.1.3.2"/>), and verifies the signature over that root with the receipt-issuer-1 key (<xref target="RFC9942" section="5.2.1"/>). Both Receipts pass. Four counterexamples fail at the signature, namely A with the Receipt for B, B with the Receipt for A, the Receipt for A with one byte of its inclusion path changed, and the Receipt for A checked with the issuer-1 key instead of the receipt-issuer-1 key.</t>
      </section>
      <section anchor="vectors-failure">
        <name>Failure Vectors</name>
        <t>Each vector below defines a failing test case based on a passing vector of <xref target="vectors-table"/> and names its expected first failing check for the stated inputs and procedure. For F10 and F13, receipt verification passes and the relying party refuses the approval under <xref target="approvals-once"/>; the vector names the item of <xref target="approvals-once"/> on which the refusal rests. The payloads are derived as in <xref target="vectors-statements"/>, where a line "remove P" removes the member at path P, and signed with the test keys of <xref target="vectors-keys"/>. F11 and F12 change a member of the Statement outside predicate, as stated below. F4, F5 and F13 reuse the envelope of V1-good or V2-good and differ from it only in an input of the verifier. F15 is the receipt of vector P1 of <xref target="SER"/>, a Signed Evaluation Receipt whose signature verifies under the issuer test key of <xref target="SER"/>; <xref target="evaluation-receipts"/> forbids a verifier to treat it as permission. F15 tests the first half of that rule; the second half, not to treat the presence of a Signed Evaluation Receipt in evidenceRefs as permission, is a rule for the relying party that has no check step and no vector of its own. The other vectors were generated from the definitions in this document, not with proofbundle.</t>
        <t>The approval record ap2 is ap with a later validUntil, and c1 is the consumption state of a relying party that has honoured ap, as an array of approval identities. c2 is the consumption state of a relying party that has rotated its record, as an object whose members are its generations, each an array of approval identities; its current generation is empty and its rotated generation holds the identity of ap. All three are the <xref target="RFC8785"/> serialization of the JSON value shown.</t>
        <artwork><![CDATA[
ap2, 231 bytes, SHA-256
37ec7f3fa06f086626268a6c818ba5b5af7fd16ba292735ce964a83c42c0357c
{
 "actionDigest": {
  "sha256": SHA-256(a1)
 },
 "approvalId": "appr-001",
 "approvedAt": "2026-10-15T09:00:00Z",
 "approver": "user-123",
 "session": "sess-1",
 "validUntil": "2026-10-15T09:30:00Z"
}

c1, 139 bytes, SHA-256
f13fce72c54f1872232c0339fa98b33ffe5142f72481cd31e378bc6a680b6f6a
[
 {
  "actionDigest": {
   "sha256": SHA-256(a1)
  },
  "approvalId": "appr-001",
  "session": "sess-1"
 }
]

c2, 164 bytes, SHA-256
3e9cea5ebe4860d1f5743526dcdf1f5200c11e8abd7ce67326abfa16f30c6c7f
{
 "current": [],
 "rotated": [
  {
   "actionDigest": {
    "sha256": SHA-256(a1)
   },
   "approvalId": "appr-001",
   "session": "sess-1"
  }
 ]
}
]]></artwork>
        <t>The decision vectors are checked like their base vectors in <xref target="vectors-table"/>, by <xref target="verify-decision"/> with Case 1 of <xref target="verify-cases"/> using a1 and ap, or with Case 2 using a2, with expected audience observer-1 and the decisionId as expected nonce. F5 is checked with a1 instead of a2. F10 is checked with ap2, and then by a relying party under <xref target="approvals-once"/> that holds c1. F11, F12 and F15 are checked like V2-good, and F13 and F14 like V1-good; F13 is then checked by a relying party under <xref target="approvals-once"/> that holds c2. F6 to F8 are checked by <xref target="verify-outcome"/> against V3-decision at T 2026-10-15T09:11:00Z, with e3 as effect bytes and forge:agent-42-bot as expected executor.id. F7 has status refused and no effectDigest; because e3 is supplied as effect bytes, F7 fails at the second sentence of step 6 of <xref target="verify-outcome"/>, which applies whatever the status.</t>
        <artwork><![CDATA[
F1, from V1-good
agent = null

F2, from V2-good
policyBoundary.validFrom = "2026-10-15T09:00:00+00:00"

F3, from V2-good
decisionMaker.id = "gate-2"

F6, from V3-good
executor.id = "forge:another-actor"

F7, from V3-good
status = "refused"
remove effectDigest

F8, from V3-good
performedAt = "2026-10-15T09:09:59Z"

F9, from V1-good
validity.expiresAt = "2026-10-15T10:00:00Z"

F10, from V1-good
decidedAt = "2026-10-15T09:20:00Z"
decisionId = "dec-0004"
inputSnapshot[1].digest.sha256 = SHA-256(ap2)
validity.expiresAt = "2026-10-15T09:25:00Z"
validity.nonce = "dec-0004"

F14, from V1-good
decision.reasonCodes = ["policy_match"]
]]></artwork>
<t>F11 and F12 have the predicate and the subject of V2-good. In F11 the Statement member _type is "https://in-toto.io/Statement/v0.1"; in F12 the member predicateType is "https://b7n0de.com/proofbundle/predicates/decision-receipt/v0.2".</t>
        <t>Each block gives the vector, the evaluation time T, the step at which it fails, the exit code of the proofbundle 6.4.0 command line interface for the command of <xref target="vectors-table"/>, and, for a new payload, its size and signer, the SHA-256 of the payload bytes and the signature in base64 on two lines. The block of F15 gives the size and SHA-256 of the receipt of P1 of <xref target="SER"/> instead.</t>
        <artwork><![CDATA[
F1, T 2026-10-15T09:01:00Z, fails at step 7 of 3.2, exit 2
1816 bytes, signed by gate-1
c20b86e4fa3753555a3e84dc87e2efe574f5094544612c6fc91ccf4f68707063
TeDLj3n16X9LrDWZGsPSM1YTwCx37OuCrXj/rYp4ayMX
X4EMk9ymbLAjBUZliV3KqqA4E0MEPXA6EYArYoThAQ==

F2, T 2026-10-15T09:06:00Z, fails at step 7 of 3.2, exit 2
1805 bytes, signed by gate-1
f9015e5fbcce4da86a56e5facfc812f629b62e6c29afa5f7172d037e6b880978
bPEAg3NIdR7cKMu7egfmj1xWPs4r27HumGAG6z95uKVk
+iQwNWltjZBCDc5PJiBDVv3hb+ufBliTWf08CluRAA==

F3, T 2026-10-15T09:06:00Z, fails at step 8 of 3.2, exit 0
1765 bytes, signed by gate-1
506905bbeeb5205b82aa707a6e3a9ec4f27f6f7213b8dc864d5083063c2f460a
qGm1ojfaW3hFVuUV5q+H+t1zYQRVA9NPIWnTup1w22Xd
dNAtygYVZ3qA7Wcame3kZsd14kmp+o+4Az0/FDNOAg==

F4, the envelope of V1-good unchanged,
T 2026-10-15T09:05:05Z, fails at step 9 of 3.2, exit 2

F5, the envelope of V2-good with a1 as action bytes,
T 2026-10-15T09:06:00Z, fails at step 10 of 3.2, exit 0

F6, T 2026-10-15T09:11:00Z, fails at step 5 of 3.4, exit 0
695 bytes, signed by observer-1
400e251d35ce2d833d22eb8699b2300a565801056bc2cccd461842957107bd69
gNh8vj8l4Ke040Yos21Vhd6uThtQYLsPVkRBJ4sXu+/C
n4LaMY2xoO4RzoI/AMU4LY8GAlwelUVCab+FLjGuBw==

F7, T 2026-10-15T09:11:00Z, fails at step 6 of 3.4, exit 0
600 bytes, signed by observer-1
b277133a0cd9e0ceea68313a8896280a89fd24c1743b1e056dcec5d10e10c6ad
EhhyqWKqst02TtQfDvlLWyVgQrQao7fPywh0elGXrH0k
uZXQxMACzjGGbX+69BoygBO3/T7SHHLtmPAB5X3bBQ==

F8, T 2026-10-15T09:11:00Z, fails at step 7 of 3.4, exit 0
694 bytes, signed by observer-1
bbe81b4cf255b9444de8ead2773fc9a859f4c2b9f8288822209fac0653fb9888
B+PLo64p+ESIWVfdIk7FR6RuANsst7kgsep1K6+g92eU
Luty4HseuWJL2laTX+tkc0aM1ztineO5Q3rA9XTtAg==

F9, T 2026-10-15T09:16:00Z, fails at Case 1 of 3.3, exit 0
1829 bytes, signed by gate-1
8271acb7293138eea0a48e52ee0dfd99c063b1139f353c8b26c9cdbe56975151
hIPtCWefKjWx+MlTv7nUxCuq9v+JjapYccXx9rawMxw8
JcxybehAGp8d8MozhTzAjZ5BZgmzvKBkEXECTfQPCA==

F10, T 2026-10-15T09:21:00Z, fails at Section 4 item 2, exit 0
1829 bytes, signed by gate-1
c299b48e0a0596f8c8eb252beef0138c7d1133f113cdc03150abb6cb41bcdcce
qCHm6JNGoxXAdFPXKud8ojxef8wh+m9BrGHbYD/1miqG
1YGcYAZ/XRFO8+el6D8RirkB313aOUqZo6YwBAUYAw==
]]></artwork>
        <artwork><![CDATA[
F11, T 2026-10-15T09:06:00Z, fails at step 6 of 3.2, exit 2
1767 bytes, signed by gate-1
9a162c5545a176d058b8daf099fafb66ec8b1a29c5ebdad865c64dbb245a3359
IjCZkGp11qcrYT4Lpn/n756TXHm5ZumTaAMJwkeM7ufG
7w100g1kBraCtZivUmlndJhG2fn1DPBH7ki6wUa4Dg==

F12, T 2026-10-15T09:06:00Z, fails at step 6 of 3.2, exit 2
1765 bytes, signed by gate-1
fc575c9130a083168047f727da512cf88c5308fc9193d090d7bf883750c5dc39
clHORGiu7nnI4nD5EkwD8dwcnq+RzeYmFwZ0POtkT+DS
d1rgTbX9wSMqz3KjlJwYCCHPaYKVFxBfnyuVSRQUDw==

F13, the envelope of V1-good unchanged, with c2,
T 2026-10-15T09:01:00Z, fails at Section 4 item 4, exit 0

F14, T 2026-10-15T09:01:00Z, fails at Case 1 of 3.3, exit 0
1828 bytes, signed by gate-1
45f47469a275828b32daca01f7437e47f3342b7d95ff5f75841cae6dfd96130b
JCf476iurjKm5ACyNoThqSbABxG5XaGiKG5cl/bS7z5D
ZIIvDxkU9bW+M26+YRxA4akMAFPMkH0JZY0iPNBeCg==

F15, the receipt of vector P1 of [SER],
871 bytes with SHA-256
02036d1f57509858330383755ec16c532bdc58b0f2d949464488d57abc9f95e7
T 2026-10-15T09:06:00Z, fails at step 1 of 3.2, exit 1
]]></artwork>
        <table>
          <name>Failure vectors and proofbundle 6.4.0</name>
          <thead><tr><th>Vector</th><th>Fails at</th><th>Exit</th><th>proofbundle 6.4.0</th></tr></thead>
          <tbody><tr><td>F1</td><td>step 7 of 3.2</td><td>2</td><td>rejects</td></tr><tr><td>F2</td><td>step 7 of 3.2</td><td>2</td><td>rejects</td></tr><tr><td>F3</td><td>step 8 of 3.2</td><td>0</td><td>accepts</td></tr><tr><td>F4</td><td>step 9 of 3.2</td><td>2</td><td>rejects</td></tr><tr><td>F5</td><td>step 10 of 3.2</td><td>0</td><td>accepts</td></tr><tr><td>F6</td><td>step 5 of 3.4</td><td>0</td><td>accepts</td></tr><tr><td>F7</td><td>step 6 of 3.4</td><td>0</td><td>accepts</td></tr><tr><td>F8</td><td>step 7 of 3.4</td><td>0</td><td>accepts</td></tr><tr><td>F9</td><td>Case 1 of 3.3</td><td>0</td><td>accepts</td></tr><tr><td>F10</td><td>Section 4, item 2</td><td>0</td><td>accepts</td></tr><tr><td>F11</td><td>step 6 of 3.2</td><td>2</td><td>rejects</td></tr><tr><td>F12</td><td>step 6 of 3.2</td><td>2</td><td>rejects</td></tr><tr><td>F13</td><td>Section 4, item 4</td><td>0</td><td>accepts</td></tr><tr><td>F14</td><td>Case 1 of 3.3</td><td>0</td><td>accepts</td></tr><tr><td>F15</td><td>step 1 of 3.2</td><td>1</td><td>rejects</td></tr></tbody>
        </table>
        <t>The proofbundle 6.4.0 commands used here receive no action bytes, effect bytes, expected executor.id or consumption state, and no expected decisionMaker.id. They reject F1, F2, F4, F11, F12 and F15 and return exit code 0 for the other nine command-line inputs. The procedures specified here reject F3, F5, F6, F7, F8, F9 and F14. F10 and F13 instead pass receipt verification and are refused by the relying party under <xref target="approvals-once"/>. F10 is refused with c1 under item 2, because ap2 is a copy of ap with other metadata and so the same approval. F13 is refused with c2 under item 4, because ap is recorded as consumed only in the rotated generation. Their acceptance by these commands does not test consumption-state enforcement. F9 shows why checking only the decision's expiry is insufficient. At the stated T of 09:16 the decision passes step 9 of <xref target="verify-decision"/>, while the approval expired at 09:15. Its validity.expiresAt exceeds the validUntil of ap, so the Case 1 time-bound condition of <xref target="verify-cases"/> is violated independently of T.</t>
      </section>
    </section>
    <section anchor="changes">
      <name>Changes</name>
      <t>This section is to be removed before publication.</t>
      <section anchor="changes-from-04">
        <name>Changes from -04</name>
      <t>Step 1 of <xref target="verify-decision"/> cites <xref target="RFC8259"/> for the JSON text of the envelope and rejects envelope bytes that begin with a byte order mark.</t>
      <t>Step 6 of <xref target="verify-decision"/> requires exactly one subject entry and no other entries, and step 2 of <xref target="verify-outcome"/> states the same rule for outcome receipts.</t>
      <t>Step 6 of <xref target="verify-outcome"/> states that the check of supplied effect bytes applies whatever the status, and <xref target="vectors-failure"/> says that F7 fails at its second sentence.</t>
      <t>Item 6 of <xref target="approvals-once"/> names the clock skew of the relying party.</t>
      <t><xref target="vectors-failure"/> names, for F10 and F13, the item of <xref target="approvals-once"/> on which the relying party refuses, and adds the consumption state c2 and the failure vectors F11 to F15, for a wrong _type, a wrong predicateType, an approval recorded as consumed only in a rotated generation, reasonCodes without user_approval in Case 1, and a Signed Evaluation Receipt presented as a decision receipt (<xref target="evaluation-receipts"/>).</t>
      <t><xref target="privacy-considerations"/> distinguishes the existence of the registered Signed Statement from the time of the decision and states that registration over the content root does not establish that the receipt's DSSE signature existed at registration time.</t>
      <t><xref target="vectors-table"/> names Case 3 as the procedure for V3-decision.</t>
      <t><xref target="vectors-failure"/> states that F15 tests the first half of the rule of <xref target="evaluation-receipts"/> and that its second half has no check step and no vector of its own.</t>
      <t><xref target="security-considerations"/> points to F13 for rotation.</t>
      <t>The reference <xref target="WRIGHT"/> cites revision -02.</t>
      <t><xref target="related"/> states that a verdict record of <xref target="WRIGHT"/> cites a receipt of this document by the SHA-256 over its envelope bytes, and that the content root is a different digest.</t>
      <t>The reference <xref target="IZMAYLOV"/> cites revision -02.</t>
      </section>
      <section anchor="changes-from-03">
        <name>Changes from -03</name>
      <t>New <xref target="vectors-registration"/> gives one example Signed Statement for each way of registration in <xref target="registration"/>, signed with a new test key, and a SCITT Receipt for each, generated with a library for illustration, and <xref target="registration"/> points to it. The informative references add RFC 8949, RFC 9052, RFC 9053, RFC 9162, RFC 9597, RFC 9679, RFC 9942, RFC 9995 and scitt-cose.</t>
      <t><xref target="verify-decision"/> step 7 and <xref target="verify-outcome"/> step 3 list by full path the members that are digests and timestamps, and step 7 gives the form of evidenceRefs[].typedDigest. <xref target="vectors-table"/> names the procedure that decides each vector. <xref target="vectors-registration"/> states that the entry of the tree is the choice of the example. New <xref target="vectors-failure"/> gives failure vectors for steps 7 to 10 of <xref target="verify-decision"/>, Case 1 of <xref target="verify-cases"/>, steps 5 to 7 of <xref target="verify-outcome"/> and <xref target="approvals-once"/>.</t>
      <t>New <xref target="field-rules"/> gives the field rules of both predicates as tables, step 7 of <xref target="verify-decision"/> and step 3 of <xref target="verify-outcome"/> refer to it, and <xref target="PB-DECISION"/> and <xref target="PB-OUTCOME"/> are informative references. The field rules distinguish JSON booleans from string literals. Step 1 of <xref target="verify-decision"/> rejects duplicate member names in DSSE envelopes. <xref target="vectors-failure"/> identifies the first failing check for each stated test procedure, distinguishes the relying-party check for F10, and explains that F9 violates the Case 1 time-bound condition independently of T. <xref target="implementation-status"/> and <xref target="vectors"/> distinguish the provenance of the seven DSSE vectors from that of the new examples. <xref target="privacy-considerations"/> clarifies that the field rules do not establish the absence of raw inputs. Case 1 of <xref target="verify-cases"/> allows inputSnapshot entries other than the approval record, and <xref target="verify-meaning"/> states which digests a pass checks against bytes.</t>
      </section>
      <section anchor="changes-from-02">
        <name>Changes from -02</name>
      <t><xref target="related"/> adds, for <xref target="GILDA"/> and <xref target="IZMAYLOV"/>, what this document does differently.</t>
      <t>The paragraph on clocks in <xref target="security-considerations"/> adds that a time-stamp token under <xref target="RFC3161"/> over the envelope bytes is an anchor outside the signer.</t>
      <t>New <xref target="observations"/> lists places where the mapping needed a reading of <xref target="AUDIT-ARCH"/>, as observations and questions.</t>
      <t><xref target="security-considerations"/> adds a paragraph on finding missing outcome receipts through the sequence member of <xref target="PB-OUTCOME"/>, and on boundary records for decisions.</t>
      </section>
      <section anchor="changes-from-01">
        <name>Changes from -01 to -02</name>
      <t>The submissionType attribute is removed from the rfc element.</t>
      <t>The Abstract states that the document describes, informatively, how a receipt can be registered with a Transparency Service under RFC 9943 and what a SCITT Receipt then shows and does not show.</t>
      <t><xref target="requirements-language"/> states to whom the key words apply.</t>
      <t><xref target="security-considerations"/> adds a paragraph on what a receipt still shows when a signing key of a decision maker or outcome signer is compromised or replaced.</t>
      <t><xref target="privacy-considerations"/> describes what each way of registration in <xref target="registration"/> reveals and distinguishes access to the registered Signed Statement from access to a detached payload.</t>
      </section>
      <section anchor="changes-from-00-to-01">
        <name>Changes from -00 to -01</name>
      <t>Added <xref target="registration"/>, an informative description of how a decision or outcome receipt can be registered with a Transparency Service under <xref target="RFC9943"/>, what a SCITT Receipt then shows and what it does not.</t>
      <t><xref target="not-adds"/>, the end of <xref target="verify-meaning"/>, <xref target="related"/> and the paragraph on suppression in <xref target="security-considerations"/> refer to <xref target="registration"/>. <xref target="security-considerations"/> adds that completeness presupposes an expectation of which receipts ought to exist, which this document does not define.</t>
      <t>The introduction states that the mapping follows revision -01 of <xref target="AUDIT-ARCH"/>.</t>
      <t>Sections 3.1 to 3.5, 4 and 5 and the test vectors of <xref target="vectors"/> are unchanged.</t>
      </section>
    </section>
    <section numbered="false" anchor="acknowledgments">
      <name>Acknowledgments</name>
      <t>The author used AI tools to help draft this document and to generate and
cross-check its examples. The author reviewed the entire text and is responsible
for it.</t>
      <t>Citing adjacent work in the References does not imply that its authors endorse this
document.</t>
    </section>
  </back>
</rfc>
