SCITT S. Mih Internet-Draft Action State Group, Inc. Intended status: Standards Track Y. Zhang Expires: 4 May 2027 Independent 31 October 2026 AAC Evidence Bundle draft-mih-zhang-agent-disclosure-bundle-02 Abstract This document defines the AAC Evidence Bundle, a portable presentation and verification container for an Agent Action Capsule and the records that make its evidentiary claim intelligible. A permalink carries a bundle in its URL fragment, an offline HTML report carries a bundle in its shell, and a hosted report serves a bundle at its URL. The bundle does not alter any enclosed Capsule. It declares its citation closure and any missing cited records, carries verified disclosure preimages as a bundle-level overlay, separates three different completeness claims, can carry the producer's signed declaration of what it offers in each category of evidence, and permits independently specified extension blocks and countersignatures: signatures by a party other than the producer over the bundle digest, each accompanied by a statement of which claims that party recomputed and with what result. 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 4 May 2027. Copyright Notice Copyright (c) 2026 IETF Trust and the persons identified as the document authors. All rights reserved. Mih & Zhang Expires 4 May 2027 [Page 1] Internet-Draft AAC Evidence Bundle October 2026 This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/ license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License. Table of Contents 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 3 2. Conventions and Definitions . . . . . . . . . . . . . . . . . 3 3. Evidence Bundle Object . . . . . . . . . . . . . . . . . . . 4 3.1. Empty-History Bundles . . . . . . . . . . . . . . . . . . 6 4. Citation Closure . . . . . . . . . . . . . . . . . . . . . . 6 5. Bundle-Level Disclosures . . . . . . . . . . . . . . . . . . 7 6. Completeness Claims and Log Membership . . . . . . . . . . . 8 6.1. Certificate Modes . . . . . . . . . . . . . . . . . . . . 9 6.2. Producer-Selected Certificates . . . . . . . . . . . . . 10 6.3. Non-Record Leaves . . . . . . . . . . . . . . . . . . . . 11 7. Category Coverage . . . . . . . . . . . . . . . . . . . . . . 13 7.1. Statuses . . . . . . . . . . . . . . . . . . . . . . . . 14 7.2. Signature . . . . . . . . . . . . . . . . . . . . . . . . 15 7.3. Verifier Properties . . . . . . . . . . . . . . . . . . . 15 8. Typed Extensions . . . . . . . . . . . . . . . . . . . . . . 17 8.1. The producer-key/v1 Extension . . . . . . . . . . . . . . 17 8.2. The composed/v1 Extension . . . . . . . . . . . . . . . . 18 8.2.1. Block . . . . . . . . . . . . . . . . . . . . . . . . 19 8.2.2. Members and Outcomes . . . . . . . . . . . . . . . . 21 8.2.3. Composition Closure . . . . . . . . . . . . . . . . . 22 8.2.4. Controller Binding Records . . . . . . . . . . . . . 23 8.2.5. Joins . . . . . . . . . . . . . . . . . . . . . . . . 26 8.2.6. Observers and Redundancy . . . . . . . . . . . . . . 28 8.2.7. Composed Digest . . . . . . . . . . . . . . . . . . . 29 8.2.8. Verifying composed/v1 . . . . . . . . . . . . . . . . 30 8.3. Provisional Extension Kinds . . . . . . . . . . . . . . . 31 9. Bundle Digest and Countersignatures . . . . . . . . . . . . . 31 9.1. The countersign/v1 Entry . . . . . . . . . . . . . . . . 32 9.2. Verifying a countersign/v1 Entry . . . . . . . . . . . . 34 9.3. Self-Countersignature . . . . . . . . . . . . . . . . . . 34 10. Fragment Codec . . . . . . . . . . . . . . . . . . . . . . . 35 11. Verification . . . . . . . . . . . . . . . . . . . . . . . . 35 12. Security Considerations . . . . . . . . . . . . . . . . . . . 35 12.1. composed/v1 . . . . . . . . . . . . . . . . . . . . . . 36 12.2. Category Coverage . . . . . . . . . . . . . . . . . . . 37 13. Privacy Considerations . . . . . . . . . . . . . . . . . . . 37 14. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 38 Mih & Zhang Expires 4 May 2027 [Page 2] Internet-Draft AAC Evidence Bundle October 2026 15. References . . . . . . . . . . . . . . . . . . . . . . . . . 39 15.1. Normative References . . . . . . . . . . . . . . . . . . 39 15.2. Informative References . . . . . . . . . . . . . . . . . 41 Change Log . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . 43 Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 43 1. Introduction A Capsule proves the identity and claimed content of one action. An audit report normally needs more: the report Capsule, its chain of judgments or adjudications, the turns cited by those records, selected disclosed preimages, and the log evidence that supports a claim about coverage. Passing these items as unrelated files produces a presentation that a verifier cannot describe precisely. The AAC Evidence Bundle is that unit of evidence. It is deliberately a presentation-layer object: the Capsules in records retain their original bytes, identities, signatures, and registrations. The same bundle can be encoded in a URL fragment, embedded in an offline HTML shell, or obtained from a hosted report URL. These are transports for one object, not distinct evidence formats. 2. Conventions and Definitions 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. Bundle: An AAC Evidence Bundle as defined in Section 3. Root Capsule: The Capsule identified by the Bundle's root member. The Bundle's evidence claim is made from this Capsule outward through its declared closure. JSON-DIGEST: The lowercase-hex SHA-256 digest of UTF8(JCS(value)), using [RFC8785] over the whole recursively canonicalized JSON value with no member filtering, as defined by [I-D.mih-scitt-agent-action-capsule]. Countersignature: A countersignature is a signature by a party other than the producer over a bundle digest, accompanied by a statement of which claims that party recomputed and with what result. A report is a bundle. Countersigner: The party that makes a countersignature. A Mih & Zhang Expires 4 May 2027 [Page 3] Internet-Draft AAC Evidence Bundle October 2026 countersigner works in the manner of an Auditor [RFC9943]: it independently recomputes checks over a Bundle it was given and signs a statement of the results -- a list of what it recomputed, never an opinion. A countersigner MAY register that statement as a Signed Statement with a Transparency Service, in which case the entry carries the Receipt; the Receipt proves that the statement is in that log and says nothing about the Bundle. Which producers a countersigner accepts Bundles from is its own admission rule, outside this document. Self-countersignature: An entry in countersignatures whose signer key is the producer's key (Section 9.3). It is well-formed and is rendered as not independent. countersignatures is a member name. An entry is a statement by a party other than the producer that it recomputed named checks over the bundle digest, in the manner of an Auditor [RFC9943]. It is not a COSE countersignature [RFC9338], not a Receipt [RFC9942], and not a Transparency Service function. WITHHELD: The disclosure state of an eligible member absent from the Bundle-level disclosure overlay. It is neither an empty value nor a verification failure. The terms "Capsule", "capsule_id", chain.parent_capsule_id, references, seq, leaf_index, and log_coordinates are as defined in [I-D.mih-scitt-agent-action-capsule]. 3. Evidence Bundle Object A Bundle is a JSON [RFC8259] object with this shape. Ellipses denote values defined by this document or a registered extension; they do not authorize untyped replacement formats. Mih & Zhang Expires 4 May 2027 [Page 4] Internet-Draft AAC Evidence Bundle October 2026 { "bundle_version": "2", "bundle_kind": "evidence-bundle/v2", "root": "", "records": [ ... ], "completeness": { "closure_depth": 2, "records_mode": "complete|declared_incomplete", "payloads_mode": "all|selected|none", "suppressed_fields": [ ... ], "missing": [ "", ... ], "selection": "producer-selected" }, "disclosures": { "": { "": "" } }, "disclosure_record": "", "completeness_certificate": { ... }, "checkpoint": { ... }, "category_coverage": { ... }, "verification": { ... }, "extensions": { "": { ... } }, "countersignatures": [ ... ] } bundle_version and bundle_kind are REQUIRED and MUST be respectively "2" and "evidence-bundle/v2". root, records, and completeness are REQUIRED, except that an empty-history Bundle (Section 3.1) has no root. root is the lowercase-hex capsule_id of one record in records. Every records element MUST be an unmodified Capsule object conforming to [I-D.mih-scitt-agent-action-capsule]; duplicate capsule_id values are not permitted. All other members shown are OPTIONAL unless a claim in this document requires them. A receiver MUST reject an object with an unknown bundle_version or bundle_kind as an AAC Evidence Bundle, rather than silently applying version-2 verification rules. payloads_mode states whether the producer included all payload material it chose to carry (all), only a selected subset (selected), or none (none). A Bundle whose payloads_mode is none carries no disclosures member. selection, when present, names the certificate mode of completeness_certificate (Section 6.1). suppressed_fields names fields intentionally not carried by the Bundle; it does not turn an absent disclosure into an empty value or a failure. Mih & Zhang Expires 4 May 2027 [Page 5] Internet-Draft AAC Evidence Bundle October 2026 3.1. Empty-History Bundles An _empty-history Bundle_ shows that a log stream has no history to disclose. A stream that was never started and a history that was cleared read the same. Clearing a history starts a new stream, with a new log_id, under the same key. It never rewrites or truncates the old stream's log, and a checkpoint that does so is inconsistent with that log's earlier checkpoints. An empty-history Bundle has an empty records array and no root member. root MUST be absent exactly when records is empty. In an empty-history Bundle: * completeness.records_mode MUST be complete, completeness.missing MUST be absent or empty, and completeness.payloads_mode MUST be none; * completeness_certificate, disclosures and disclosure_record MUST be absent; * checkpoint, with checkpoint.cose, SHOULD be present when the stream has a checkpoint: its first checkpoint, or its latest one while it still holds no record. A stream that was never started has none. A Bundle with no root that is not a well-formed empty-history Bundle is malformed. A verifier reports a well-formed empty-history Bundle as _no history_. It is well formed: a verifier MUST NOT report it as failed, and MUST NOT report it as an absence (Section 8.2.2). Of its claims (Section 6), graph closure passes, since there is nothing to close, and interval coverage and per-record membership are not established, with the finding no_records. When checkpoint.cose verifies, the verifier reports the checkpoint's signed timestamp with the result, as no history since that time. Otherwise it reports no history without a date. 4. Citation Closure Citation closure is declared, not assumed. Starting at root, a producer MUST traverse chain.parent_capsule_id and every references[].digest transitively through completeness.closure_depth edges. The default depth is 2 when the member is absent: report to judgments or adjudications, then to turns. A producer using a different depth MUST state that non-negative JSON integer explicitly. Mih & Zhang Expires 4 May 2027 [Page 6] Internet-Draft AAC Evidence Bundle October 2026 For each target reached within that depth, the Bundle MUST either supply the cited Capsule in records with a matching identity or list its digest once in completeness.missing. A target MUST NOT be silently dropped. records_mode MUST be complete exactly when missing is absent or empty, and MUST be declared_incomplete exactly when it is non-empty. A verifier MUST report the latter as declared incomplete, not as complete and not as an unexplained failure. A supplied record whose computed capsule_id does not match the chain target or reference digest is not supplied evidence for that target. The closure declaration says nothing about records beyond its stated depth. A verifier MUST report the depth it applied and MUST NOT infer unbounded ancestry or citation completeness from the presence of a short chain. 5. Bundle-Level Disclosures disclosures is a Bundle-level overlay keyed first by the enclosed Capsule's capsule_id, then by the disclosure member name: "disclosures": { "": { "agent_input": { ... }, "agent_output": { ... } } } It has the same eligibility and DE-3 digest rule as the per-Capsule Disclosure Envelope in [I-D.mih-agent-disclosure-envelope]. The member name selects that draft's registered committed-digest path in the specified Capsule. For every disclosed member, a verifier MUST compute JSON-DIGEST(revealed preimage) and compare it to the committed digest at that registered path in that records element. A match is REVEALED; a mismatch is a failed verification of that disclosed content. A member absent from this overlay is WITHHELD, never blank and never failed. The overlay is carried once per Bundle rather than by wrapping each Capsule in {capsule, disclosures}. It MUST NOT alter an enclosed Capsule or its capsule_id. An overlay key not naming a supplied record, or a member not eligible under the Disclosure Envelope registry, is a disclosure finding and MUST NOT be treated as a successful revelation. disclosure_record, when present, identifies the Capsule that records the act of sealing or issuing these disclosures; it is evidence about that act and does not replace the DE-3 check. Mih & Zhang Expires 4 May 2027 [Page 7] Internet-Draft AAC Evidence Bundle October 2026 6. Completeness Claims and Log Membership completeness_certificate and checkpoint, when supplied, support three separate claims. A verifier MUST report each claim independently. The composed/v1 extension adds a fourth claim, composition closure (Section 8.2.3), which is reported separately from these three. 1. *Graph closure*: every citation reached under Section 4 is supplied with matching identity or explicitly listed in completeness.missing. 2. *Interval coverage*: the claimed sequence interval is bound to a checkpointed range root. Without a verified Receipt [RFC9942] over the checkpoint from a Transparency Service, or a verified checkpoint signature, this is only relative to a producer- asserted checkpoint. 3. *Per-record membership*: every supplied record is bound to its claimed log position under that range root, and, for a range, every other leaf in the interval is accounted for (Section 6.3). Per-record membership is the claim a range certificate makes about the records in its interval: interval coverage binds the leaf values, and per-record membership says what each leaf is. A verifier MUST ignore members of completeness_certificate that this document does not define; they MUST NOT change any result it reports. The certificate MUST state its log_id, range root, first and last seq, and the proof material that binds that range root to checkpoint. A signed range proof that binds only the first and last record proves endpoint inclusion only: an interior record can be deleted or replaced while such a proof still passes. A verifier MUST NOT report whole-range completeness from endpoint inclusion alone. A verifier MUST verify an included Receipt [RFC9942] over the checkpoint, or the checkpoint signature, before reporting interval coverage or per- record membership as independently verified. Otherwise it MUST explicitly label those claims checkpoint_unverified and describe them as relative to a producer-asserted checkpoint. The portable checkpoint signature member is checkpoint.cose, an unpadded base64url CLL COSE checkpoint. A verifier that implements this member MUST verify it and require its log identifier, MMR size, and root to equal the certificate and checkpoint values before removing the qualifier. For the third claim, every supplied record MUST either carry a membership entry within the declared interval or be explicitly listed in completeness.missing. A membership entry or record whose seq is outside the interval MUST be rejected. Each membership entry MUST carry log_coordinates stating its claimed position and an inclusion Mih & Zhang Expires 4 May 2027 [Page 8] Internet-Draft AAC Evidence Bundle October 2026 proof to the certificate's range root. The base profile's terms apply exactly: seq is the 1-based log position and leaf_index = seq - 1 is the zero-based MMR index. log_coordinates states which index is used. The verifier MUST verify every inclusion proof at its stated leaf_index, require the proof's leaf_index to equal that coordinate and its size to equal checkpoint.mmr_size, and bind the record to the range root; it MUST NOT substitute an endpoint proof for a missing per-record proof. A record without a valid proof may remain usable for graph closure but does not satisfy per-record membership. 6.1. Certificate Modes completeness.selection names the mode in which completeness_certificate is read: * *Absent* (the Bundle has no selection member): a range certificate, as described above. Its interval ends at the checkpoint's last leaf. * *producer-selected*: a producer-selected certificate (Section 6.2). This document defines no other value. A verifier that meets a selection value it does not implement, including a value that is not a string (null among them), MUST report interval coverage and per- record membership as not established (finding certificate_mode_unsupported). It MUST NOT report either claim as failed because of the mode, MUST NOT read the certificate under another mode, and MUST NOT report the Bundle as invalid on that ground. Graph closure, disclosures, extensions and countersignatures are unaffected. The same rule applies to a verifier that predates a mode: a verifier that does not implement producer-selected certificates reports such a Bundle's interval coverage and per-record membership as not established, never as failed. A Bundle in a mode the verifier lacks is unverified in that respect; it is not evidence of tampering, and reporting it as invalid would make an honest Bundle indistinguishable from an altered one. The selection member is the producer's to write, and so is any edit to a Bundle after it is made: setting an unknown mode can turn a failing claim into one that is not established, but never into one that is established (Section 12). Mih & Zhang Expires 4 May 2027 [Page 9] Internet-Draft AAC Evidence Bundle October 2026 6.2. Producer-Selected Certificates A producer-selected Bundle carries records that its producer chose from a log, each proven on its own, and makes no claim about the records between them. Its completeness.selection is producer- selected. Its certificate carries log_id, range_root and memberships. It carries no range: first_seq, last_seq, body_digests and range_proof are not part of it, and a verifier does not read them. It MUST NOT carry non_record_leaves (Section 6.3). "completeness": { "closure_depth": 0, "records_mode": "complete", "payloads_mode": "none", "suppressed_fields": [], "missing": [], "selection": "producer-selected" }, "completeness_certificate": { "log_id": "", "range_root": "", "memberships": { "": { "log_coordinates": { ... }, "inclusion_proof": { ... } } } } A verifier that implements this mode: * reports interval coverage as not established (finding selection_not_checkable): there is no interval; * verifies per-record membership record by record. range_root MUST equal the checkpoint's root, and the certificate's log_id the checkpoint's log_id. Each record's membership entry MUST carry log_coordinates naming the checkpoint's log_id, a seq of at least 1 that no other entry claims, and leaf_index = seq - 1, and an inclusion proof at that index whose size equals checkpoint.mmr_size and that binds the record's capsule_id to the root. A membership entry for a record the Bundle does not carry is a failure. Otherwise the rules of Section 6 apply, including the checkpoint_unverified label; * reports a certificate that carries non_record_leaves as invalid. When checkpoint.cose does not verify, or a stated value (including the certificate's log_id) contradicts it, the checkpoint anchors no record: the verifier reports per-record membership as not established, labelled checkpoint_unverified, except that a certificate that carries non_record_leaves still fails it. Mih & Zhang Expires 4 May 2027 [Page 10] Internet-Draft AAC Evidence Bundle October 2026 A producer-selected Bundle is therefore never complete as to its log: a verifier MUST NOT report it as such, and its best result is that every carried record is a member of the checkpointed log. A changed record or proof fails per-record membership exactly as in a range Bundle. Graph closure, which is about citations, not log positions, is unaffected by the mode. 6.3. Non-Record Leaves A log can hold leaves that are not records. The Evidence Layer [I-D.mih-agent-evidence-layer] reserves the record_type value padding for records a store appends so that a checkpoint's size falls on a bucket boundary (its Section 12.1). A store that pads before every checkpoint usually has a padding leaf at the checkpoint's last leaf, so a range ending there always covers one. A range certificate covers such leaves in its member non_record_leaves, which carries each one in full: "non_record_leaves": [ { "seq": 6, "content": { "capsule_id": "<64 hex>", "record_type": "padding", "epistemic_type": "producer_claim", "store_nonce": "<64 hex>" } } ] non_record_leaves is an array. Each element is an object with seq, the leaf's 1-based log position within [first_seq, last_seq], and content, the leaf's content. A digest alone is not accepted in place of content: a bare leaf value could be the identifier of a Capsule that the Bundle thereby hides. Members of an element other than seq and content are ignored. *The padding leaf.* This document defines one non-record leaf type, padding. The members of a padding record are those of [I-D.mih-agent-evidence-layer] Section 12.1: record_type padding, epistemic_type producer_claim, and store_nonce, 32 bytes as 64 lowercase hexadecimal characters. That document fixes the members but not their serialization or the record's identifier, so this document states both for a padding leaf in a Bundle. Its content is a JSON object with exactly four members: those three and capsule_id. capsule_id is 64 lowercase hexadecimal characters, and is the JSON- DIGEST (Section 2) of the object formed by the other three members. The leaf value is capsule_id. A store's local-only producer envelope (signature, key_id) is not part of content. (Moving this rule into the Evidence Layer awaits a later revision of that document.) *Checking an element.* A verifier reads the elements in order. For each one: Mih & Zhang Expires 4 May 2027 [Page 11] Internet-Draft AAC Evidence Bundle October 2026 1. An element that is not an object is malformed (finding non_record_leaf_element_invalid). 2. A seq that is not an integer within [first_seq, last_seq], that any membership entry states in its log_coordinates (whether or not that entry is otherwise valid), or that is the seq of an earlier element, is invalid (finding non_record_leaf_seq_invalid); the element accounts for no position. 3. Otherwise the element accounts for its seq. Then: * when content is not an object, or its record_type is not a string, the element is malformed (finding non_record_leaf_malformed); * when record_type is not padding, the leaf is of a type this document does not define (finding non_record_leaf_type_unsupported), and the verifier checks nothing further about it; * when the padding content does not have exactly the four members above, each in the form above, with epistemic_type equal to producer_claim, it is malformed (finding non_record_leaf_malformed); * the verifier recomputes the leaf value from the other three members and requires it to equal both content.capsule_id and body_digests[seq - first_seq]; otherwise the leaf does not match (finding non_record_leaf_mismatch). A non_record_leaves value that is not an array is malformed (finding non_record_leaves_malformed) and accounts for no position. *Per-position accounting.* For per-record membership over a range, every seq in [first_seq, last_seq] MUST be accounted for by exactly one of a record's membership entry and a non_record_leaves element. Each position is then: * *verified*: a record's verified membership, or a padding leaf that recomputes to its body digest; * *unsupported*: a leaf of a type the verifier does not implement; or * *unaccounted*: neither, or an element that failed a check above (finding membership_record_missing for a position with neither). Mih & Zhang Expires 4 May 2027 [Page 12] Internet-Draft AAC Evidence Bundle October 2026 Any failure fails per-record membership, whatever else is unsupported. When nothing fails and some position is unsupported, per-record membership is not established: the verifier MUST NOT report it as established, and MUST NOT report it as failed. Otherwise the rules of Section 6 apply. A verifier that implements this member therefore no longer rejects a range because it contains padding records, as [I-D.mih-agent-evidence-layer] Section 12.1 requires. A verifier that does not implement the member ignores it, as it ignores any member it does not know, and then reports every padding position as missing, which fails per-record membership. A producer therefore SHOULD NOT emit non_record_leaves to readers that do not implement this revision; until it can, a producer-selected certificate states what it can prove without it. A non-record leaf is not a record. It never appears in records, never counts as a record for graph closure, disclosures or any count a verifier reports, and is never the target of a citation. Leaves other than padding, such as a store's checkpoint stamps, are not covered by this document. A range over a log that contains one is reported, at best, as not established through non_record_leaf_type_unsupported; a producer that needs a Bundle over such a log without that result uses a producer-selected certificate. 7. Category Coverage category_coverage, when present, is the producer's signed declaration of what it offers in each category of a named category set: for each category, exactly one status. It answers the categories field of an Evidence Request ([I-D.mih-agent-evidence-request]), and a producer MAY include it without one. *It declares; it does not prove.* A verifier checks that it is well formed, who signed it, and whether it is consistent with what the Bundle carries. It never establishes that the producer offers everything it declares, or that nothing exists in a category declared absent. "category_coverage": { "set": "", "categories": { "": { "status": "AVAILABLE" }, "": { "status": "UNDISCLOSED", "policy_uri": "" } }, "request_digest": "<64 hex>", "signer": { "key_id": "<64 hex>" }, "signature": "<128 hex>" } Mih & Zhang Expires 4 May 2027 [Page 13] Internet-Draft AAC Evidence Bundle October 2026 set is REQUIRED, a non-empty string naming a category set (Section 14). A set whose identifier begins x- is private: it is not registered, and a verifier never treats it as known. categories is REQUIRED, a non-empty object keyed by category name; each value is an object with status and, where required, policy_uri. request_digest, OPTIONAL, is the digest of the Evidence Request this declaration answers, computed as [I-D.mih-agent-evidence-request] computes a request digest, in lowercase hexadecimal. signer and signature are OPTIONAL, and present together or not at all. Members not defined here are ignored: they never make the member malformed, and a signature covers them. The member is part of the bundle digest (Section 9), so a countersignature binds it. 7.1. Statuses Each category has exactly one status, written in upper case: +=============+=====================================================+ | status | Meaning | +=============+=====================================================+ | AVAILABLE | evidence in this category is offered | +-------------+-----------------------------------------------------+ | PARTIAL | only some evidence in this category | | | is offered | +-------------+-----------------------------------------------------+ | WITHHELD | evidence in this category may exist | | | and is not released to this requester | +-------------+-----------------------------------------------------+ | DELETED | evidence in this category was | | | destroyed or has expired | +-------------+-----------------------------------------------------+ | ABSENT | the producer states that it holds | | | nothing in this category | +-------------+-----------------------------------------------------+ | UNDISCLOSED | the producer does not state which of | | | the other statuses applies, under the | | | policy policy_uri names | +-------------+-----------------------------------------------------+ Table 1 AVAILABLE, PARTIAL, WITHHELD and DELETED are retention states of the Evidence Layer [I-D.mih-agent-evidence-layer], with the same meanings, applied to a category rather than to one record's payload. This document defines UNDISCLOSED and ABSENT. ABSENT is the producer's asserted absence in the Evidence Layer's sense ("Three Mih & Zhang Expires 4 May 2027 [Page 14] Internet-Draft AAC Evidence Bundle October 2026 Kinds of No"): its own unproven claim about its own store, never a non-membership proof and never the requester's recorded absence of [I-D.mih-agent-evidence-request]. The retention state LEGAL_HOLD is not a status: it changes what may happen to evidence, not what is offered. UNDISCLOSED MUST carry policy_uri, an absolute URI ([RFC3986], Section 4.3) naming the policy under which the status is not disclosed; policy_uri MAY accompany any other status. WITHHELD and UNDISCLOSED are different statements and MUST NOT be conflated: WITHHELD says evidence may exist and is not released; UNDISCLOSED says nothing about whether any exists. 7.2. Signature signer.key_id is a 32-byte Ed25519 [RFC8032] public key as 64 lowercase hexadecimal characters. signature is the Ed25519 signature, as 128 lowercase hexadecimal characters, under that key over the signing input UTF8(JCS({"category_coverage": , "root": })) Including root binds the declaration to the root record of the Bundle it was made for: a signed declaration copied into a Bundle with another root does not verify. It does not bind the rest of the Bundle; a Bundle with the same root and other records carries it unchanged, and only the bundle digest (Section 9) tells the two Bundles apart. The signature attributes the declaration to the holder of the key. It does not establish who that holder is; a verifier MAY compare signer.key_id with the producer's keys (Section 9.3) and report the result. 7.3. Verifier Properties A verifier that implements this member reports the following properties, each as exactly one of PASS, FAIL, NOT_PRESENT, NOT_CHECKED and INCONCLUSIVE, as the definition of each property below assigns them. A Bundle without the member has no category properties. category_coverage_form: PASS when the member is as described above, including a policy_uri for every UNDISCLOSED status; otherwise FAIL. When it is FAIL, every other property is NOT_CHECKED. category_coverage_signature: NOT_PRESENT when the member carries no Mih & Zhang Expires 4 May 2027 [Page 15] Internet-Draft AAC Evidence Bundle October 2026 signature; PASS when the signature verifies; FAIL otherwise, including when the signing input has no JCS serialization (for example, a number JCS cannot represent). category_coverage_set_registered: NOT_PRESENT for a private (x-) set; INCONCLUSIVE when the verifier does not know the set; FAIL when it knows the set and a declared category is not one of its names; PASS otherwise. category_coverage_request: NOT_CHECKED when the verifier does not have the Evidence Request; otherwise FAIL when request_digest is present and is not that request's digest, computed over its octets before they are parsed; otherwise NOT_CHECKED when the request cannot be read, or its categories field is malformed ([I-D.mih-agent-evidence-request]); NOT_PRESENT when the request has no categories field; FAIL when the request names another set, or a requested category has no entry; PASS otherwise. category_coverage_consistency: NOT_CHECKED when the verifier cannot assign every record the Bundle carries to a category, or to none (the set's definition says how): a record it cannot assign could be in any category; FAIL when a record the Bundle carries belongs to a category declared ABSENT or WITHHELD; PASS otherwise. A record in a DELETED or UNDISCLOSED category is not a contradiction, and an AVAILABLE category with no record in the Bundle is not one either: the Bundle may cover less than the producer offers. Each property stands alone. A verifier MUST report them separately and MUST NOT combine them, or the statuses, into a count, a percentage, a score or a claim of completeness. It MUST NOT report a PASS of every property as proof that the producer offered everything it holds. A FAIL of category_coverage_form, category_coverage_signature or category_coverage_consistency is a failed check of the Bundle; the other properties are reported and change no other result. Category coverage is reported apart from the completeness claims of Section 6 and changes none of them. A verifier that does not implement this member follows the rule for any member it does not know: it reports nothing about it, and the member stays covered by the bundle digest. Mih & Zhang Expires 4 May 2027 [Page 16] Internet-Draft AAC Evidence Bundle October 2026 8. Typed Extensions extensions, when present, is an object keyed by a registered Evidence Bundle extension kind. The member name declares the kind and its value is that kind's block. The extension kind registry is Specification Required. A registered specification defines its block shape and any semantic checks. For example, a company-side row model such as report/v1 is permitted only as such an extension; this neutral core does not define, parse, or own its rows. Extensions are included in the bundle digest (Section 9). A verifier that does not implement a registered extension kind MUST preserve its integrity status as digest-covered, report the block as uninterpreted, and MUST NOT apply that block's semantics. An unknown kind MUST NOT alter the core Capsule, closure, disclosure, or membership checks. 8.1. The producer-key/v1 Extension The producer-key/v1 extension kind declares the key of the producer that assembled the Bundle: "extensions": { "producer-key/v1": { "public_key": "<64 lowercase hex>" } } public_key is the producer's 32-byte Ed25519 [RFC8032] public key as 64 lowercase hexadecimal characters. The block carries one key. A producer MUST NOT add other members to the block, and a verifier MUST ignore any it finds. Like every extension, the block is covered by the bundle digest, so a countersignature's over binds the declaration, and adding, removing, or changing the declaration afterwards makes that entry invalid. A verifier that implements this kind uses public_key for one purpose only: it adds the key to the producer's keys when determining independence (Section 9.3), so that a countersign/v1 entry whose signer.key_id equals it is reported as not independent. The declaration can only cause an entry to be reported as not independent. It MUST NOT cause any entry to be reported as independent, resolved, or valid, and it MUST NOT change any other result. It is not a claim of identity or of authority, and a verifier MUST NOT present it as one. The absence of this extension says nothing about whether any entry is independent. Mih & Zhang Expires 4 May 2027 [Page 17] Internet-Draft AAC Evidence Bundle October 2026 The block is malformed when it is not an object, or when public_key is absent, is not a string, or is not exactly 64 lowercase hexadecimal characters. A verifier MUST ignore a malformed block when determining independence, MUST NOT fail the Bundle or any claim because of it, and still treats the block as digest-covered. 8.2. The composed/v1 Extension The composed/v1 extension kind carries an evidence set built from the answers of several responders as one portable object. Each responder answered one Evidence Request ([I-D.mih-agent-evidence-request]) with exactly one of three outcomes: * an artifact, here an Evidence Bundle; * a signed refusal; * a recorded absence. Each answer is a _member_ of the composition. The block declares: * each member's digest and outcome; * the observer that produced each member; * the joins between members; * a _composed digest_ that a judgment or other record can cite as the exact evidence set it was made from. The containing Bundle is an ordinary evidence-bundle/v2. Its root is the composing party's own record, and its core checks apply unchanged. The extension adds a set of member bundles alongside that record; it does not change what records, root or completeness mean. Mih & Zhang Expires 4 May 2027 [Page 18] Internet-Draft AAC Evidence Bundle October 2026 "extensions": { "composed/v1": { "members": [ { "id": "", "observer": "", "request_digest": "<64 hex>", "outcome": "artifact", "digest": "<64 hex>", "bundle": { ... } }, { "id": "", "observer": "", "request_digest": "<64 hex>", "outcome": "refusal", "digest": "<64 hex>", "refusal": { ... } } ], "observers": [ { "id": "", "role": "", "custody_domain": "