Internet-Draft Vaara Receipt October 2026
Sirkkavaara Expires 14 April 2027 [Page]
Workgroup:
Independent Submission
Internet-Draft:
draft-sirkkavaara-vaara-receipt-13
Published:
Intended Status:
Informational
Expires:
Author:
H. Sirkkavaara
Vaara

The Vaara Receipt: A Recomputable Receipt Format for Decisions About Autonomous Actions

Abstract

This document specifies vaara.receipt/v1, a signed and independently recomputable record that binds a decision about an autonomous action to the evidence the decision was made on, and optionally to one or more external timestamp anchors. The format is canonicalized with the JSON Canonicalization Scheme (JCS) so that a third party can recompute its digests, and, for a receipt signed with a public-key algorithm, verify its signature, without access to the issuer. A decision and the execution receipt that answers it form one recomputable pair through the envelope's back link.

The receipt's trust is root-agnostic: the same record is verifiable with or without a hardware trusted execution environment and is re-expressible as an IETF RATS Entity Attestation Result. Downstream specifications (a payment rail, a compliance regime, a framework integration) define profiles that pin to a version of this document and add only their own evidence schema; they do not redefine the envelope. The format described here is deployed, and its receipts are independently recomputable from public conformance vectors that ship with standalone checkers importing no issuer code. The minimal profile is the engine decision: one receipt per decision an engine records on its own audit trail, bound to the trail record it decided, with no external rail.

Status of This Memo

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

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

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

This Internet-Draft will expire on 14 April 2027.

▲

Table of Contents

1. Introduction

A Vaara receipt is a signed, independently recomputable record that binds a decision about an autonomous action to the evidence it was made on, and optionally to one or more external timestamp anchors. Any system that emits or consumes Vaara receipts conforms to this document. Downstream specifications define profiles that pin to a version of this document and add only their own evidence schema; they do not redefine the envelope. An action here is any operation an autonomous or semi-autonomous system performs; an AI agent tool call is one case, and the format does not depend on the actor being an AI agent. The property this provides is accountable autonomy: an autonomous system may act, and an outside party can still recompute what it was permitted to do and what it did, without trusting the operator.

The receipt's trust is root-agnostic. The same record is verifiable with or without a hardware TEE and re-expressible as an IETF RATS ([RFC9334]) Entity Attestation Result (an AR4SI vector, [I-D.ietf-rats-ear]), whether rooted in a TPM 2.0 host, an AMD SEV-SNP confidential VM, or software alone. The signature and the optional external time anchor carry the evidence, not a single trust root.

This document packages a format that already ships and is independently recomputable from public conformance vectors. The executable conformance fixtures live under tests/vectors/ in the source repository ([VAARA-REPO]), each directory with a checker (_check_independent.py) that imports no issuer code: only the standard library and, as its profile needs, libraries for signatures, JCS, ASN.1, or ML-DSA.

The floor of the format is the engine decision profile (Section 6.8): one receipt per decision an engine records on its hash-chained audit trail, bound to that trail record, with no payment rail, settlement artifact, or external evidence record to join. It is the smallest conforming receipt, it is what a default install of the reference implementation emits for every decision, and it is the entry point a producer reaches for first.

1.1. Terminology

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

2. Canonicalization, Digests, Numbers, and Times

Every digest of a JSON value in this document, and every signed payload, is computed over the JSON Canonicalization Scheme (JCS, [RFC8785]). The canonicalization label for the evidenceRef.canonicalization member (Section 4) is "jcs-rfc8785". The values "JCS" and "jcs-json-v1" are accepted aliases for the same algorithm; producers SHOULD emit "jcs-rfc8785", and consumers MUST accept all three.

A digest is written "sha256:" followed by the 64 lowercase hexadecimal characters of a SHA-256 ([FIPS180-4]) value. Unless the definition of a member says otherwise, the hashed bytes are the JCS encoding of the referenced JSON value. Where a member is a digest over bytes that are not a JSON value (a UTF-8 string, a configuration file, a joined preimage), its definition names those bytes.

No signed block and no evidence record defined in this document carries a non-integer number. Quantities that are not integers, such as risk scores and thresholds, are carried as decimal strings (for example "0.12"). A producer MUST NOT emit a non-integer JSON number in any of them, because two JCS implementations are only guaranteed to agree on integers within the range JCS defines.

Times are date-time strings as defined in [RFC3339], in UTC with the "Z" designator. Fractional seconds MAY be present. A consumer MUST NOT reorder or compare receipts by these strings without parsing them, because two producers can write the same instant with a different number of fractional digits.

3. The Receipt Envelope

A receipt is a JSON object. It is either a decision receipt, which records a decision about an action, or an execution receipt, which records what followed. Both kinds share the envelope below and differ in their derived block and their asserted block.

Table 1: Receipt envelope members
Member Type Kind Presence Meaning
version integer both REQUIRED 1 for this document.
alg string both REQUIRED "ES256", "RS256", or "HS256". See Section 3.1.
backLink object both REQUIRED The predecessor this receipt answers. See Section 3.3.
decisionDerived object decision REQUIRED The decision and its basis. See Section 4.
issuerAsserted object decision REQUIRED The issuer block. See Section 3.4.
outcomeDerived object execution REQUIRED The outcome. See Section 3.7.
receiptAsserted object execution REQUIRED The issuer block. See Section 3.4.
signature string both REQUIRED The signature over the signed payload (Section 3.2). See Section 3.1.
timestampAnchors array decision OPTIONAL External time attestations. See Section 5.
pqSignature object execution OPTIONAL A post-quantum signature beside the classical one. See Section 3.5.
existenceProof object execution OPTIONAL A timestamp over the whole signed receipt. See Section 3.6.

A decision receipt carries decisionDerived and issuerAsserted and neither outcomeDerived nor receiptAsserted; an execution receipt carries the reverse. The schema is closed. A consumer MUST reject a receipt that carries a member not listed for its kind in Table 1, and MUST reject any member not defined by this document inside backLink, decisionDerived, evidenceRef, issuerAsserted, receiptAsserted, outcomeDerived, completeness, cryptoPosture, pqSignature, or existenceProof. A consumer that rebuilds a signed block from the members it understands would otherwise leave out signed bytes, and could report a receipt as verified over content it never checked. Evidence records are defined by profiles (Section 6), and their own rules govern members they do not define.

Appendix A gives the envelope in CDDL ([RFC8610]). The CDDL and the prose are both normative. Rules the CDDL cannot express, such as runningCount equal to seq + 1, the issuer block alg equal to the envelope alg, and the absence of sigSuite from a decision receipt, are stated in the prose only.

3.1. Algorithms and Signature Encoding

alg names the algorithm of signature. ES256 is ECDSA using P-256 and SHA-256, and the signature is the 64-byte r||s pair as defined for "ES256" in [RFC7518]. RS256 is RSASSA-PKCS1-v1_5 using SHA-256, and HS256 is HMAC using SHA-256, both as defined in [RFC7518]. signature is the lowercase hexadecimal encoding of the raw signature or MAC bytes. No other alg value is defined in this version, and a consumer MUST reject a receipt that names one.

HS256 is symmetric. An HS256 receipt is verifiable only by a holder of the shared secret, so it is not recomputable by an arbitrary third party. Producers that intend receipts for parties outside their own trust domain SHOULD use ES256 or RS256.

The asserted block repeats the algorithm in its own alg member, inside the signed bytes. The two MUST be equal. A consumer MUST reject a receipt whose envelope alg and asserted-block alg differ, before trying any key.

3.2. Signed Payload

The signature is computed over the JCS encoding of the object containing exactly these members, with their receipt values:

<CODE BEGINS>
decision receipt:
  ("version", "alg", "backLink", "decisionDerived", "issuerAsserted")
execution receipt:
  ("version", "alg", "backLink", "outcomeDerived", "receiptAsserted")

<CODE ENDS>

"signature", "timestampAnchors", "pqSignature", and "existenceProof" are not part of the signed payload. Each is either the signature itself or evidence attached after signing, so attaching one does not invalidate the signature. A consumer MUST verify the signature by reconstructing the payload for the receipt's kind from the members as received, canonicalizing it, and checking it under alg with the verification key (the public key for ES256 and RS256, the shared secret for HS256).

3.4. Issuer Block

issuerAsserted (in a decision receipt) and receiptAsserted (in an execution receipt) have the same members. Both are inside the signed payload.

Table 3: Issuer block members
Member Type Presence Meaning
iss string REQUIRED The issuer.
sub string REQUIRED The subject: the agent or principal the action was taken by or for.
iat string REQUIRED Issuance time, an [RFC3339] date-time in UTC. This is a string, not a JSON Web Token NumericDate.
nonce string REQUIRED Unique per receipt. Producers SHOULD draw at least 128 bits from a cryptographic random source.
alg string REQUIRED Equal to the envelope alg (Section 3.1).
secretVersion string REQUIRED Names the verification key. A consumer resolves the key from iss and secretVersion out of band; this document defines no resolution protocol.
aud string OPTIONAL The relying party the receipt was issued for.
taskId string OPTIONAL The long-running task the action belongs to.
completeness object OPTIONAL The per-boundary sequence of this receipt, in the issuer block. The same block, carried in the evidence record, is the completeness layer of Section 6.4.
sigSuite string OPTIONAL The hybrid signature suite the issuer committed to (Section 3.5). Execution receipts only.
cryptoPosture object OPTIONAL The algorithms protecting the receipt and their post-quantum level (Section 3.5).

aud and taskId, when present, are non-empty strings. A consumer asked to check either against an expected value reports three outcomes: bound (present and equal), conflict (present and different), or unsupported (absent). An absent aud or taskId states that the issuer bound none. It does not state that the receipt was issued for any relying party or task.

completeness, when present, carries exactly three members, all REQUIRED: boundaryId (a non-empty string), seq (an integer, 0 or greater), and runningCount (an integer equal to seq + 1). A consumer MUST reject a completeness object that is partial or breaks these rules. The boundary of an execution receipt is the boundary of its decision receipts with "#execution" appended, so a refused decision, which has no execution receipt, does not read as a gap.

3.5. Post-Quantum Signature and Crypto Posture

There is no post-quantum alg value in this version. An execution receipt MAY carry a post-quantum signature beside the classical one. The issuer commits to it inside the signed payload with sigSuite, whose defined values are "ES256+ML-DSA-65" and "RS256+ML-DSA-65". The classical part of the value MUST equal alg. pqSignature then carries three non-empty strings: alg ("ML-DSA-65", [FIPS204]), keyid (names the ML-DSA verification key), and sig (the lowercase hexadecimal ML-DSA-65 signature over the same signed payload bytes the classical signature covers).

A consumer MUST reject a receipt whose sigSuite has any other value. A consumer that verifies ML-DSA MUST reject a receipt whose sigSuite names a hybrid suite and whose pqSignature is absent or does not verify: that is a stripped signature, and the committed sigSuite is what makes the stripping detectable. A pqSignature on a receipt without sigSuite commits nothing, and a consumer MUST NOT treat it as post-quantum protection. A decision receipt MUST NOT carry sigSuite.

cryptoPosture records which algorithms protect the receipt, in the shape of CycloneDX cryptographic properties. It has three REQUIRED members: assetType ("algorithm"), algorithms (a non-empty array of objects, each with exactly algorithm, primitive, and nistQuantumSecurityLevel), and nistQuantumSecurityLevel (an integer from 0 to 5, the highest level in algorithms). The levels are 0 for HS256 (primitive "mac"), ES256, and RS256 (primitive "signature"), and 3 for ML-DSA-65 (primitive "signature"). A consumer checks cryptoPosture by recomputing it from alg and sigSuite. A posture that does not match the recomputation, or that claims an ML-DSA leg without a sigSuite that commits it, is a claim the receipt does not back, and a consumer MUST NOT rely on it.

3.6. Existence Proof

An execution receipt MAY carry existenceProof, an RFC 3161 ([RFC3161]) timestamp over the whole signed receipt. It has exactly four members, all non-empty strings: backend ("rfc3161-eidas-qualified" in this version), hashAlgorithm ("sha256"), recordDigest (a digest of the receipt with existenceProof removed, signature included), and token (the base64 DER TimeStampToken whose message imprint is that digest). A consumer recomputes recordDigest from the receipt and requires the token's imprint to equal it. It is outside the signed payload; its integrity rests on the token, which covers the signed receipt including its signature. The attested time is qualified only when the consumer pins the token signer's issuing authority from a trusted list it holds; the backend value alone proves nothing.

3.7. Execution Receipt

An execution receipt records the outcome of the action a decision governed. Its conformance vectors are tests/vectors/execution_receipt_v0/, with a standalone checker that imports no issuer code.

Table 4: outcomeDerived members
Member Presence Meaning
status REQUIRED "executed" (the action ran), "refused" (it did not run), or "errored" (it was attempted and failed). A consumer MUST reject any other value.
completedAt REQUIRED Time the outcome was recorded (Section 2).
resultCommitment OPTIONAL A commitment to the result, or to the error for "errored". Absent for "refused".
decisionDigest OPTIONAL A digest of the decision receipt this outcome answers, over its signed members and its signature, without timestampAnchors.

resultCommitment takes one of two forms. The projection form is {projection, projectionDigest}: projection is a string holding the JCS encoding of a JSON value, and projectionDigest is "sha256:" over the UTF-8 bytes of that string. The value is either the result itself or the object {"digest": "sha256:..."} over the JCS encoding of the result, so a result is committed by value or by digest while the raw result stays private. The reference form is {ref, digest, canonicalization}: ref locates the result, digest is a digest of it, and canonicalization is "jcs". A consumer that holds the result recomputes the commitment.

The backLink pair (Section 3.3) binds the execution receipt to the call it answers. decisionDigest binds it to the content of one decision, so an outcome cannot be reattached to a different decision about the same call. Because status is inside the signed payload, an executed receipt replayed with its status changed to "refused" does not verify: the signed envelope, not any single sub-check, binds the outcome. See tests/vectors/execution_receipt_v0/normative/ and tests/vectors/decision_pairing_v0/.

3.8. Worked Examples

Two receipts from the conformance vectors, as the library wrote them. Both verify with the standalone checkers of their suites. Lines longer than the page are folded with the single-backslash strategy of [RFC8792]; the unfolded bytes are the vector files.

A decision receipt, the floor of the format (Section 6.8), from tests/vectors/trail_decision_v0/valid/0-allow.json. The evidence record it binds follows it; evidenceRef.digest is the SHA-256 of that record's JCS encoding, and the back link names the previous trail record's hash, here the hash of the empty string because this is the first record of its trail.

<CODE BEGINS>
========== NOTE: '\' line wrapping per RFC 8792 ==========

{
  "alg": "ES256",
  "backLink": {
    "attestationDigest": "sha256:e3b0c44298fc1c149afbf4c8996fb92427a\
  e41e4649b934ca495991b7852b855",
    "attestationNonce": "dc8b561b-01e2-4e8e-9af2-b8b0fcb9a2ff"
  },
  "decisionDerived": {
    "decidedAt": "2026-09-25T00:17:48.320Z",
    "decision": "allow",
    "evidenceRef": {
      "canonicalization": "jcs-rfc8785",
      "digest": "sha256:7663868c3f5830dba2be46d514c65451404b8cf93d75\
  69efff1493eb3c380a4e",
      "ref": "vaara:trail/dc8b561b-01e2-4e8e-9af2-b8b0fcb9a2ff",
      "schema": "vaara.trail-decision/v0"
    },
    "policyId": "policy:vaara-engine/1",
    "reason": "allow: risk=0.12 (threshold allow<0.55 deny>0.85)",
    "riskScore": "0.12"
  },
  "issuerAsserted": {
    "alg": "ES256",
    "iat": "2026-09-25T00:17:48Z",
    "iss": "vaara:engine",
    "nonce": "RBKpasu2API112jCGYcLZ0M7",
    "secretVersion": "es256:dfa441deb94a9c1c",
    "sub": "vector-agent"
  },
  "signature": "7ebfd51b88d876a46fea986beb497ef0e122e84f3356c5244dd0\
  a2a893a8aa7eaee95ec0c84d12a41929ea15403be85b0e9b1211ae4e6acb6dcb96\
  c4bafc42ad",
  "version": 1
}

<CODE ENDS>

The evidence record behind evidenceRef:

<CODE BEGINS>
========== NOTE: '\' line wrapping per RFC 8792 ==========

{
  "actionId": "vector-action-0",
  "agentId": "vector-agent",
  "decidedAt": "2026-09-25T00:17:48.320Z",
  "decision": "allow",
  "eventType": "decision_made",
  "previousHash": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e464\
  9b934ca495991b7852b855",
  "reason": "allow: risk=0.12 (threshold allow<0.55 deny>0.85)",
  "recordHash": "sha256:b0b163a567a30a5396583055f4a943484958c3ad082d\
  2d656b2b30ebf6105af4",
  "recordId": "dc8b561b-01e2-4e8e-9af2-b8b0fcb9a2ff",
  "riskScore": "0.12",
  "schema": "vaara.trail-decision/v0",
  "tenantId": "",
  "toolName": "read_file"
}

<CODE ENDS>

An execution receipt (Section 3.7) with an executed status and a projection result commitment, from tests/vectors/execution_receipt_v0/normative/es256_executed_projection/receipt.json. Its back link carries the attestation digest and nonce of the decision receipt it follows, so the outcome cannot be reattached to another decision.

<CODE BEGINS>
========== NOTE: '\' line wrapping per RFC 8792 ==========

{
  "alg": "ES256",
  "backLink": {
    "attestationDigest": "sha256:79acdd4bb3c22a688b1c3321b9a26cafb5c\
  b58c990a963874066d04b8497f70b",
    "attestationNonce": "fixed-attestation-nonce-000"
  },
  "outcomeDerived": {
    "completedAt": "2026-05-29T10:00:00Z",
    "resultCommitment": {
      "projection": "{\"deleted\":true,\"path\":\"/archive/2024-Q3.m\
  d\"}",
      "projectionDigest": "sha256:c9a4caed49b3efaa7908a29a550b8d33ff\
  bb088c52d519242477223a83214198"
    },
    "status": "executed"
  },
  "receiptAsserted": {
    "alg": "ES256",
    "iat": "2026-05-29T10:00:00Z",
    "iss": "issuer://test",
    "nonce": "fixed-receipt-nonce-0001",
    "secretVersion": "v1",
    "sub": "agent:archiver"
  },
  "signature": "867c0439a289d77b75d489b07c42292095c947869365f1c92d98\
  2440338bddf0bb0bf91212cf9b1e681b076315862b5458f5167e98f0fca3a03c42\
  3b2a825f44",
  "version": 1
}

<CODE ENDS>

4. Decision and Evidence Binding (decisionDerived)

Table 5: decisionDerived members
Member Presence Meaning
decision REQUIRED "allow", "block", or "escalate". A consumer MUST reject any other value.
decidedAt REQUIRED Time of the decision (Section 2).
reason OPTIONAL The issuer's reason, a string.
policyId OPTIONAL Names the policy the decision was made under.
riskScore, thresholdAllow, thresholdBlock OPTIONAL Decimal strings (Section 2): the score the decision rested on and the thresholds it was compared with.
clientTurnId OPTIONAL A turn identifier the client supplied. It records that the client claimed it, not that the issuer vouches for it.
evidenceRef OPTIONAL Binds the decision to an evidence record. Every profile in Section 6 requires it.
rationale OPTIONAL The rule that decided and why, in words.
binding OPTIONAL Digests binding the decision to its policy, intent, and inputs.
decisionProof OPTIONAL A zero-knowledge proof over binding.

"allow" means the action was permitted. "block" means it was refused. "escalate" means it was referred to a person or another authority and was not permitted at the time of the decision; a later decision, with its own receipt, settles it. These are the only values. Profiles below name verdicts that a verifier computes, such as "deny" or "revise"; those are outputs of a checker, not values of decision.

rationale has the members rule, reason, and declaredIntent (strings, REQUIRED) and intentSatisfied (a boolean, OPTIONAL). binding has four REQUIRED digests: policyDigest over the JCS encoding of the policy, intentDigest over the UTF-8 bytes of the declared intent, inputsDigest over the JCS encoding of the evaluation inputs, and bindingDigest over the UTF-8 bytes of policyDigest, intentDigest, inputsDigest, and decision joined in that order by the single byte 0x1F. decisionProof is a proof that the committed values reach the stated decision, opened against bindingDigest; its format is not defined by this document. A consumer that does not verify decisionProof MUST NOT read it as evidence of anything, and the signature covers it either way.

Table 6: evidenceRef members
Member Presence Meaning
canonicalization REQUIRED A label from Section 2.
digest REQUIRED A digest of the evidence record.
schema REQUIRED The schema identifier of the evidence record, defined by its profile.
ref OPTIONAL An advisory locator for the evidence record, defined by the profile. Not an identifier; see below.

The binding is recomputable: given the receipt and the evidence record, a third party confirms that the digest of the evidence record equals evidenceRef.digest with no access to the issuer.

The digest is the binding; ref is advisory. A profile MAY assign the same ref to more than one evidence record, and profiles in use do: where a single action settles to several parties, each party's record is a separate evidence record carried under one shared ref. Those records differ under digest because their contents differ.

A consumer therefore MUST NOT resolve an evidence record by ref alone, and MUST confirm that the digest of the evidence record equals evidenceRef.digest before treating the record as the one the receipt decided over. Resolving by ref alone admits a record that shares the locator but is not the record the issuer signed over, and no check in this document fails when that happens.

5. Timestamp Anchors (timestampAnchors)

A timestamp anchor is evidence from outside the issuer that a decision receipt existed no later than a stated time. Anchors are optional and are attached to decision receipts; an execution receipt carries its time evidence in existenceProof (Section 3.6). Every anchor binds anchoredDigest, the digest of the receipt's signed payload (Section 3.2), so an anchor commits to the exact signed receipt and does not depend on any other anchor.

<CODE BEGINS>
{
  "method": "rfc3161",
  "anchoredDigest": "sha256:...",
  "token": "<base64 DER RFC 3161 TimeStampToken>",
  "authority": "<optional human-readable authority name>"
}

<CODE ENDS>

method is REQUIRED and selects the members that follow. anchoredDigest is REQUIRED for every method. authority is OPTIONAL and informative.

Table 7: Timestamp anchor methods
method What it is Further members
rfc3161 An RFC 3161 ([RFC3161]) timestamp token whose message imprint is anchoredDigest, from any time-stamping authority, including one the producer runs. token
rfc3161-eidas-qualified As rfc3161, from a qualified time-stamping authority under eIDAS ([eIDAS]). The qualification adds legal weight and nothing else. token
rfc3161-blinded As rfc3161, with the authority shown a salted digest instead of anchoredDigest. token, anchorSalt
rfc3161-eidas-qualified-blinded As rfc3161-eidas-qualified, blinded the same way. token, anchorSalt
scitt Inclusion of anchoredDigest as a leaf of an append-only Merkle log hashed as in [RFC6962]. The identifier is kept for receipts that already carry it; this method is not registration with a SCITT Transparency Service and its entry is not a COSE receipt. logId, leafIndex, treeSize, inclusionProof, rootHash

For every method a consumer MUST first recompute anchoredDigest from the receipt and reject the anchor if it differs. For the rfc3161 methods token is the base64 DER TimeStampToken, and a consumer requires its message imprint to equal anchoredDigest, or the blinded imprint below. The method name is not proof of who signed the token: a consumer treats the attested time as independent of the issuer only when it checks the token signer against a certificate or trusted list it holds, and as qualified only when that list is a qualified trust list.

A blinded method keeps the authority's request log from being matched against published receipts. The producer draws a fresh 32-byte salt from a cryptographic random source, sends the authority the imprint SHA-256("vaara/anchor-blind/v1" || salt || D), where D is the 32 raw bytes of anchoredDigest and the label is ASCII, and carries the salt as anchorSalt (64 lowercase hexadecimal characters). A producer MUST NOT reuse a salt. A consumer MUST recompute the imprint, MUST reject a blinded anchor whose anchorSalt is absent or malformed, and MUST reject an unblinded method that carries anchorSalt, so that a blinded anchor is never read as a plain one. Blinding does not hide the anchor from anyone holding the receipt, since the salt travels with it, and it does not hide the timing or volume of requests from the authority.

For the scitt method logId is the base64 SHA-256 of the log's name, leafIndex and treeSize are integers, inclusionProof is an array of base64 sibling hashes, and rootHash is the base64 root at the time of append. A consumer recomputes the root from the leaf (the 32 raw bytes of anchoredDigest) and inclusionProof. rootHash is the log operator's own claim. The anchor witnesses the receipt only when the consumer checks rootHash against a tree head it holds independently of the receipt, directly at the same tree size or through a consistency proof ([RFC9162]) to a later head.

The method registry is maintained by this document. A consumer MUST NOT treat an anchor whose method it does not implement as verified, and MUST NOT reject the receipt because of it: the receipt's integrity rests on its signature, and an anchor is additional evidence.

Registration with a SCITT Transparency Service ([RFC9943]) complements an anchor and is not one. A receipt's bytes can be the attached payload of a SCITT Signed Statement. The service's receipt commits to that Signed Statement as registered, not to anchoredDigest, so it travels beside the receipt and is not carried in timestampAnchors. A consumer verifies it against the statement bytes and the service's published keys, with no call to the service.

A receipt MAY carry several anchors of different methods. The producer's own time evidence (rfc3161 from its own authority, or scitt) and the legal anchor (rfc3161-eidas-qualified) are independent and can be added separately.

6. Profiles

A profile is a downstream specification that uses this envelope unchanged and defines only its own evidence record (the schema and contents behind evidenceRef), plus any join keys it needs. A profile MUST state the vaara.receipt/vN version it pins to and SHOULD ship recomputable vectors.

There is one binding mechanism, not one per plane. Each named profile (Section 6.3, Section 6.4, Section 6.5, Section 6.6) names an external artifact by content address and binds it through this envelope unchanged; they differ only in which artifact is hashed and the evidenceRef.ref label. Section 6.7 states that mechanism in schema-agnostic form: a single binding that does not depend on what is connected to it. The named profiles are instances of it, kept because a given ecosystem pins to a label it recognizes as its own.

6.1. Registry

The profiles below pin to vaara.receipt/v1. Vector paths are relative to the source repository ([VAARA-REPO]).

Table 8: Profile registry
Profile Evidence schema Vectors
x402 settlement binding x402.settlement.*/v0 tests/vectors/x402_settlement_v0/
authorization decision vaara.authorization/v0 tests/vectors/authorization_v0/, tests/vectors/contiguity_v0/, tests/vectors/class_gate_v0/
AP2 checkout binding vaara.authorization/v0 (names AP2 PEF frame_id) tests/vectors/ap2_v0/
TAP request binding tap.request/v0 tests/vectors/tap_v0/
generic external execution evidence vaara.authorization/v0 (names an external_execution_evidence slot) tests/vectors/external_evidence_v0/
engine decision (the floor) vaara.trail-decision/v0 tests/vectors/trail_decision_v0/, tests/vectors/cage_v0/

Three further suites in the same repository are related to this format and are not profiles of it, because the artifact each one verifies is not a vaara.receipt/v1 envelope: governance_decision_v0 (Section 6.2), credential_binding_v0 (the signed HS256 grant a credential broker issues, the artifact the authorization profile's grantFingerprint names), and atlas_threat_v0 (a flat HMAC record exercised against MITRE ATLAS agent threat patterns). Each ships a standalone checker, and none defines an evidence schema for evidenceRef.

This section is informative. tests/vectors/governance_decision_v0/ holds signed governance decision and outcome records in the contract shape proposed for the CrewAI framework (schemas crewai.governance.decision/v1 and crewai.governance.outcome/v1), each record wrapped as {"record", "signature"} with an ES256 signature over the JCS encoding of the record. They are not vaara.receipt/v1 envelopes and define no evidence schema for evidenceRef; earlier revisions of this document described them as the floor of this format, which they were not.

What the suite does pin is the part a third party recomputes with a JCS library and a signature library alone: an intent_ref derived from the schema, agent, action type, normalized scope and an intent digest over the call parameters, so a re-presented authorization recomputes to the same identity on a retry; a target-state digest and a decision context hash binding the policy set and the continuation; four fail-closed verdicts (intent mismatch, target-state drift, continuation mismatch, duplicate outcome); and a per-run completeness sequence with a terminal seal, the same layering as Section 6.4. The member names of these preimages are those of the records themselves, in snake case, and the checker is tests/vectors/governance_decision_v0/_check_independent.py; a second checker with no dependencies at all, _check_zerodep.py, reaches the same verdicts.

The case cases/unicode_scope.json carries a normalized scope with non-ASCII characters. Under RFC 8785 these are emitted as their raw UTF-8 bytes; a producer that escapes them to \uXXXX form canonicalizes different bytes and fails the vector, which is the cheapest way to catch a canonicalizer that is sorted JSON but not JCS. That property holds for every digest in this document.

6.3. Profile Example: x402 Settlement Binding

This profile binds an x402 payment settlement to a Vaara receipt across an action lifecycle, on a generic rail and on the Sui exact-payment rail. It adds:

  • A settlement record (schema = x402.settlement.<rail>/v0) whose JCS digest is the receipt's evidenceRef.digest.
  • A join key actionRef = sha256(JCS({agentId, actionType, scope, timestampMs, seq, terminal})), carried on the settlement, so an in-progress receipt (terminal: false) cannot be presented where the terminal one is required.

A third party recomputes three per-step verdicts (action-ref recomputes, settlement binding resolves, signature verifies) and one lifecycle verdict, with only the settlement and the receipt in hand. See _check_independent.py in the vectors directory.

6.4. Profile Example: Authorization Decision

This profile turns an enforcement decision into a receipt. A credential broker authorizes a tool call against a signed, attestation-bound grant with typed capability scopes; the gateway's verdict, allow or deny, is minted as a receipt instead of being discarded. The decision maps onto the envelope verdict vocabulary: an allowed call is "allow", a refused call is "block" carrying the machine reason (capability_exceeded, binding_unknown, missing_credential, ...) as decisionDerived.reason. It adds:

  • An authorization record (schema = vaara.authorization/v0) whose JCS digest is the receipt's evidenceRef.digest. It binds toolName, tenantId, the grant by content address (grantFingerprint = sha256(JCS(grant)) over the grant with its signature member removed, the bytes the grant's signature covers; an ECDSA signature has two valid encodings for one signing act, so a digest over the signature would give one grant two identities), the runtime argument commitment (argsCommitment = sha256(JCS(args))), the evaluated capabilities, and the verdict / reason.
  • The raw arguments never enter the record; only their commitment does, so the receipt is publishable while the arguments stay private. An auditor holding the arguments out of band recomputes the commitment and re-runs the verdict.
  • An optional coverage block names the observation boundary the decision was made under, inside the record and therefore under the signature. It binds the boundary (the chokepoint identity), the serverFingerprint (the exact capability surface in scope, manifest:sha256(JCS(tools)) or the command hash), and a scope literal stating that only calls routed through the chokepoint are observed. A tool reached on an out-of-band path is out of coverage. The block is absent when no boundary is asserted, leaving the record byte-identical to a coverage-free decision.
  • An optional completeness block scopes a sequence to that boundary, inside the record and therefore under the signature. It binds the boundaryId (the same boundary the coverage block names), a monotonic seq starting at 0 with no gaps by construction, and a runningCount equal to the total receipts issued under the boundary up to and including this one (runningCount = seq + 1). The block is absent when no sequence is asserted, leaving the record byte-identical to a completeness-free decision.
  • An optional sealing record finalizes the boundary: a terminal completeness block ({boundaryId, sealed: true, total: N}) that pins the boundary's final count independently of the per-record sequence. It is additive and emitted once the boundary is closed; a boundary that is never sealed verifies exactly as before, with the seal absent and the stream byte-identical. The seal may also carry maxClass, the highest action class the boundary authorized; it bounds a gap's worst case and is itself optional.

A verdict is only as meaningful as what the issuer could see. "allow" over an unbounded surface and "allow" over a stated one are identical bytes with opposite meaning, so an absent refusal reads as fact only against a declared scope: "not refused within this boundary", never "not observed". The coverage block carries that boundary in the trace itself, so it is recomputable evidence rather than a separate trust root. The verdict stays a thin read over it. The chokepoint remains an observer of what passes through it, not a claim about what does not.

The deny case is the point. A refused call leaves a signed, content-addressed, portable proof of the non-action: a third party recomputes the verdict from the grant and the arguments and confirms the refusal, trusting only the issuer's public key. A third party recomputes five verdicts per case (grant fingerprint, argument commitment, capability verdict, evidence binding, signature) with only the grant, the arguments, the evidence, and the receipt in hand. See _check_independent.py.

Coverage states the boundary; completeness makes a gap inside it provable. With the per-boundary seq contiguous by construction and the runningCount signed into each record, a dropped receipt is a missing sequence number that any holder detects from the receipts alone: the highest running count names how many exist, so a short set is self-evidently incomplete and the absent seq is named. This needs no issuer access and no external witness. The tests/vectors/contiguity_v0/ vectors and the "vaara verify-contiguity" surface carry that check.

The per-record running count alone cannot tell a pure tail truncation (holding 0..k with nothing after) from a complete stream, since the latest held count is then k + 1 and reads as whole. The optional sealing record closes that gap: when a boundary is finalized, the holder expects max(seq + 1, runningCount, total) records, so a dropped tail shows as the missing range up to the sealed total. A boundary that is never sealed verifies exactly as before. One residual remains, and it is irreducible from the held set alone: a suffix drop that also suppresses the sealing record leaves nothing to detect. Closing that is the job of an rfc3161 anchor over the running count (Section 5), which attests that at time T, N receipts existed under the boundary. The layering is seq for order, the hash chain for tamper-evidence, the sealing record for a truncated tail, and the timestamp anchor for the seal-suppressed residual.

A gap proves that a record is absent but not what it would have authorized. When worst-case-governs is the reading, the seal's optional maxClass bounds it: it names the highest action class the boundary authorized, so a missing record could have authorized an action of at most that class. The verifier surfaces this as worstCaseClass, computed from the held set and the seal alone, with no issuer. The field is optional; absent it, a gap reports only that a record is missing.

Beyond bounding a gap at audit time, the sealed maxClass is consumable at enforcement time. A chain recipient gating its own next unattended action holds a policy set of action classes it will proceed under and permits if and only if the sealed worst-case class is a member of that set, failing closed when no class is sealed. This is a membership test, not an ordering: this document computes no ordering over class labels, so the recipient asks "is the sealed class one I permit", never "is it at or below a ceiling". Because the seal bounds a gap's worst case at maxClass, a permitted class permits even when the boundary has a gap: the recipient consumes the committed bound and does not re-derive the chain or query a log. The bound is trustworthy under the honest issuer whose seal commits before any tail is trimmed; a seal that under-states the class is a reconciliation question against the issuer's log, not one this held-set-alone gate answers.

maxClass lives in the unsigned evidence block, so a recipient MUST NOT consume it raw. It rides under signature only through the binding: the seal's signed decisionDerived.evidenceRef.digest is "sha256:" + JCS(evidence), so recomputing that digest proves the class is the class that was signed. Before gating, a recipient MUST verify each receipt's signature and that its evidence recomputes to the signed digest; a seal whose binding fails is not trusted, contributes no class, and the gate fails closed. Without this, an agent loosens the gate by relabeling an irreversible action's class into a permitted one while the record signature, which never covered the evidence, still verifies. The conformance vectors are in tests/vectors/class_gate_v0/; the deny_relabeled case carries exactly this attack and the independent checker rejects it.

6.5. Profile Example: AP2 Checkout Binding

This profile binds an AP2 checkout to the post-checkout agent actions a credential broker authorizes, so the actions taken after a payment settles carry the same recomputable, gap-evident record as the authorization decisions in Section 6.4. It reuses the vaara.authorization/v0 evidence record unchanged and adds a join to the AP2 Payment Evidence Frame (PEF, AP2 PR #274):

  • The AP2 checkout emits a PEF whose frame_id = sha256(JCS(frame)), with frame_id and signature excluded from the preimage, and whose receipt_hash = sha256(JCS(receipt)) content-addresses the wrapped Checkout Receipt. Canonicalization is urn:x402:canonicalisation:jcs-rfc8785-v1 (JCS / RFC 8785), the same as this envelope, so the address joins with no re-canonicalization.
  • Each post-checkout authorization receipt names the checkout it followed by content address: decisionDerived.evidenceRef.ref = ap2:checkout/<frame_id>, under the receipt signature. The AP2 task scope is the coverage.boundary (Section 6.4), and the completeness block sequences the actions under it.

The identity of the checkout is the PEF frame_id, a content address the payment side already computes; the completeness of the actions taken under it is the vaara.authorization/v0 contiguity stream. A per-action hash says an action was recorded; the running count says none inside the AP2 task boundary was dropped. A third party recomputes the frame address, confirms every receipt names that checkout, resolves each evidence binding, verifies each signature, and re-runs the gap check, with only the PEF and the held receipts in hand. See tests/vectors/ap2_v0/_check_independent.py. AP2 can pin from the point the Checkout Receipt ends rather than define a new post-settlement primitive.

6.6. Profile Example: TAP Request Binding

This profile binds a Visa Trusted Agent Protocol (TAP) request to the action a trusted agent takes under it, across the action lifecycle, so the post-authorization record is the same recomputable evidence as any other decision receipt. It adds a TAP request evidence record (schema = tap.request/v0) whose JCS digest is the receipt's evidenceRef.digest, and the join key actionRef = sha256(JCS({agentId, actionType, scope, timestampMs, seq, terminal})) carried on the request:

  • The trusted agent presents the TAP request to the relying party. The decision receipt names it by content address: decisionDerived.evidenceRef.digest = sha256(JCS(request)), decisionDerived.evidenceRef.ref = tap:request/<actionRef>, both under the receipt signature. Canonicalization is JCS / RFC 8785, the same as this envelope, so the address joins with no re-canonicalization.
  • The lifecycle lives in the join key. Because the action tuple covers terminal, the in-progress (terminal: false) request has a different actionRef than the final (terminal: true) one, and the in-progress receipt does not resolve against the terminal request. A mid-action receipt cannot be presented where the final one is required.

The verdict is recomputable offline. A third party recomputes the action ref, resolves the request binding, and verifies the signature with only the TAP request, the held receipts, and the issuer's public key, with the TAP service offline and no live verifier endpoint to trust. See tests/vectors/tap_v0/_check_independent.py. TAP can pin to vaara.receipt/v1 for the post-authorization record rather than define a new primitive.

6.7. Profile: Generic External Execution Evidence

This is the schema-agnostic binding the named profiles above are instances of. It takes any external execution-evidence artifact, content-addresses it, and binds it through this envelope unchanged, with no field names that depend on what produced it. A verifier carrying an external_execution_evidence slot (linked_call_id / evidence_hash / evidence_type, written linkedCallId, evidenceHash and evidenceType in the vectors) resolves that slot against a vaara.receipt/v1 authorization receipt as the recomputable producer:

  • evidence_hash = sha256(JCS(evidence_record)), equal to the receipt's decisionDerived.evidenceRef.digest, so the slot and the receipt name the same recomputable artifact (JCS / RFC 8785, no re-canonicalization).
  • linked_call_id is the call the receipt names: decisionDerived.evidenceRef.ref = mcp:call/<linked_call_id>, under the receipt signature.
  • evidence_type is the receipt's evidence schema (vaara.authorization/v0).

The trace is the coverage.boundary, and each receipt carries a signed completeness block (seq + runningCount), so the held set proves not only that each named call's evidence resolves but that none inside the boundary was dropped. A slot's evidence_hash alone proves a given record exists; the completeness block turns a silent drop into a named gap. The dropped vector withholds one record, slot and receipt both, and the signed running count still proves it existed.

A third party recomputes every verdict offline with only the held slots, the receipts, and the issuer's public key, with no live verifier endpoint to trust. See tests/vectors/external_evidence_v0/_check_independent.py. Any plane that emits execution evidence pins here by naming its artifact through this slot, rather than defining a new primitive or a profile of its own.

6.8. Profile: Engine Decision

An engine that keeps a hash-chained audit trail writes one decision receipt per decision it records on that trail. The evidence record is the decision as the trail holds it, under schema vaara.trail-decision/v0. It carries no tool arguments, so a receipt can leave the machine without them.

Table 9: vaara.trail-decision/v0 evidence members
Field Meaning
schema "vaara.trail-decision/v0".
recordId, actionId The trail record and the action it decided.
eventType "decision_made" or "action_blocked".
agentId, toolName, tenantId As recorded. tenantId is "" when unset.
decision, reason The trail's verdict ("allow", "escalate" or "deny") and its reason.
riskScore Decimal string.
decidedAt ISO 8601 UTC with milliseconds.
recordHash "sha256:" and the trail record's own hash.
previousHash "sha256:" and the hash of the record before it. An empty genesis link is written as the SHA-256 of the empty string.
decisionDetail The refinement behind the verdict, present only when the trail record carries one.
approver, humanDisposed The disposition: present together, only when the trail record carries an approver. See below.
cage OPTIONAL. The cage block (Section 6.8.1).

The envelope writes the trail's "deny" as "block". backLink.attestationDigest is previousHash, backLink.attestationNonce is recordId, and evidenceRef.ref is "vaara:trail/" followed by recordId. A verifier checks the signature and the evidence digest as in Section 3.2 and Section 4. With the trail in hand it also looks up recordId and confirms that the stored record hash matches recordHash; a receipt whose record is missing from the trail, or whose hash differs, fails. See tests/vectors/trail_decision_v0/_check_independent.py.

approver and humanDisposed name what kind of party disposed of the decision, inside the evidence record and therefore under the signature. approver is exactly "human" or "policy", and humanDisposed is a boolean that is true only when a human acted on this decision. A producer MUST NOT emit humanDisposed true with an approver other than "human". The converse is permitted: approver "human" with humanDisposed false records a human who reviewed while the disposition stayed automatic, which only narrows the claim. Both members are absent when no disposition was asserted, leaving the record byte-identical to a disposition-free decision.

The disposition exists because one verdict word covers dispositions a relying party has to separate. A decision admitted because a human approved it, and a decision admitted because an earlier human approval was replayed against a matching argument commitment, both carry the verdict "allow". The second was disposed of by the deployment, against an argument commitment some human approved at another time and on another action. Where that difference reaches a consumer only as free text, a consumer that must branch on human involvement cannot do it from the signed members. The approver vocabulary is closed at two values: a value an implementation may invent is a value a relying party cannot branch on.

A consumer MUST NOT infer human involvement from absent disposition members. Absence states that no disposition was asserted, and records written before these members existed carry none. See tests/vectors/decision_disposition_v0/ for the live-approval, replayed-approval and policy-claiming-human cases.

6.8.1. Cage Block

The cage block states which cage, if any, the process that made the decision ran in, and whether the issuer confirmed at decision time that the confinement held on that process. A cage here is any isolation layer an agent is started in: a mandatory access control profile, a system call filter, a user-space kernel, or a virtual machine. The block is a member of the evidence record, so evidenceRef.digest and the signature bind it like any other member.

Table 10: Cage block members
Field Type Required Meaning
driver string MUST The name of the cage's driver, never empty, or "none" when no cage was declared to the deciding process.
confirmed boolean MUST Whether the confinement was confirmed at decision time, as defined below.
basis string MUST unless driver is "none" What the confirmation rests on: "declared" when only the launcher's declaration stands, otherwise the name of the fact that was read.
configDigest string MAY "sha256:" and 64 lowercase hexadecimal characters over the cage's effective configuration.
upstream string MAY Informative. The cage's own name and version.
name string MAY Informative. The name of this launch inside the cage.

A block with driver "none" MUST carry confirmed false and MUST NOT carry any other member. A block with any other driver MUST carry basis.

confirmed true means exactly this: at decision time the issuer read, on the deciding process or on the platform under it, the fact that basis names, and the fact held. confirmed true MUST be accompanied by a basis other than "none" or "declared". It does not mean that the cage enforced the configuration configDigest names, that the cage is free of defects, or that any party other than the issuer observed the fact. confirmed false with basis "declared" means that a launcher declared the cage and the issuer did not confirm it.

The block names the deciding process, not the agent the decision was about. One launch can therefore produce blocks that differ by the surface the decision was made on: a decision made inside the caged tree names the cage and confirms it; a decision made by a process outside the tree about that tree (a file-system guard, an egress proxy) names that process's own confinement, which may be "none" or the declared block unconfirmed. Each is true of the process that signed it. A consumer collecting one launch's receipts groups them by subject and name, not by the block.

Each driver defines which bytes its configDigest covers. A consumer uses configDigest as a comparator: two receipts with the same driver and configDigest ran under the same declared configuration. A consumer that holds the configuration and the driver's rule MAY recompute the digest; one that does not treats it as an opaque value. A configDigest that does not match the stated form makes the block non-conforming.

The values of driver and basis form open sets. Their names carry no normative meaning beyond the rules above; Appendix B lists the values in use at the time of writing. A consumer MUST ignore cage block members it does not recognize. An evidence record without a cage block makes no claim about confinement, and a consumer MUST NOT read its absence as either confined or unconfined.

The conformance vectors are tests/vectors/cage_v0/: a run outside any cage, a cage declared and not confirmed, and a confirmed cage, written by a reference engine; a block changed after signing, which fails the evidence digest; and three blocks that are signed and digest-consistent but break a rule of the block (confirmed on basis "declared", confirmed with driver "none", and a malformed configDigest). The standalone checker tests/vectors/cage_v0/_check_independent.py gives each file a signature, evidence, and cage verdict and imports no issuer code.

7. Conformance

An implementation conforms to vaara.receipt/v1 if, for every receipt it emits:

  1. The receipt keeps the rules of Section 3 and Section 4: one kind, no undefined members, an alg defined in Section 3.1 and repeated unchanged in the issuer block, a decision or status value defined there, and a well-formed completeness block where one is present.
  2. The Section 3.2 signature verifies against the stated alg and key.
  3. evidenceRef.digest equals sha256(JCS(evidence_record)) for the referenced record, under one of the Section 2 canonicalization labels.
  4. Any timestampAnchors[].anchoredDigest equals the digest of the signed payload of the same receipt, and any existenceProof.recordDigest equals the digest of the receipt with existenceProof removed.
  5. For an execution receipt (Section 3.7), backLink.attestationDigest equals "sha256:" of the JCS-canonical predecessor and backLink.attestationNonce equals the predecessor's issuerAsserted.nonce; and when status is "executed", resultCommitment.projectionDigest equals "sha256:" of the projection bytes.
  6. Any cage block in an evidence record (Section 6.8.1) keeps the rules of that section.

The committed vectors plus _check_independent.py are the reference conformance suite; running the x402 profile checker and having it exit 0 is a passing run for that profile.

The same vectors serve as recomputable test evidence for the reversibility classification and enforcement controls in OWASP AISVS 1.0 ([AISVS2026]), specifically C9.2.3 (trusted reversibility classification), C9.2.4 (runtime enforcement of reversibility), and C9.2.10 (highest-impact class enforcement across multi-step chains).

8. Implementation Status

This section records the status of known implementations at the time of writing, per [RFC7942]. It is informational and may be removed before publication. The format is not specific to any single agent runtime; it records decisions about autonomous actions in general, of which AI agent tool calls are one case.

A reference implementation ships the format at three layers, all in the source repository ([VAARA-REPO]):

A default install of the library signs a receipt for every decision. The signing dependencies are part of the base package, not an optional extra.

The implementation also takes a receipt to roots outside its own signature. It registers a receipt with an IETF SCITT Transparency Service ([RFC9943]) over the reference APIs ([I-D.ietf-scitt-scrapi]) and verifies the service's receipt with no network access (Section 5). A continuous-integration job registers a decision receipt with a SCITT ledger built from its public source, stops the ledger, and verifies the result offline. For an AMD SEV-SNP host, it checks an attestation report's signing key offline against AMD's root key: the root certifies the intermediate key, the intermediate certifies the VCEK or VLEK ([AMD-VCEK]), the VCEK's chip identifier and TCB match the report ([AMD-SNP-ABI]), and the report signature verifies under it. The check passes on a report from production hardware. It does not consult AMD's certificate revocation list. The in-guest report emitter follows the kernel interface and has not yet been run inside a guest by the implementation.

The library, vectors, and checkers are exercised on every release. The application is built from source on the installing machine by its package formula and is not distributed as a notarized build.

9. Versioning

The envelope version is the integer "version" member and the vaara.receipt/vN schema identifier. A change to the signed-payload member set, the canonicalization, or the signature construction bumps N.

A new OPTIONAL member of a block defined in Section 3 or Section 4 is added only by a revision of this document and does not bump N. Because those blocks are closed (Section 3), a consumer built to an earlier revision rejects a receipt that carries the new member. That is intended: it fails closed rather than verifying bytes it does not understand. A producer that needs receipts accepted by such consumers omits the new member. New anchor methods and new profiles do not change how the envelope is parsed.

10. Security Considerations

The integrity of a receipt rests on the Section 3.2 signature over the JCS-canonical signed payload, not on any timestamp anchor or trust root. A consumer MUST verify that signature, under the algorithm "alg" names and with the key the issuer block names through iss and secretVersion, before relying on any field. Because the signed payload excludes "signature" and "timestampAnchors", anchors added after signing cannot alter the signed content; a consumer MUST recompute each anchoredDigest from the signed payload rather than trusting the anchor's stated value.

Verifying that signature establishes that the key the issuer block names produced the signed payload and that the payload has not changed since. It says nothing about the state of that key now. Offline verification is a computation over the parameters the consumer holds, while revocation is a property of the present, and this document defines no revocation mechanism and places no freshness requirement on key material. A consumer MUST NOT treat a signature that verifies as evidence that the signing key is still valid. Where a decision depends on revocation state, the key resolution path and the staleness a deployment accepts are operational parameters of that deployment and MUST be stated by it; the receipt does not carry them.

Recomputability depends entirely on canonicalization. A producer and a consumer that disagree on JCS output for the same JSON value will compute different digests; implementations MUST use a conformant JCS ([RFC8785]) implementation and MUST treat any of the three accepted labels as the same algorithm.

The argument commitment in the authorization profile (Section 6.4) lets a receipt be published while the raw arguments stay private, but a low-entropy argument set is open to a dictionary attack against the commitment. Producers SHOULD ensure the committed object carries sufficient entropy (for example a per-call nonce) where argument confidentiality matters.

An absent refusal is evidence only within a declared coverage boundary (Section 6.4). A reader MUST NOT read a missing receipt as "the action did not happen"; without a coverage block it means only "not observed", and with one it means "not refused within this boundary". The completeness block makes a dropped receipt inside the boundary detectable, but a pure tail truncation is not detectable by sequence contiguity alone and requires a timestamp anchor over the running count to close.

A decision receipt records what was decided. It does not record what followed. A decision receipt carrying the verdict "allow", with no execution receipt bound to it by backLink, establishes that the action was permitted and establishes nothing about whether it ran. A consumer MUST NOT read a decision receipt as evidence that the action took effect: the executed status lives in the execution receipt's outcomeDerived and is signed there (Section 3.7). Only the pair establishes that an action was permitted and then took effect, which is why backLink is a required member.

A recipient that consumes a sealed maxClass to gate its own next action (Section 6.4) MUST bind the class to the signature before acting on it. maxClass sits in the unsigned evidence block and is covered by the signature only through the seal's decisionDerived.evidenceRef.digest = "sha256:" + JCS(evidence). A recipient MUST verify each receipt's signature and that its evidence recomputes to that signed digest; a seal whose binding fails contributes no class and the gate fails closed. A recipient that reads maxClass raw, without recomputing the binding, can be made to permit an irreversible action whose class an agent relabeled into a permitted one while the record signature, which never covered the evidence, still verifies. The gate is also a membership test over class labels, not an ordering; this document defines no ordering over classes, and a recipient MUST NOT infer one.

The cage block (Section 6.8.1) is an assertion by the issuer, bound by the issuer's signature. confirmed true is not an attestation by the cage, the kernel, or the hardware: a compromised issuer can sign a block that claims confinement it did not have, and a process can be confined in ways the issuer cannot see. A consumer that needs confinement established independently of the issuer needs evidence from outside it, such as a hardware attestation of the platform. Bases differ in strength. "hypervisor_present" shows that a virtual machine is underneath and not which one or how it is configured, and a mandatory access control label shows that a profile is attached and not what the profile allows. configDigest names the declared configuration; it does not show that the declared configuration is the one in force.

11. Privacy Considerations

A receipt is built to be handed to parties outside the issuer, so whatever it carries in clear travels with it. The signed blocks carry identifiers (iss, sub, aud, taskId), times, a decision, and an optional free-text reason. Evidence records defined by profiles carry more: the engine decision profile (Section 6.8) carries the agent identifier, the tool name, the tenant, and the reason. A producer SHOULD treat sub, agent and tenant identifiers, and reason text as potentially personal data where the subject or the operator is a natural person, and SHOULD keep personal data out of reason.

The format keeps the action's inputs and results out of the receipt by design. Arguments and results enter only as commitments (Section 3.7, Section 6.4), and the evidence record is bound by digest, so a receipt can be shared while the evidence stays with the operator. A commitment over a small or predictable value can be reversed by guessing; the dictionary-attack paragraph in Section 10 applies to every commitment in this document, not only to arguments.

Receipts are durable and have no expiry. A receipt that has left the issuer cannot be withdrawn, and its signature keeps verifying. Producers subject to erasure obligations should keep erasable data in evidence records held by the operator, where deleting the record leaves the receipt verifiable and the evidence unrecoverable from it. Timestamp anchors disclose to the time-stamping authority that a receipt existed at a time; the blinded methods (Section 5) keep the authority's log from being matched to published receipts.

12. Regulatory Applicability

This section is informative. It states which element of the receipt carries what a named legal or standards text asks for, and which public conformance suite in [VAARA-REPO] exercises that element. It does not assert that a deployment holding receipts complies with any text. Compliance is a property of the deployment and of its legal reading; the receipt is evidence a reader can recompute. Every suite named below ships a checker that imports no issuer code (Section 7).

The mapping covers Union law first because that is where the format is deployed. Other regimes with an equivalent logging obligation map onto the same rows and are not enumerated.

[AIACT] Art. 12(1): Automatic recording of events over the lifetime of a high-risk system.
The decision record and the execution receipt that answers it (Section 3, Section 3.7), one pair per action. Suites: execution_receipt_v0, decision_pairing_v0.
[AIACT] Art. 12(1), read with Art. 19 and Art. 26(6): Records that stay verifiable across a retention period measured in years, held by the provider and by the deployer.
Signature over canonical bytes (Section 2) with the signing key identified in the envelope, so a record verifies after the issuer rotates keys; the regulator package export. Suites: key_rotation_v0, article12_fold_v0.
[AIACT] Art. 12(1): A record of events, which a reader can only rely on if it can tell a missing record from an event that did not occur.
Gap-evident contiguity over a declared coverage boundary, checkable from the held receipts and the issuer's public key alone. Suites: contiguity_v0.
[AIACT] Art. 14: Human oversight, including the ability to intervene and override.
The disposition of a decision: who produced the allow, deny or escalate, so that a record cannot overstate human involvement. Suites: decision_disposition_v0.
[AIACT] Art. 13: Operation transparent enough for deployers to interpret output.
The one-page audit summary rendered from a record set: verdict, counts, findings, with pinned bytes. Suites: audit_summary_v0, record_set_v0.
[eIDAS] Art. 41 and 42: A qualified electronic time stamp enjoys a presumption of accuracy of the date and time it indicates.
An RFC 3161 token from a qualified trust service over the record's canonical bytes: the rfc3161-eidas-qualified anchor on a decision receipt (Section 5) and existenceProof on an execution receipt (Section 3.6). Suites: qualified_time_v0, which exercises existenceProof.
[GDPR] Art. 5(1)(c): Data minimisation.
Evidence enters the receipt by content digest, never by value (Section 4); the record proves what was decided on without carrying it. Suites: evidence_ref_v0.
[GDPR] Chapter V: Transfers of personal data to third countries.
A signed data-locality record binding one action's transfer facts to the decision that ran, optionally with a region attestation from a party other than the issuer. Suites: data_locality_v0.
[DORA-RTS] Art. 12: Logging that is protected against unauthorised alteration and whose clocks are synchronised.
Hash chain and signature over canonical bytes; the external time anchor as the clock the issuer does not control. Suites: transparency_consistency_v0, qualified_time_v0.
[PLD] Art. 9: Disclosure of relevant evidence at the claimant's request, in an accessible and understandable form.
A receipt recomputable by the claimant's expert from the bytes, with no access to the producer's systems. Suites: record_conformance_v0, article12_fold_v0.
[ISO42001] Annex A, event logging control: Recording of AI system event logs.
The same decision and receipt pair; the summary page is the management-system artefact. Suites: execution_receipt_v0, audit_summary_v0.

Two limits apply to every row. First, a receipt records what its issuer observed at signing time; the revocation and key-status limits in Section 10 hold regardless of which obligation the record is read against, and a suite (revocation_freshness_v0) pins what a clean answer may claim. Second, the rows name obligations on the operator of a system, and the receipt is the operator's evidence; the format places no obligation on a verifier beyond recomputation.

14. IANA Considerations

This document has no IANA actions. The timestamp anchor method registry (Section 5) and the profile registry (Section 6.1) are maintained by the specification, not by IANA, in this version.

15. Normative References

[FIPS180-4]
National Institute of Standards and Technology, "Secure Hash Standard (SHS)", FIPS PUB 180-4, , <https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf>.
[FIPS204]
National Institute of Standards and Technology, "Module-Lattice-Based Digital Signature Standard", FIPS PUB 204, , <https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.pdf>.
[RFC2119]
Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, , <https://www.rfc-editor.org/info/rfc2119>.
[RFC3161]
Adams, C., Cain, P., Pinkas, D., and R. Zuccherato, "Internet X.509 Public Key Infrastructure Time-Stamp Protocol (TSP)", RFC 3161, DOI 10.17487/RFC3161, , <https://www.rfc-editor.org/info/rfc3161>.
[RFC3339]
Klyne, G. and C. Newman, "Date and Time on the Internet: Timestamps", RFC 3339, DOI 10.17487/RFC3339, , <https://www.rfc-editor.org/info/rfc3339>.
[RFC6962]
Laurie, B., Langley, A., and E. Kasper, "Certificate Transparency", RFC 6962, DOI 10.17487/RFC6962, , <https://www.rfc-editor.org/info/rfc6962>.
[RFC7518]
Jones, M., "JSON Web Algorithms (JWA)", RFC 7518, DOI 10.17487/RFC7518, , <https://www.rfc-editor.org/info/rfc7518>.
[RFC8174]
Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, , <https://www.rfc-editor.org/info/rfc8174>.
[RFC8610]
Birkholz, H., Vigano, C., and C. Bormann, "Concise Data Definition Language (CDDL): A Notational Convention to Express Concise Binary Object Representation (CBOR) and JSON Data Structures", RFC 8610, DOI 10.17487/RFC8610, , <https://www.rfc-editor.org/info/rfc8610>.
[RFC8785]
Rundgren, A., Jordan, B., and S. Erdtman, "JSON Canonicalization Scheme (JCS)", RFC 8785, DOI 10.17487/RFC8785, , <https://www.rfc-editor.org/info/rfc8785>.

16. Informative References

[ACTA-RECEIPTS]
Farley, T., "Signed Decision Receipts for Machine-to-Machine Access Control", Work in Progress, Internet-Draft, draft-farley-acta-signed-receipts, , <https://datatracker.ietf.org/doc/draft-farley-acta-signed-receipts/>.
[AGENT-ACTION-RECEIPTS]
Sahu, N., "Signed, Hash-Chained Action Receipts for AI Agents", Work in Progress, Internet-Draft, draft-sahu-agent-action-receipts, , <https://datatracker.ietf.org/doc/draft-sahu-agent-action-receipts/>.
[AGENTROA]
Michalak, J., "Agent Route Origin Authorization (AgentROA): A Cryptographic Policy Enforcement Framework for AI Agent Actions", Work in Progress, Internet-Draft, draft-nivalto-agentroa-route-authorization, , <https://datatracker.ietf.org/doc/draft-nivalto-agentroa-route-authorization/>.
[AIACT]
European Parliament and Council, "Regulation (EU) 2024/1689 laying down harmonised rules on artificial intelligence (Artificial Intelligence Act)", , <https://eur-lex.europa.eu/eli/reg/2024/1689/oj>.
[AISVS2026]
OWASP Foundation, "OWASP AI Security Verification Standard (AISVS) 1.0, Chapter 9: Orchestration and Agentic Action", , <https://github.com/OWASP/AISVS/blob/main/1.0/en/0x10-C09-Orchestration-and-Agentic-Action.md>.
[AMD-SNP-ABI]
Advanced Micro Devices, "SEV Secure Nested Paging Firmware ABI Specification", AMD Publication 56860, Revision 1.58, , <https://docs.amd.com/v/u/en-US/56860>.
[AMD-VCEK]
Advanced Micro Devices, "Versioned Chip Endorsement Key (VCEK) Certificate and KDS Interface Specification", AMD Publication 57230, <https://docs.amd.com/v/u/en-US/57230>.
[ASQAV-COMPLIANCE]
Marques, J., "Compliance Profile of Signed Action Receipts for AI Agents", Work in Progress, Internet-Draft, draft-marques-asqav-compliance-receipts, , <https://datatracker.ietf.org/doc/draft-marques-asqav-compliance-receipts/>.
[AUDIT-ARCH]
Kuehlewind, M. and H. Birkholz, "An Architecture for Auditing AI Agent Delegation and Interactions", Work in Progress, Internet-Draft, draft-kuehlewind-audit-architecture, , <https://datatracker.ietf.org/doc/draft-kuehlewind-audit-architecture/>.
[DORA-RTS]
European Commission, "Commission Delegated Regulation (EU) 2024/1774 supplementing Regulation (EU) 2022/2554 with regard to regulatory technical standards specifying ICT risk management tools, methods, processes, and policies", , <https://eur-lex.europa.eu/eli/reg_del/2024/1774/oj>.
[eIDAS]
European Parliament and Council, "Regulation (EU) No 910/2014 on electronic identification and trust services for electronic transactions in the internal market (eIDAS)", , <https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:32014R0910>.
[GDPR]
European Parliament and Council, "Regulation (EU) 2016/679 on the protection of natural persons with regard to the processing of personal data (General Data Protection Regulation)", , <https://eur-lex.europa.eu/eli/reg/2016/679/oj>.
[He2026SAB]
He, J., "Sovereign Assurance Boundary: Certificate-Bound Admission for Agentic Infrastructure", arXiv 2606.11632, , <https://arxiv.org/abs/2606.11632>.
[He2026SEB]
He, J., "Sovereign Execution Broker: Enforcing Certificate-Bound Authority in Agentic Control Planes", arXiv 2606.20520, , <https://arxiv.org/abs/2606.20520>.
[I-D.ietf-rats-ear]
Fossati, T. and S. Frost, "Attestation Results for Secure Interactions", Work in Progress, Internet-Draft, draft-ietf-rats-ear, , <https://datatracker.ietf.org/doc/draft-ietf-rats-ear/>.
[I-D.ietf-scitt-scrapi]
Birkholz, H., Geater, J., and A. Delignat-Lavaud, "Supply Chain Integrity, Transparency, and Trust (SCITT) Reference APIs", Work in Progress, Internet-Draft, draft-ietf-scitt-scrapi-11, , <https://datatracker.ietf.org/doc/draft-ietf-scitt-scrapi/>.
[ISO42001]
ISO/IEC, "ISO/IEC 42001:2023, Information technology, Artificial intelligence, Management system", , <https://www.iso.org/standard/42001>.
[PLD]
European Parliament and Council, "Directive (EU) 2024/2853 on liability for defective products", , <https://eur-lex.europa.eu/eli/dir/2024/2853/oj>.
[RFC7942]
Sheffer, Y. and A. Farrel, "Improving Awareness of Running Code: The Implementation Status Section", BCP 205, RFC 7942, DOI 10.17487/RFC7942, , <https://www.rfc-editor.org/info/rfc7942>.
[RFC8792]
Watsen, K., Auerswald, E., Farrel, A., and Q. Wu, "Handling Long Lines in Content of Internet-Drafts and RFCs", RFC 8792, DOI 10.17487/RFC8792, , <https://www.rfc-editor.org/info/rfc8792>.
[RFC9162]
Laurie, B., Messeri, E., and R. Stradling, "Certificate Transparency Version 2.0", RFC 9162, DOI 10.17487/RFC9162, , <https://www.rfc-editor.org/info/rfc9162>.
[RFC9334]
Birkholz, H., Thaler, D., Richardson, M., Smith, N., and W. Pan, "Remote ATtestation procedureS (RATS) Architecture", RFC 9334, DOI 10.17487/RFC9334, , <https://www.rfc-editor.org/info/rfc9334>.
[RFC9943]
Birkholz, H., Delignat-Lavaud, A., Fournet, C., Deshpande, Y., and S. Lasker, "An Architecture for Trustworthy and Transparent Digital Supply Chains", RFC 9943, DOI 10.17487/RFC9943, , <https://www.rfc-editor.org/info/rfc9943>.
[Salfeld2026]
Salfeld-Nebgen, J., "Governing Actions, Not Agents: Institutional Attestation as a Governance Model for Autonomous AI Systems", arXiv 2606.26298, , <https://arxiv.org/abs/2606.26298>.
[Uchibeke2026]
Uchibeke, U., "Before the Tool Call: Deterministic Pre-Action Authorization for Autonomous AI Agents", arXiv 2603.20953, , <https://arxiv.org/abs/2603.20953>.
[VAARA-REPO]
Vaara, "Vaara Receipt Specification (vaara.receipt/v1) and conformance vectors", , <https://github.com/vaaraio/vaara/tree/35e3d6c5ae21f322a230e63c4f104adb3d3b0494>.
[VCP]
Kamimura, T., "A SCITT Profile for Verifiable Audit Trails in Algorithmic Trading: The VeritasChain Protocol (VCP)", Work in Progress, Internet-Draft, draft-kamimura-scitt-vcp, , <https://datatracker.ietf.org/doc/draft-kamimura-scitt-vcp/>.

Appendix A. Envelope Schema (CDDL)

This appendix is normative. It describes the JSON encoding of a receipt (Section 3) in CDDL. Maps are closed: a member not named here is not allowed, which is the rule of Section 3. A reference implementation validates every positive receipt in its published conformance vectors against this schema.

<CODE BEGINS>
; vaara.receipt/v1 envelope, JSON encoding.
; Maps are closed: a member not named here is not allowed.
; Rules CDDL cannot state are in the prose: runningCount is
; seq + 1, the issuer block alg equals the envelope alg, and
; the classical part of sigSuite equals alg.

receipt = decision-receipt / execution-receipt

decision-receipt = {
  version: 1,
  alg: alg,
  backLink: back-link,
  decisionDerived: decision-derived,
  issuerAsserted: decision-issuer-block,
  signature: hex,
  ? timestampAnchors: [* anchor],
}

execution-receipt = {
  version: 1,
  alg: alg,
  backLink: back-link,
  outcomeDerived: outcome-derived,
  receiptAsserted: issuer-block,
  signature: hex,
  ? pqSignature: pq-signature,
  ? existenceProof: existence-proof,
}

alg = "ES256" / "RS256" / "HS256"
hex = tstr .regexp "[0-9a-f]+"
digest = tstr .regexp "sha256:[0-9a-f]{64}"
nonempty = tstr .regexp ".+"
date-time = tstr .regexp "[0-9-]{10}T[0-9:]{8}([.][0-9]+)?Z"
decimal = tstr .regexp "-?[0-9]+([.][0-9]+)?"

back-link = {
  attestationDigest: digest,
  attestationNonce: nonempty,
  ? fallbackProjection: nonempty,
}

issuer-block = {
  issuer-members,
  ? sigSuite: "ES256+ML-DSA-65" / "RS256+ML-DSA-65",
}

; A decision receipt has no pqSignature, so its issuer block
; names no sigSuite (SPEC.md 2.5).
decision-issuer-block = {
  issuer-members,
}

issuer-members = (
  iss: tstr,
  sub: tstr,
  iat: date-time,
  nonce: tstr,
  alg: alg,
  secretVersion: tstr,
  ? aud: nonempty,
  ? taskId: nonempty,
  ? completeness: completeness,
  ? cryptoPosture: crypto-posture,
)

completeness = {
  boundaryId: nonempty,
  seq: uint,
  runningCount: uint,
}

crypto-posture = {
  assetType: "algorithm",
  nistQuantumSecurityLevel: 0..5,
  algorithms: [+ crypto-algorithm],
}

crypto-algorithm = {
  algorithm: nonempty,
  primitive: nonempty,
  nistQuantumSecurityLevel: 0..5,
}

decision-derived = {
  decision: "allow" / "block" / "escalate",
  decidedAt: date-time,
  ? reason: tstr,
  ? policyId: tstr,
  ? riskScore: decimal,
  ? thresholdAllow: decimal,
  ? thresholdBlock: decimal,
  ? clientTurnId: tstr,
  ? evidenceRef: evidence-ref,
  ? rationale: rationale,
  ? binding: binding,
  ? decisionProof: { * tstr => any },
}

evidence-ref = {
  canonicalization: "jcs-rfc8785" / "JCS" / "jcs-json-v1",
  digest: digest,
  schema: nonempty,
  ? ref: nonempty,
}

rationale = {
  rule: tstr,
  reason: tstr,
  declaredIntent: tstr,
  ? intentSatisfied: bool,
}

binding = {
  policyDigest: digest,
  intentDigest: digest,
  inputsDigest: digest,
  bindingDigest: digest,
}

outcome-derived = {
  status: "executed" / "refused" / "errored",
  completedAt: date-time,
  ? resultCommitment: projection-commitment / reference-commitment,
  ? decisionDigest: digest,
}

projection-commitment = {
  projection: tstr,
  projectionDigest: digest,
}

reference-commitment = {
  ref: tstr,
  digest: digest,
  canonicalization: "jcs",
}

pq-signature = {
  alg: "ML-DSA-65",
  keyid: nonempty,
  sig: hex,
}

existence-proof = {
  backend: "rfc3161-eidas-qualified",
  hashAlgorithm: "sha256",
  recordDigest: digest,
  token: nonempty,
}

anchor = rfc3161-anchor / blinded-anchor / log-anchor / other-anchor

rfc3161-anchor = {
  method: "rfc3161" / "rfc3161-eidas-qualified",
  anchoredDigest: digest,
  token: nonempty,
  ? authority: tstr,
}

blinded-anchor = {
  method: "rfc3161-blinded" / "rfc3161-eidas-qualified-blinded",
  anchoredDigest: digest,
  token: nonempty,
  anchorSalt: tstr .regexp "[0-9a-f]{64}",
  ? authority: tstr,
}

log-anchor = {
  method: "scitt",
  anchoredDigest: digest,
  logId: nonempty,
  leafIndex: uint,
  treeSize: uint,
  inclusionProof: [* tstr],
  rootHash: nonempty,
  ? authority: tstr,
}

; A method this document does not define: carried, never
; treated as verified. CDDL cannot say "any method name but
; the three above", so this alternative also admits a
; registered name with members missing; the prose rule that
; a registered method keeps its own shape is checked by the
; verifier, not by this schema.
other-anchor = {
  method: tstr,
  anchoredDigest: digest,
  * tstr => any,
}

<CODE ENDS>

Appendix B. Cage Drivers and Bases in Use

This appendix is informative. It lists the driver and basis values a reference implementation emits at the time of writing. No value here is normative, and either list can grow without a revision of this document.

Table 11: Driver values and the basis each can confirm on
driver What it starts the agent in basis when confirmed
vaara-cage An AppArmor profile with a cgroup and a file access guard apparmor_label
openshell NVIDIA OpenShell seccomp_filter
codex The OpenAI Codex sandbox (bubblewrap, Landlock and seccomp on Linux) seccomp_filter
sandbox-runtime Anthropic sandbox-runtime (bubblewrap on Linux) bwrap_init
nono nono (Landlock with a seccomp baseline) seccomp_filter, no_new_privs
gvisor gVisor (a user-space kernel) gvisor_kernel_log
agent-sandbox Kubernetes SIG agent-sandbox (gVisor or Kata) gvisor_kernel_log, hypervisor_present
kata Kata Containers (one lightweight VM per container) hypervisor_present
firecracker Firecracker (a microVM) hypervisor_present
microsandbox microsandbox (libkrun microVM) hypervisor_present
e2b E2B, self-hosted (Firecracker microVM) hypervisor_present
apple-container Apple container (one lightweight VM per container) hypervisor_present
Table 12: Basis values
basis The fact that was read
none Nothing; no cage was declared.
declared Nothing beyond the launcher's declaration.
apparmor_label The process carries the cage's AppArmor label.
seccomp_filter A seccomp filter is attached and no_new_privs is set.
no_new_privs no_new_privs is set, which Landlock requires.
bwrap_init Process 1 of the process's PID namespace is bubblewrap.
gvisor_kernel_log The kernel log is the one gVisor writes.
hypervisor_present The CPU reports a hypervisor underneath.

Author's Address

Henri Sirkkavaara
Vaara