<?xml version="1.0" encoding="UTF-8"?>
<rfc xmlns:xi="http://www.w3.org/2001/XInclude"
     ipr="trust200902"
     category="info"
     submissionType="independent"
     docName="draft-elkhatabi-verifiable-telemetry-ledgers-10"
     version="3">
  <front>
    <title abbrev="VTL">Verifiable Telemetry Ledgers</title>
    <seriesInfo name="Internet-Draft" value="draft-elkhatabi-verifiable-telemetry-ledgers-10"/>
    <author fullname="Bilal El Khatabi" initials="B." surname="El Khatabi">
      <organization>Independent</organization>
      <address>
        <postal>
          <country>Morocco</country>
        </postal>
        <email>elkhatabibilal@gmail.com</email>
      </address>
    </author>
    <date year="2026" month="August" day="26"/>

    <area>Informational</area>
    <workgroup>Independent Submission</workgroup>
    <keyword>telemetry</keyword>
    <keyword>merkle</keyword>
    <keyword>timestamping</keyword>
    <keyword>iot</keyword>

    <abstract>
      <t>
        This document profiles a verifiable-telemetry ledger. Its interoperability boundary begins
        with exact canonical-record byte strings that an upstream system has
        already produced. The profile fixes admission and assignment of those
        byte strings to serial-numbered segments, deterministic commitment-tree
        calculation, an authoritative segment artifact encoded in Concise
        Binary Object Representation (CBOR), a producer manifest, three
        disclosure classes, and binding of the authoritative segment artifact
        digest to timestamp artifacts under the RFC 3161 profile.
        Transport framing, decryption, anti-replay processing, payload
        interpretation, and source-telemetry-to-record mapping are outside this
        profile. Segment closure uses a deployment-configured elapsed-time
        interval and does not depend on calendar dates from either the source
        or the ledger producer.
        Every baseline producer uses RFC 3161 timestamping, as
        updated by RFC 5816 and profiled by this document, for every emitted
        segment. Alternative timestamping and attestation mechanisms are
        outside this profile and require a separate specification.
      </t>
      <t>
        The profile enables independent recomputation and audit of disclosed
        evidence from the admitted canonical-record bytes onward. It does not
        verify how source telemetry was authenticated, interpreted, or mapped
        to those bytes, and it does not cover device onboarding, end-to-end
        security of sensor values, or safety decisions.
      </t>
    </abstract>
  </front>

  <middle>
    <section numbered="true" toc="include" anchor="introduction">
      <name>Introduction</name>
      <t>
        Verifiable Telemetry Ledgers (VTL) support long-lived telemetry
        deployments that need evidence that record bytes disclosed later are
        the same bytes a ledger producer committed when they were admitted,
        even when upstream delivery is intermittent and verification happens
        later.
      </t>
      <t>
        Two trust questions must be distinguished. The first is whether a
        source was genuine, authorized, and mapped correctly. The second is
        whether, after exact record bytes were selected for commitment, a later
        verifier can determine that those bytes, the ledger artifact, and
        timestamp artifacts are mutually consistent. This profile standardizes the second
        question.
      </t>
      <t>
        This memo is an Independent Submission. It is not an Internet
        Standard and has not been evaluated as having IETF community
        consensus.
      </t>
      <t><strong>Protocol at a Glance</strong></t>
      <t>
        The following informative summary provides a reading path through the
        normative requirements that follow:
      </t>
      <ol>
        <li>Admission. The ledger producer validates the byte-level
        profile and admits the unchanged canonical-record bytes into the
        logical interval open at the admission linearization point. Each
        admission is one record occurrence, including when two admitted
        occurrences have identical bytes.</li>
        <li>Commitment. The producer computes each leaf as
        <tt>SHA-256(0x00 || record)</tt>, sorts the leaf hashes, and calculates
        <tt>segment_root</tt> over the complete sorted list using the
        domain-separated tree construction in <xref target="merkle-policy"/>.
        It partitions the same list into aligned batch subtrees. The
        authoritative segment artifact carries those subtree roots, and their
        RFC 9162 tree composition reproduces <tt>segment_root</tt>.</li>
        <li>Sealing. The producer encodes the authoritative segment
        artifact using deterministic CBOR. The artifact carries the commitment
        profile identifier, ledger and segment identity, closure claim,
        predecessor-artifact digest, record count, batch-subtree roots, and
        segment root.</li>
        <li>Timestamp artifacts. The producer computes SHA-256 over the
        exact authoritative segment artifact bytes and submits that digest
        using <xref target="RFC3161"/> for every emitted segment.</li>
        <li>Verification. A verifier starts from the authoritative
        segment artifact and performs the validations supported by the disclosed
        bundle. Class A supports public record-level recomputation. Class B
        supports controlled audit when some record material is withheld. Class
        C provides segment-level commitment and timestamp artifacts without
        record preimages and does not support opening batch contents. The verifier reports the exercised scope, segment-chain
        status, TSA channel status, and overall outcome; it claims validated chain
        adjacency only when the predecessor artifact is disclosed.</li>
      </ol>
      <t>
        Segment intervals are ledger batching rules, not source-reporting
        periods or civil-time claims. The producer assigns each admitted
        record to the logical interval open at its admission linearization
        point and uses a non-decreasing elapsed-time source for interval
        closure. Source arrival time, upstream processing time,
        <tt>ingest_time</tt>, <tt>device_time</tt>, and UTC do not select
        segment membership. Segment identity is
        <tt>(ledger_id, segment_number)</tt>, and a sealed segment is not
        reopened. <xref target="segment-formation"/> specifies boundary
        ordering, empty intervals, size-triggered closure, policy changes, and
        recovery behavior.
      </t>
      <figure anchor="arch-flow">
        <name>Evidence Path and Interoperability Boundary</name>
        <artwork type="ascii-art"><![CDATA[

Source telemetry
      |
      v
+----------------------------+       OUTSIDE THIS PROFILE
| Upstream admission system  |
| auth / replay / projection |
+----------------------------+
      | exact canonical-record bytes
======|================================================ boundary
      v
+----------------------------+ --> authoritative segment
| Ledger producer            |     artifact ----------> Verifier
| admit / assign / commit    | --> artifact digest
| seal / chain               |          |
+----------------------------+          +--> timestamp artifacts
]]></artwork>
      </figure>
      <t>
        The boundary is admission of an already-formed canonical-record byte
        string. From that point, the ledger producer is responsible for
        byte preservation, segment assignment, durable state, artifact
        construction, and timestamp submission. Verification establishes
        consistency of disclosed post-admission evidence, not source
        authenticity, dataset completeness, or physical truth.
      </t>
      <t><strong>Document Roadmap.</strong> <xref target="terminology"/> and
        <xref target="roles"/> define the common terminology and system roles.
        The producer implementation path continues with <xref target="data-model"/>,
        <xref target="artifacts"/>, <xref target="anchoring-verification"/>,
        <xref target="versioning"/>, and <xref target="conformance-vectors"/>.
        The verifier implementation path additionally includes
        <xref target="disclosure-bundles"/> and Appendices A through C.
        The operator path additionally includes <xref target="operations"/> and
        <xref target="security"/>.
      </t>

      <section numbered="true" toc="include" anchor="relationship-ietf-work">
        <name>Relationship to Existing Work</name>
        <t>
          VTL reuses the Merkle Tree Hash construction from
          <xref target="RFC9162"/> to commit a producer-local segment, but it
          does not define a Certificate Transparency log or protocol. In
          particular, VTL defines no transparency service, public append-only
          log, statement-registration protocol, receipt, inclusion proof,
          consistency proof, gossip protocol, or log-auditing API.
        </t>
        <t>
          Unlike Certificate Transparency, VTL commits to a multiset rather
          than an append-ordered sequence: it sorts leaf hashes before tree
          reduction. The resulting root is independent of admission order and
          cannot support append-order, prefix, or consistency claims between
          partial snapshots. Chaining orders sealed segment artifacts, not
          records within a segment.
        </t>
        <t>
          The SCITT architecture in <xref target="RFC9943"/> defines signed
          statements, registration with transparency services, verifiable data
          structures, and receipts. Those services and claims are outside the
          VTL baseline. A separate specification can publish a VTL artifact or
          bundle through SCITT, but doing so does not replace or alter the VTL
          commitment and verification rules.
        </t>
        <t>
          <xref target="RFC9052"/> defines COSE signing and encryption
          structures. VTL does not use a COSE object as its authoritative
          segment artifact and does not require a COSE producer signature.
          A deployment can wrap or publish VTL artifacts using COSE under a
          separate profile without changing the bytes committed by VTL.
        </t>
      </section>

    </section>

    <section numbered="true" toc="include" anchor="terminology">
      <name>Conventions and Terminology</name>
      <t>
        The key words "<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>",
        "<bcp14>REQUIRED</bcp14>", "<bcp14>SHALL</bcp14>",
        "<bcp14>SHALL NOT</bcp14>", "<bcp14>SHOULD</bcp14>",
        "<bcp14>SHOULD NOT</bcp14>", "<bcp14>RECOMMENDED</bcp14>",
        "<bcp14>NOT RECOMMENDED</bcp14>", "<bcp14>MAY</bcp14>", and
        "<bcp14>OPTIONAL</bcp14>" in this document are to be interpreted as
        described in BCP 14 <xref target="RFC2119"/> <xref target="RFC8174"/>
        when, and only when, they appear in all capitals, as shown here.
      </t>
      <t>Terms:</t>
      <ul>
        <li>Upstream admission system: A component outside this profile that authenticates, filters, decrypts, de-duplicates, interprets, or maps source telemetry and produces a canonical-record byte string. It can be colocated with the ledger producer.</li>
        <li>Canonical-record byte string: The exact deterministic-CBOR byte string presented at the interoperability boundary and admitted as one commitment input. "Canonical" describes its byte-level encoding under the commitment profile; it does not assert physical truth or correct derivation from source telemetry.</li>
        <li>Commitment profile: One immutable set of normative rules for validating canonical-record byte strings and deterministically constructing and verifying commitment outputs. These rules include canonical-record syntax and encoding constraints, hash and Merkle tree construction, leaf ordering and occurrence handling, deterministic batching, authoritative segment artifact construction and chaining, and the applicable recomputation semantics.</li>
        <li>Commitment profile identifier (<tt>commitment_profile_id</tt>): The opaque text value that selects exactly one commitment profile. This document defines one profile, informally named "VTL Canonical CBOR", and assigns it the UUIDv4 <tt>c08ade4e-1785-4eb6-9648-b7003d76288d</tt> under <xref target="RFC9562"/>. The identifier uses the RFC 9562 lowercase hex-and-dash representation; the informal name is descriptive and is not an identifier. Normative identifier handling is specified in <xref target="versioning"/>.</li>
        <li>Ledger: One ordered chain of authoritative segment artifacts identified by a 128-bit <tt>ledger_id</tt> generated so that collisions are negligible, rendered as 32 lowercase hexadecimal characters. Segment serial numbers are scoped to this identifier.</li>
        <li>Ledger epoch: The lifetime of one ledger sequence under a single <tt>ledger_id</tt>. The epoch segment is segment zero and carries the zero predecessor value.</li>
        <li>Segment: The multiset of admitted canonical-record byte strings assigned to one emitted ledger interval. Depending on <tt>empty_mode</tt>, a segment can be empty. Segment membership is selected by the admission linearization point and a non-decreasing elapsed-time close rule, not by record timestamps.</li>
        <li>Authoritative segment artifact: The deterministic-CBOR record for one emitted segment and the cryptographic source of truth for verification. The producer manifest member <tt>artifacts.segment_cbor</tt> references the exact bytes of this object and does not name a separate protocol object. Its storage path and filename are not protocol fields.</li>
        <li>Segment closure policy: The committed policy snapshot containing its version, interval, batch limit, optional record and size limits, and empty mode. It is a configuration claim and does not establish that the producer observed the claimed elapsed duration.</li>
        <li>Authoritative: Designates the exact canonical-record byte strings and authoritative segment artifact that this document treats as cryptographic sources of truth; see <xref target="artifacts"/> and <xref target="verify"/>.</li>
        <li>Projection: A non-authoritative representation (for example JSON) derived from an authoritative segment artifact.</li>
        <li>Producer manifest: A non-authoritative JSON object supplied by the producer that claims a disclosure class and identifies disclosed artifacts, their digests, and the producer timestamp state.</li>
        <li>Verifier result: The verifier-authored output that reports the exercised scope, any segment-chain conclusion, TSA channel status, overall outcome, and failure reasons when verification fails. It reports externally meaningful conclusions rather than an implementation trace. It is not a commitment input or a producer claim.</li>
        <li>Batch subtree: A consecutive slice of the globally sorted segment leaf list, bounded by the committed power-of-two <tt>batch_record_limit</tt>. Its root is an aligned subtree of the segment Merkle tree and is commitment material, not a storage-layout convention.</li>
        <li>Batch opening: A producer-manifest entry that discloses every canonical-record occurrence committed by one batch subtree. It permits a verifier to recompute that indexed subtree root without disclosing other batches.</li>
        <li>Timestamp artifacts: The timestamp response and any disclosed request associated with validation of the authoritative segment artifact digest against the timestamp token.</li>
        <li>Timestamp Authority (TSA): An authority operating under <xref target="RFC3161"/> that issues timestamp responses.</li>
        <li><tt>TimeStampResp</tt>: The <xref target="RFC3161"/> protocol response containing status information and, on success, a timestamp token. This document also calls it the timestamp response.</li>
        <li>Timestamp token: The signed CMS object carried inside a successful timestamp response.</li>
        <li>Verification scope: The disclosure level and claim boundaries that a verifier actually exercised and asserts in a verifier result.</li>
        <li>Admission linearization point: The serialization point in the ledger producer's processing at which one exact canonical-record byte string is accepted as a commitment input and assigned to the currently open segment; it is not a wall-clock instant. Normative serialization requirements are specified in <xref target="segment-formation"/>.</li>
        <li>Disclosure class: The level of artifact disclosure associated with a verification claim.</li>
      </ul>
      <t>
        The following JSON excerpt is illustrative; the authoritative segment
        artifact is CBOR and contains additional required fields:
      </t>
      <sourcecode type="json"><![CDATA[
{
  "commitment_profile_id": "c08ade4e-1785-4eb6-9648-b7003d76288d",
  "ledger_id": "0123456789abcdef0123456789abcdef",
  "segment_number": 42
}
]]></sourcecode>
      <t>
        The profile identifier has that same fixed value wherever this
        document carries the field. <tt>ledger_id</tt> and
        <tt>segment_number</tt> identify a particular ledger and segment and
        therefore vary.
      </t>
    </section>

      <section numbered="true" toc="include" anchor="roles">
        <name>System Roles</name>
      <t>
        The roles below participate at different sides of the profile boundary.
        Baseline producer and verifier conformance is defined in
        <xref target="baseline-conformance"/>.
      </t>
      <ul>
        <li>Upstream admission system: Produces canonical-record byte strings after applying deployment-specific source validation and mapping. This role is outside the profile.</li>
        <li>Ledger producer: Accepts exact canonical-record byte strings at the profile boundary, assigns them to serial-numbered segments, constructs authoritative segment artifacts, and submits their digests for timestamping. A physical gateway can implement both the upstream and ledger-producer roles, but conformance under this document begins only at the byte-level handoff.</li>
        <li>Verifier: Recomputes commitments and validates timestamp artifacts from disclosed bundles.</li>
        <li>Timestamp Authority (TSA): Issues timestamp responses over authoritative segment artifact digests for every emitted segment.</li>
      </ul>
    </section>

    <section numbered="true" toc="include" anchor="data-model">
      <name>Data and Commitment Model</name>
      <t>
        The normative input to this section is an exact canonical-record byte
        string that has already been produced by an upstream admission system.
        The interoperable core begins at that byte-level handoff and covers
        record admission, segment assignment, deterministic hashing and tree
        calculation, authoritative segment artifacts, disclosure, and verification. No
        source transport, decryption, anti-replay, payload interpretation, or
        source-to-record projection is defined by this document.
      </t>

      <section numbered="true" toc="include" anchor="canonical-record-input">
        <name>Canonical-Record Input Boundary</name>
        <t>
          The protocol input defined by this document is one exact
          canonical-record byte string. The byte string <bcp14>MUST</bcp14> encode exactly one
          CBOR data item using the record shape below and the deterministic
          encoding constraints in <xref target="cbor-profile"/>. A ledger
          producer <bcp14>MUST</bcp14> reject a proposed input that does not satisfy those
          byte-level constraints.
        </t>
        <t>
          A baseline producer <bcp14>MUST</bcp14> accept every conforming canonical-record
          byte string whose total encoded length is no greater than 4096
          octets. A producer <bcp14>MAY</bcp14> accept larger conforming records under its
          documented resource policy. A configured maximum below 4096 octets
          does not satisfy baseline producer conformance. The 4096-octet
          value is a shared minimum acceptance capability that permits
          bounded-resource implementations; it is not derived from a network
          MTU and is not a protocol maximum or a default deployment limit.
        </t>
        <t>
          A larger byte string remains in this commitment profile when it
          otherwise conforms. An implementation <bcp14>MAY</bcp14> receive or validate such
          a byte string incrementally, but admission still applies to one
          complete byte string encoding exactly one canonical record. An
          upstream system <bcp14>MAY</bcp14> instead produce multiple independently
          conforming canonical records, but each is a separate admitted
          occurrence. This profile does not treat such records as transparent
          chunks of one canonical record or define their reassembly semantics.
        </t>
        <t>
          Once admitted, the exact supplied octets are authoritative. The
          ledger producer <bcp14>MUST</bcp14> use those octets, without modification, as the
          leaf preimage under <xref target="merkle-policy"/>. It <bcp14>MUST NOT</bcp14> decode
          and re-encode, normalize, enrich, remove, reorder, or otherwise
          substitute a different byte string for commitment. Each admission
          event contributes one record occurrence, including when two admitted
          occurrences have identical byte strings.
        </t>
        <t>
          Source transport, framing, authentication, decryption, anti-replay
          processing, duplicate-submission policy, device-identifier mapping,
          message-type mapping, payload interpretation, and construction of the
          canonical-record byte string are upstream of this boundary and are
          not specified or verified here. A physical gateway <bcp14>MAY</bcp14> perform those
          functions and ledger production in one implementation, but its
          interoperability claim under this document begins only with the exact
          byte string passed across this logical boundary.
        </t>
        <t>
          Under the commitment profile defined by this document, each
          canonical-record byte string encodes the following fixed
          seven-element CBOR array:
        </t>
        <sourcecode type="cddl"><![CDATA[
canonical-record = [
  version: 1,
  device_id: bstr .size 8,
  fc: uint,
  ingest_time: uint,
  device_time: uint / nil,
  kind: uint,
  payload: restricted-cbor-item
]

restricted-cbor-item =
  int / bstr / tstr / bool / nil / finite-float /
  [* restricted-cbor-item] /
  { * tstr => restricted-cbor-item }

finite-float = float ; Finite only; deterministic rules follow.
]]></sourcecode>
        <t>
          The positional labels are conventional names for inspecting disclosed
          records; they do not move source-to-record mapping into this profile.
          Their byte-level requirements are:
        </t>
        <ul>
          <li><tt>version</tt> is the unsigned integer <tt>1</tt>.</li>
          <li><tt>device_id</tt> is an opaque 8-octet identifier assigned upstream. This document defines no mapping from a transport or deployment alias to this value.</li>
          <li><tt>fc</tt> is an unsigned upstream-supplied sequence value. This document defines no replay or duplicate-suppression semantics for it.</li>
          <li><tt>ingest_time</tt> is an unsigned count of whole non-leap seconds since <tt>1970-01-01T00:00:00Z</tt>. Its assignment and accuracy are upstream responsibilities, and it <bcp14>MUST NOT</bcp14> select segment membership.</li>
          <li><tt>device_time</tt> is an unsigned application timestamp or <tt>null</tt>. Its epoch and unit are upstream semantics, and it <bcp14>MUST NOT</bcp14> select segment membership.</li>
          <li><tt>kind</tt> is an unsigned application discriminator. This document defines no message-type or payload-family mapping for it.</li>
          <li><tt>payload</tt> is one recursively restricted CBOR data item of the type above. Its schema and meaning are outside this profile.</li>
        </ul>
        <t>
          Canonical-record identity is exact-octet identity, not numeric or
          application-level equality. Within <tt>payload</tt>, the integer
          <tt>1</tt> and the floating-point value <tt>1.0</tt> are distinct
          values and have distinct deterministic encodings. Positive
          floating-point zero and negative floating-point zero are also
          distinct: both are finite and permitted, and their shortest exact
          CBOR encodings are respectively <tt>f90000</tt> and
          <tt>f98000</tt>. A producer or verifier <bcp14>MUST NOT</bcp14> normalize negative
          zero to positive zero or convert between an integer and a
          numerically equal floating-point value.
        </t>
        <t>
          A different record array shape or different byte-level field type is
          a different commitment profile and requires a distinct
          <tt>commitment_profile_id</tt>. Application schemas <bcp14>MAY</bcp14> separately
          define the meanings of <tt>device_id</tt>, <tt>fc</tt>,
          <tt>device_time</tt>, <tt>kind</tt>, and <tt>payload</tt>, but
          successful verification under this document does not validate those
          external semantics.
        </t>
        <t>
          Class A recomputation starts with the disclosed canonical-record byte
          strings. It demonstrates that those exact bytes produce the disclosed
          leaf digests, roots, and authoritative segment artifact. It does not
          reconstruct the bytes from source telemetry. Conformance vectors for
          this profile therefore begin with exact canonical-record byte
          strings; transport messages and upstream projection fixtures, if
          supplied, are informative and are not inputs to baseline conformance.
        </t>
      </section>
      <section numbered="true" toc="include" anchor="cbor-profile">
        <name>Deterministic CBOR Commitment Encoding</name>
        <t>
          Commitment bytes <bcp14>MUST</bcp14> satisfy the core deterministic-encoding
          requirements of Section 4.2.1 of <xref target="RFC8949"/>. Items
          <bcp14>MUST</bcp14> use definite-length encoding; integers and finite
          floating-point values <bcp14>MUST</bcp14> use their shortest exact encodings. Map
          keys <bcp14>MUST</bcp14> be ordered in the bytewise lexicographic order of their
          deterministic encodings.
        </t>
        <t>
          Map keys <bcp14>MUST</bcp14> be CBOR text strings. Duplicate map keys and invalid
          UTF-8 text strings <bcp14>MUST</bcp14> be rejected. CBOR tags, NaN, positive
          infinity, and negative infinity <bcp14>MUST NOT</bcp14> appear. Permitted values
          are integers, byte strings, text strings, arrays, maps, booleans,
          null, and finite deterministic floating-point values.
          Negative floating-point zero is finite and is permitted. Exact type,
          sign, and encoded-octet distinctions described in
          <xref target="canonical-record-input"/> are preserved by admission
          and verification.
        </t>
        <t>
          Because this profile permits only text-string map keys and requires
          their preferred deterministic encodings, bytewise ordering of their
          encoded heads first orders them by UTF-8 byte length and then orders
          equal-length keys by their encoded bytes. The resulting order is also
          the length-first order described in Section 4.2.3 of
          <xref target="RFC8949"/>. This coincidence does not replace any other
          core deterministic-encoding requirement in Section 4.2.1.
        </t>
        <t>
          JSON projections are optional and non-authoritative and <bcp14>MUST NOT</bcp14> be
          commitment inputs. Implementations can use
          <xref target="RFC8785"/> when stable JSON projection octets are
          useful. Once a canonical-record byte string is admitted, its exact
          octets <bcp14>MUST</bcp14> be committed without re-encoding.
        </t>
        <t>
          Unless a rule explicitly says otherwise, every digest in this
          document is computed over the exact received or disclosed octets;
          no implementation may re-encode, normalize, or reserialize input
          before hashing.
        </t>
      </section>

      <section numbered="true" toc="include" anchor="merkle-policy">
        <name>Deterministic Commitment Tree Calculation</name>
        <t>
          For a given segment <tt>S</tt>, the current commitment profile
          computes <tt>segment_root</tt> from canonical-record bytes using the
          domain-separated tree shape of Section 2.1.1 of
          <xref target="RFC9162"/>, specialized to SHA-256 and to the multiset
          ordering below. SHA-256 is defined by <xref target="FIPS180-4"/>.
          <xref target="RFC6234"/> provides informative implementation
          descriptions and test material for the SHA family.
        </t>
        <t>
          Every SHA-256 invocation in this profile <bcp14>MUST</bcp14> produce the complete
          32-octet SHA-256 digest; a truncated digest or a different SHA-2
          function is nonconformant. For commitment-tree hashing, an
          implementation <bcp14>MUST</bcp14> use exactly the <tt>0x00</tt> leaf prefix and
          <tt>0x01</tt> internal-node prefix specified below and <bcp14>MUST NOT</bcp14> add,
          omit, or substitute another tree-domain prefix.
        </t>
        <t>
          For each exact canonical-record byte string <tt>record</tt>, compute
          <tt>leaf_hash = SHA-256(0x00 || record)</tt>. Sort the resulting raw
          32-octet leaf hashes in ascending byte order. The authoritative
          artifact represents hash values as CBOR byte strings; hexadecimal
          renderings in this document are for human-readable vectors only.
        </t>
        <t>
          Let <tt>VTLRoot(L)</tt> operate on the sorted list of
          already-computed leaf hashes. <tt>VTLRoot([]) = SHA-256("")</tt> and
          <tt>VTLRoot([x]) = x</tt>. For a list of <tt>n &gt; 1</tt> hashes, let
          <tt>k</tt> be the largest power of two strictly less than <tt>n</tt>,
          and compute
          <tt>VTLRoot(L) = SHA-256(0x01 || VTLRoot(L[0:k]) || VTLRoot(L[k:n]))</tt>.
          Implementations <bcp14>MUST NOT</bcp14> duplicate an unpaired final hash. The
          prefixes <tt>0x00</tt> and <tt>0x01</tt> provide leaf/parent domain
          separation, and the recursive split gives every leaf count a unique
          tree shape.
        </t>
        <t>
          For an emitted empty segment, <tt>record_count</tt> <bcp14>MUST</bcp14> be zero,
          <tt>batch_roots</tt> <bcp14>MUST</bcp14> be an empty array,
          and <tt>segment_root</tt> <bcp14>MUST</bcp14> equal <tt>VTLRoot([])</tt>, the SHA-256 digest of zero bytes:
          <tt>e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855</tt>.
          Its <tt>closure_policy.empty_mode</tt> <bcp14>MUST</bcp14> be <tt>emit</tt>, except
          that a mandatory empty <tt>shutdown</tt> or <tt>recovery</tt>
          lifecycle artifact retains the committed <tt>suppress</tt> value as
          specified in <xref target="segment-formation"/>. Any other empty
          artifact under <tt>suppress</tt> mode is invalid.
          For a non-empty segment, <tt>record_count</tt> <bcp14>MUST</bcp14> be positive and
          <tt>batch_roots</tt> <bcp14>MUST</bcp14> contain at least one root. The resulting <tt>segment_root</tt> is deterministic
          for the multiset of committed canonical records. Because leaf
          digests are sorted before reduction, the root does not commit to
          admission order. Admission order selects segment membership at the
          boundary but is not itself a verifier-visible total-order claim.
          Producer conformance requires sorting the complete segment leaf
          multiset before batching. Verification of that global sort rule is
          complete only under the <tt>public_recompute</tt> scope defined in
          <xref target="verification-inputs-scope"/>; weaker scopes provide
          only the ordering assurances explicitly defined for those scopes.
        </t>
        <t>
          Any future change to this calculation that alters commitment bytes
          <bcp14>MUST</bcp14> use a new
          <tt>commitment_profile_id</tt>.
        </t>
      </section>

      <section numbered="true" toc="include" anchor="segment-formation">
        <name>Segment Formation and Closure</name>
        <t anchor="segment-normal-timing"><em>Normal Interval Timing and Admission</em></t>
        <t>
          Segment formation uses an elapsed-time source maintained by the
          ledger producer. That source <bcp14>MUST</bcp14> be non-decreasing and <bcp14>MUST</bcp14> progress
          during normal operation while an interval is open. Its resolution
          <bcp14>MUST</bcp14> be no coarser than the smaller of 1000 milliseconds and the
          configured <tt>closure_policy.interval_ms</tt> value. Resolution here
          means the greatest quantization step exposed to the boundary logic.
          It constrains comparison granularity, not the precision of the
          underlying clock. A producer <bcp14>MAY</bcp14> sample the elapsed-time source or
          evaluate the boundary more frequently and <bcp14>MAY</bcp14> use a finer-resolution
          source.
          The policy field is a positive uint64 number of milliseconds and
          specifies a fixed elapsed duration.
          It is not a civil-time duration and <bcp14>MUST NOT</bcp14> be aligned by local midnight, UTC
          midnight, time zone, daylight-saving transition, or leap second.
          The first logical interval of an epoch opens when the ledger is
          activated. Activation is the deployment-defined start action by
          which the producer makes the <tt>ledger_id</tt> and initial segment
          state durable before admitting a record. Reactivation resumes that
          durable state after a <tt>shutdown</tt> closure.
          Each normal or early closure other than <tt>shutdown</tt> immediately
          opens the next logical interval. Logical intervals continue across
          idle periods in both empty modes; <tt>suppress</tt> changes artifact
          emission and serial consumption, not the elapsed-time schedule.
        </t>
        <t>
          The producer <bcp14>MUST</bcp14> serialize the interval-boundary transition with the
          admission linearization point so that each admitted input has exactly
          one segment assignment. For an interval whose elapsed-time deadline
          is <tt>T</tt>:
        </t>
        <ul>
          <li>A record whose acceptance linearizes before <tt>T</tt> belongs to the current logical interval.</li>
          <li>At <tt>T</tt> or later, the producer <bcp14>MUST</bcp14> process the boundary before another acceptance can linearize.</li>
          <li>Upstream processing can begin before <tt>T</tt>, but if canonical-record admission linearizes at or after <tt>T</tt>, the record belongs to the next logical interval.</li>
          <li>Source arrival time, upstream validation or record-construction time, <tt>device_time</tt>, and <tt>ingest_time</tt> <bcp14>MUST NOT</bcp14> override this assignment.</li>
        </ul>
        <t>
          The producer <bcp14>MUST</bcp14> determine deadline expiry by checked elapsed-time
          subtraction; it <bcp14>MUST NOT</bcp14> add
          <tt>closure_policy.interval_ms</tt> to an absolute counter in a way
          that can wrap. If elapsed time cannot be represented or compared
          safely, the producer <bcp14>MUST</bcp14> enter the recovery procedure below before
          accepting another record.
        </t>
        <t anchor="segment-policy-changes"><em>Policy Changes and Early Closure</em></t>
        <t>
          The producer snapshots <tt>closure_policy</tt> when a logical interval
          opens. That snapshot <bcp14>MUST</bcp14> remain unchanged through closure. A normal
          configuration update becomes effective for the next logical
          interval. An immediate update <bcp14>MUST</bcp14> first close the current logical
          interval under the old snapshot. It emits an artifact with
          <tt>close_reason</tt> equal to <tt>reconfigure</tt> unless the interval
          is empty under <tt>suppress</tt> mode, in which case it emits no
          artifact and consumes no segment number.
        </t>
        <t>
          Early closure is permitted only for a condition represented by the
          committed <tt>close_reason</tt>. A producer <bcp14>MUST NOT</bcp14> place a record
          whose acceptance linearizes after the interval deadline into the
          expired interval merely because closure processing was late. Late
          closure is an operational fault and <bcp14>SHOULD</bcp14> generate an alarm.
        </t>
        <t>
          A <tt>manual</tt> closure occurs when an operator-initiated action,
          external to the producer's automatic timer and limit evaluation,
          requests immediate closure. A producer <bcp14>MUST NOT</bcp14> use
          <tt>manual</tt> for a closure triggered by its own timer or limit
          evaluation. The producer <bcp14>MUST</bcp14>
          serialize that action with admission, close the current logical
          interval under its existing policy snapshot, and immediately open
          the next logical interval. Artifact emission and serial consumption
          for an empty manual interval follow the committed
          <tt>empty_mode</tt>. A <tt>shutdown</tt> closure occurs when
          the producer closes the current logical interval as part of an
          orderly cessation of ledger operation. It <bcp14>MUST NOT</bcp14> open another
          logical interval until the ledger is reactivated. A shutdown closure
          <bcp14>MUST</bcp14> emit an artifact and consume a segment number even when the
          interval is empty and its committed <tt>empty_mode</tt> is
          <tt>suppress</tt>.
        </t>
        <t anchor="segment-close-reasons"><em>Limits and Close-Reason Selection</em></t>
        <t>
          The <tt>interval</tt> reason applies when the snapshotted
          <tt>interval_ms</tt> elapsed-time deadline expires and no
          higher-precedence close condition applies.
        </t>
        <t>
          <tt>closure_policy.record_limit</tt>, when non-null, is the maximum
          number of admitted records in one logical interval. The interval
          closes immediately after the acceptance that makes the record count
          equal to <tt>record_limit</tt>.
        </t>
        <t>
          <tt>closure_policy.size_limit_bytes</tt>, when non-null, is a close
          threshold for the sum of the lengths of the exact admitted
          canonical-record byte strings. After an acceptance has linearized, if
          the resulting byte total is greater than or equal to
          <tt>size_limit_bytes</tt>, the producer <bcp14>MUST</bcp14> close that logical
          interval before another acceptance can linearize. The triggering
          record remains assigned to the interval because segment assignment is
          final at the admission linearization point. Consequently,
          <tt>size_limit_bytes</tt> is not a hard pre-admission maximum and an
          emitted segment can exceed the threshold by the contribution of its
          final admitted record. If a single record admitted to an empty
          interval exceeds <tt>size_limit_bytes</tt>, that record forms a
          one-record interval, which <bcp14>MUST</bcp14> close before another acceptance can
          linearize. Threshold comparisons and byte-count updates <bcp14>MUST</bcp14> use
          checked arithmetic; the producer <bcp14>MUST</bcp14> enter recovery or stop
          acceptance before acknowledging a record if the new total cannot be
          represented safely.
        </t>
        <t>
          If multiple close conditions are simultaneously true, the committed
          <tt>close_reason</tt> <bcp14>MUST</bcp14> be selected by the following precedence,
          numbered from highest to lowest:
        </t>
        <ol>
          <li><tt>recovery</tt></li>
          <li><tt>shutdown</tt></li>
          <li><tt>reconfigure</tt></li>
          <li><tt>manual</tt></li>
          <li><tt>size_limit</tt></li>
          <li><tt>record_limit</tt></li>
          <li><tt>interval</tt></li>
        </ol>
        <t>
          The selected reason does not change which acceptances already
          linearized into the interval.
        </t>
        <t anchor="segment-empty-intervals"><em>Empty Intervals and Timer Continuity</em></t>
        <t>
          While elapsed-timer continuity is maintained, in <tt>emit</tt> mode
          every logical interval produces an artifact;
          an empty interval uses the empty construction in
          <xref target="merkle-policy"/>. In <tt>suppress</tt> mode, an empty
          logical interval produces no artifact and consumes no segment number,
          except that <tt>shutdown</tt> and <tt>recovery</tt> closures always
          emit the empty construction and consume a segment number.
          The next emitted artifact uses the next contiguous number. A
          suppressed interval makes neither a completeness claim nor a claim
          that no event occurred.
        </t>
        <t>
          Suspend time counts toward <tt>closure_policy.interval_ms</tt> when
          the selected elapsed-time source advances across suspend. If it does
          not, or if its continuity is uncertain, the producer <bcp14>MUST</bcp14> apply the
          recovery procedure before accepting another record.
        </t>
        <t anchor="segment-recovery"><em>Recovery and Durable State</em></t>
        <t>
          After restart or failover, the producer <bcp14>MUST</bcp14> recover the active
          <tt>ledger_id</tt>, next segment number, policy snapshot, and any open
          interval state before accepting more telemetry. If elapsed-time or
          open-interval state is uncertain, the producer <bcp14>MUST NOT</bcp14> infer the
          boundary from a possibly regressed wall clock. It <bcp14>MUST</bcp14> either stop
          acceptance or seal recoverable material with <tt>close_reason</tt>
          equal to <tt>recovery</tt> before accepting into a new interval. A
          recovery closure <bcp14>MUST</bcp14> emit an artifact and consume a segment number
          even when the recoverable interval is empty and its committed
          <tt>empty_mode</tt> is <tt>suppress</tt>. It
          <bcp14>MUST NOT</bcp14> synthesize historical empty artifacts and represent them as
          having been sealed at missed deadlines.
        </t>
        <t>
          The admission linearization point is a durable transaction boundary.
          Before acknowledging acceptance, the producer <bcp14>MUST</bcp14> make the exact
          canonical-record octets, their membership in the open interval, the
          interval record count and byte count, and the corresponding recovery
          state atomically durable or recoverable. After a crash, an acceptance
          <bcp14>MUST</bcp14> be recovered exactly once in the same logical interval, or it
          <bcp14>MUST</bcp14> be treated as never having completed. Segment sealing <bcp14>MUST</bcp14>
          atomically persist the authoritative segment artifact, its digest, the next
          serial allocation, and the new open-interval state before admission
          resumes.
        </t>
        <t>
          These durability requirements specify the observable crash-recovery
          outcome, not a particular operating-system call. An implementation
          can use <tt>fsync()</tt>, a transactional store, replicated durable
          state, or another mechanism only if the required state is durable or
          recoverable before acceptance is acknowledged. Calling
          <tt>fsync()</tt> alone is not sufficient when the surrounding
          storage and transaction design does not provide that outcome.
        </t>
        <t anchor="segment-batch-subtrees"><em>Deterministic Aligned Batch Subtrees</em></t>
        <t>
          In this profile, a batch is not a chronological admission chunk. It
          is a consecutive slice of the complete globally sorted leaf-hash
          list, formed only after segment membership is fixed.
        </t>
        <t>
          For a non-empty interval, compute the complete sorted leaf-hash list
          defined in <xref target="merkle-policy"/>. Partition that list into
          consecutive batches of <tt>B =
          closure_policy.batch_record_limit</tt> hashes. <tt>B</tt> <bcp14>MUST</bcp14> be a
          positive power of two no greater than 2^63. Batch zero contains the
          first <tt>B</tt> hashes, batch one the next <tt>B</tt> hashes, and so
          on; only the last batch can contain fewer than <tt>B</tt> hashes.
          Compute each <tt>batch_roots[i]</tt> as <tt>VTLRoot</tt> over that batch's
          already-computed leaf hashes. This rule is the sole baseline batch
          partitioning rule and is independent of storage flushes, worker
          scheduling, or input-file layout.
        </t>
        <t>
          Requiring a power of two makes every full batch align with a
          recursive <tt>VTLRoot</tt> split. An aligned batch root can therefore
          substitute directly for its subtree when composing
          <tt>segment_root</tt>, without an auxiliary sibling path or a
          storage-dependent tree shape.
        </t>
        <t>
          Let <tt>N</tt> be the segment <tt>record_count</tt>. For <tt>N &gt;
          0</tt>, the number of batch roots <bcp14>MUST</bcp14> be
          <tt>1 + ((N - 1) / B)</tt> using integer division. To compose a range
          root from those aligned batch roots, return the sole supplied root
          when the range contains at most <tt>B</tt> leaves. Otherwise, let
          <tt>k</tt> be the largest power of two strictly less than the range's
          leaf count. Because <tt>B</tt> is a power of two and the range spans
          multiple batches, <tt>k</tt> is a batch boundary. Recursively compose
          the roots before and after that boundary, then return
          <tt>SHA-256(0x01 || left || right)</tt>. The result <bcp14>MUST</bcp14> equal
          <tt>segment_root</tt>. This is subtree substitution under the
          <tt>VTLRoot</tt>
          recursion in Sections 2.1.1 and 2.1.2 of <xref target="RFC9162"/>;
          it does not define a Certificate Transparency log or a CT wire object.
        </t>
      </section>

      <section numbered="true" toc="include" anchor="segment-artifact-schema">
        <name>Authoritative Segment Artifact Schema</name>
        <t>
          The authoritative segment artifact is a deterministic CBOR-encoded
          segment record produced under <xref target="cbor-profile"/>. It is the
          stable segment-scoped object of commitment verification. It commits
          to one record multiset, its ledger identity, serial number, closure
          policy and reason, and predecessor artifact. It is not a transport
          envelope, publication statement, or complete verification claim.
        </t>
        <t>
          An authoritative segment artifact is interpreted only under its
          in-band <tt>commitment_profile_id</tt>. Because that identifier is
          inside the artifact bytes, a valid timestamp token over its digest binds the
          commitment semantics. A producer manifest <bcp14>MUST</bcp14> repeat the same value
          and verifiers <bcp14>MUST</bcp14> report a mismatch as
          <tt>commitment_mismatch</tt>. Profile dispatch follows the
          canonical rules in <xref target="versioning"/>.
        </t>
        <t>The segment record contains exactly these fields:</t>
        <ul>
          <li><tt>version</tt> (uint): segment-record schema version, exactly <tt>1</tt>.</li>
          <li><tt>commitment_profile_id</tt> (tstr): a lowercase RFC 9562 UUID string. A baseline producer <bcp14>MUST</bcp14> emit exactly the profile UUID defined in <xref target="terminology"/>.</li>
          <li><tt>ledger_id</tt> (tstr): stable ledger identifier consisting of exactly 32 lowercase hexadecimal characters.</li>
          <li><tt>segment_number</tt> (uint): serial number in the range 0..(2^64-1).</li>
          <li><tt>closure_policy</tt> (map): immutable policy snapshot for this logical interval, containing exactly <tt>version</tt> equal to <tt>1</tt>; positive uint64 <tt>interval_ms</tt>; power-of-two uint64 <tt>batch_record_limit</tt> no greater than 2^63; <tt>record_limit</tt> and <tt>size_limit_bytes</tt>, each a positive uint64 or null; and <tt>empty_mode</tt> equal to <tt>emit</tt> or <tt>suppress</tt>.</li>
          <li><tt>close_reason</tt> (tstr): exactly one of <tt>interval</tt>, <tt>reconfigure</tt>, <tt>record_limit</tt>, <tt>size_limit</tt>, <tt>shutdown</tt>, <tt>recovery</tt>, or <tt>manual</tt>. When <tt>record_count</tt> is zero, <tt>closure_policy.empty_mode</tt> <bcp14>MUST</bcp14> be <tt>emit</tt> unless <tt>close_reason</tt> is <tt>shutdown</tt> or <tt>recovery</tt>.</li>
          <li><tt>prev_segment_sha256</tt> (bstr): 32-octet SHA-256 digest of the exact bytes of the previous authoritative segment artifact, or the epoch predecessor value defined in <xref target="segment-chaining"/>.</li>
          <li><tt>record_count</tt> (uint): number of canonical-record occurrences committed by the segment.</li>
          <li><tt>batch_roots</tt> (array of bstr): ordered aligned-subtree roots, each exactly 32 octets; exactly empty for an empty emitted segment.</li>
          <li><tt>segment_root</tt> (bstr): 32-octet deterministic segment root.</li>
        </ul>
        <t>
          Array position is the batch number. The root at position <tt>i</tt>
          <bcp14>MUST</bcp14> commit the consecutive sorted-leaf range beginning at
          <tt>i * batch_record_limit</tt>. The total root count, final-batch
          width, and composed segment root are derived from
          <tt>record_count</tt> and the committed closure policy as specified
          in <xref target="segment-formation"/>.
        </t>
        <t>
          The deterministic-CBOR object is the authoritative segment artifact. A JSON
          projection, filename, and storage path are non-authoritative. A
          verifier <bcp14>MUST</bcp14> validate that the producer manifest
          <tt>segment_number</tt> is the shortest unsigned decimal form defined
          in Appendix B, parse it as a uint64, and compare that numeric value
          with the decoded CBOR uint. A non-shortest decimal form is a producer
          manifest schema violation and therefore a bundle-processing error
          without a verifier result under
          <xref target="verification-inputs-scope"/>. After a valid parse, a
          numeric mismatch with the artifact is
          <tt>commitment_mismatch</tt>. A verifier <bcp14>MUST NOT</bcp14> trust a path or
          filename as the segment number.
        </t>
        <t>
          A serialized authoritative segment artifact conforming to this
          document <bcp14>MUST</bcp14> use the
          <tt>application/vnd.vtl.segment+cbor</tt> media type.
        </t>
      </section>

      <section numbered="true" toc="include" anchor="segment-chaining">
        <name>Segment Chaining</name>
        <t>
          Segment identity and chaining are defined within one stable
          <tt>ledger_id</tt>. They do not depend on UTC dates or elapsed idle
          time.
        </t>
        <ul>
          <li>The epoch segment <bcp14>MUST</bcp14> have <tt>segment_number</tt> equal to <tt>0</tt> and <tt>prev_segment_sha256</tt> equal to a 32-octet all-zero byte string.</li>
          <li>Every non-epoch segment <bcp14>MUST</bcp14> have a serial number exactly one greater than its predecessor, <bcp14>MUST</bcp14> retain the same <tt>ledger_id</tt> and <tt>commitment_profile_id</tt>, and <bcp14>MUST</bcp14> set <tt>prev_segment_sha256</tt> to <tt>SHA-256</tt> over the exact bytes of the predecessor's authoritative segment artifact.</li>
          <li>A producer <bcp14>MUST NOT</bcp14> reuse, skip, or wrap <tt>segment_number</tt>. Before serial exhaustion, it <bcp14>MUST</bcp14> stop the ledger and start a new ledger with a new <tt>ledger_id</tt>.</li>
          <li>A closure-policy change <bcp14>MUST</bcp14> take effect only in a newly opened logical interval. It does not reset <tt>segment_number</tt> or <tt>ledger_id</tt>.</li>
        </ul>
        <t>
          When a new epoch begins, the producer <bcp14>MUST</bcp14> generate a new
          <tt>ledger_id</tt> so that the probability of collision with any
          other ledger identifier is negligible. A uniformly random 128-bit
          value from a cryptographically strong random source satisfies this
          requirement. If durable sequence state
          cannot be recovered unambiguously, a producer <bcp14>MUST</bcp14> stop acceptance or
          begin a new ledger with a fresh identifier; it <bcp14>MUST NOT</bcp14> reset the
          serial under the old identifier. Redundant producer instances <bcp14>MUST</bcp14>
          use single-writer fencing or an atomic shared allocator so that they
          cannot emit different artifacts for the same
          <tt>(ledger_id, segment_number)</tt>.
        </t>
        <t>
          A verifier given adjacent authoritative segment artifacts <bcp14>MUST</bcp14> validate serial
          continuity, exact <tt>commitment_profile_id</tt> equality, and
          predecessor-digest linkage. A profile mismatch is a
          <tt>segment_chain_mismatch</tt>. A partial disclosure that
          omits the predecessor can still support validation of the disclosed
          artifact and its timestamp artifacts, but the verifier <bcp14>MUST</bcp14> report
          <tt>chain_status</tt> as <tt>predecessor_not_disclosed</tt>.
        </t>
      </section>
    </section>

    <section numbered="true" toc="include" anchor="artifacts">
      <name>Artifacts and Verification Bundles</name>
      <t>
        A deployment can store canonical records, authoritative segment
        artifacts, producer manifests, verifier results, and timestamp artifacts in any suitable
        layout. Filenames and layouts are non-authoritative. Each disclosed
        record artifact <bcp14>MUST</bcp14> contain the exact admitted canonical-record octets
        without a wrapper or re-encoding.
      </t>
      <t>
        Every verification bundle that claims a disclosure class under this
        document <bcp14>MUST</bcp14> disclose the authoritative segment artifact and a
        producer manifest.
      </t>

      <section numbered="true" toc="include" anchor="producer-manifest">
        <name>Producer Manifest</name>
        <t>
          The artifact's in-band <tt>commitment_profile_id</tt> is the
          cryptographically bound profile identifier. The producer manifest
          repeats the ledger identity, segment number, commitment profile,
          claimed disclosure class, artifact digests, and claimed producer
          timestamp state. It <bcp14>MUST NOT</bcp14> contain a segment-chain validation conclusion,
          verifier status, failure reasons, or an overall
          verification outcome.
        </t>
        <t>
          Each <tt>artifacts.record_batches</tt> entry opens the aligned batch
          subtree identified by its <tt>batch_number</tt>. Each nested
          <tt>records</tt> entry represents one admitted record occurrence.
          Duplicate entries are permitted and <bcp14>MUST</bcp14> be counted separately.
          When occurrences have identical canonical-record bytes, their
          entries <bcp14>MAY</bcp14> reference the same disclosed artifact. A verifier <bcp14>MAY</bcp14>
          reuse a successful digest computation for identical bytes, but the
          resulting leaf hash <bcp14>MUST</bcp14> contribute once for each listed occurrence.
          Artifact-reference order does not assert admission order.
        </t>
        <t>
          For a non-empty segment, a Class A manifest <bcp14>MUST</bcp14> open every batch
          exactly once. For an emitted empty segment, a Class A manifest <bcp14>MUST</bcp14>
          omit <tt>record_batches</tt>. A Class B manifest <bcp14>MUST</bcp14> open a non-empty
          proper subset of a non-empty segment's batches and therefore cannot
          claim an empty segment. A Class C manifest <bcp14>MUST</bcp14> omit
          <tt>record_batches</tt>. An
          opening <bcp14>MUST</bcp14> disclose exactly the number of record occurrences
          derived for that batch from <tt>record_count</tt> and
          <tt>batch_record_limit</tt>. After hashing and sorting those exact
          record octets, their <tt>VTLRoot</tt> value <bcp14>MUST</bcp14> equal the indexed
          <tt>batch_roots</tt> value.
        </t>
        <t>
          Producer timestamp state is limited to <tt>present</tt> when the
          corresponding timestamp response is disclosed, <tt>pending</tt>
          when issuance was initiated but has not reached a terminal state,
          and <tt>unavailable</tt> when issuance terminated without a usable
          response.
          Producer manifests <bcp14>MUST NOT</bcp14> use
          verifier states such as <tt>verified</tt> or <tt>failed</tt>.
        </t>
        <t>
          A <tt>pending</tt> or <tt>unavailable</tt> state <bcp14>MUST</bcp14> omit
          <tt>tsa_tsr</tt>. A <tt>present</tt> TSA state <bcp14>MUST</bcp14> reference
          <tt>tsa_tsr</tt>. When a disclosed response contains a nonce, the
          manifest <bcp14>MUST</bcp14> also reference <tt>tsa_req</tt>. Producer obligations
          for a nonce-bearing request are specified in
          <xref target="rfc3161-profile"/>.
        </t>
        <t>
          A serialized producer manifest conforming to this document <bcp14>MUST</bcp14> use
          the <tt>application/vnd.vtl.manifest+json</tt> media type.
        </t>
        <t>
          The producer manifest is the primary disclosure surface for
          verifier-visible producer claims. Its schema is defined in
          <xref target="appendix-b"/>. Deployment-specific data can be carried
          only in explicit extension containers and <bcp14>MUST</bcp14> preserve the
          semantics defined here. Extension data is opaque to baseline
          verification and does not select an additional evidence channel or
          affect the baseline outcome.
        </t>
      </section>

      <section numbered="true" toc="include" anchor="verifier-result">
        <name>Verifier Result</name>
        <t>
          Verification under <xref target="verify"/> produces a logical
          verifier result. Only that verifier-authored result states the
          exercised scope, any segment-chain conclusion, TSA channel status,
          verifier-policy identifier, overall
          outcome, and failure reasons. The result reports conclusions needed
          by a relying party; local step-by-step diagnostics and execution
          traces are implementation-specific. A producer manifest and a
          verifier result <bcp14>MUST NOT</bcp14> be represented as the same object.
        </t>
        <t>
          A verifier <bcp14>MAY</bcp14> serialize its result as JSON. A serialized result that
          claims conformance with this document <bcp14>MUST</bcp14> use the schema in
          <xref target="appendix-b"/> and the <tt>application/json</tt> media
          type. This document does not request a specialized media type for
          verifier results.
        </t>
      </section>

      <section numbered="true" toc="include" anchor="portable-artifact-references">
        <name>Portable Artifact References and Binding</name>
        <t>
          Every path-bearing object consumed during verification, including a
          producer manifest artifact reference or an extension object, <bcp14>MUST</bcp14>
          satisfy the requirements in this
          subsection. Each path is a UTF-8 string interpreted relative to the
          disclosed evidence bundle root, using
          <tt>/</tt> as the only separator. A path <bcp14>MUST</bcp14> be non-empty; <bcp14>MUST NOT</bcp14>
          begin with <tt>/</tt>, <tt>\</tt>, or a drive-letter prefix; <bcp14>MUST NOT</bcp14>
          contain <tt>\</tt>, a colon, a control character in the ranges U+0000
          through U+001F or U+007F, an empty path component, or a component
          equal to <tt>.</tt> or <tt>..</tt>. Verifiers <bcp14>MUST</bcp14> resolve and open
          every consumed path through a safe resolver that returns an object
          confined below the bundle root and prevents substitution of that
          object before it is consumed.
        </t>
        <t>
          These are semantic requirements and do not depend on a
          regular-expression dialect or operating-system pathname behavior.
          Every artifact listed in the
          producer manifest <bcp14>MUST</bcp14> carry a lowercase hexadecimal SHA-256 digest entry.
        </t>
        <t>
          After the primary-input boundary in
          <xref target="verification-inputs-scope"/> has been satisfied, an
          unsafe secondary reference is reported according to the role of the
          referenced object. A record or batch-opening artifact required for
          the claimed class or selected scope yields
          <tt>insufficient_disclosure</tt>. An unsafe referenced timestamp
          response yields TSA channel status <tt>missing</tt> and
          <tt>channel_failure</tt>. A disclosed predecessor that cannot
          be safely resolved yields <tt>chain_status</tt> equal to
          <tt>failed</tt> and <tt>segment_chain_mismatch</tt>. A reference that
          is safely opened but whose bytes fail the declared digest uses
          <tt>commitment_mismatch</tt> instead.
        </t>
        <t>
          The producer manifest binds claim semantics to the authoritative
          segment artifact. The producer manifest's <tt>ledger_id</tt>,
          <tt>segment_number</tt>, and <tt>commitment_profile_id</tt> <bcp14>MUST</bcp14> match
          the corresponding fields in the authoritative segment artifact. An
          identity mismatch <bcp14>MUST</bcp14> be reported as
          <tt>commitment_mismatch</tt>. Segment-number
          comparison follows the rule in
          <xref target="segment-artifact-schema"/>; profile selection follows
          <xref target="versioning"/>.
        </t>
      </section>

    </section>

    <section numbered="true" toc="include" anchor="anchoring-verification">
      <name>Anchoring and Verification</name>

      <section numbered="true" toc="include" anchor="baseline-conformance">
        <name>Baseline Conformance</name>
        <t>
          A baseline producer <bcp14>MUST</bcp14> emit the fixed
          <tt>commitment_profile_id</tt> defined in this document, construct
          authoritative segment artifacts and producer manifests under this
          profile, and initiate <xref target="RFC3161"/> timestamping
          for every emitted segment. Timestamp issuance <bcp14>MAY</bcp14> remain
          <tt>pending</tt> while incomplete.
        </t>
        <t>
          A baseline verifier <bcp14>MUST</bcp14> implement this commitment profile and the
          RFC 3161 validation profile in <xref target="rfc3161-profile"/>, obtain
          the profile identifier from the authoritative segment artifact, and
          use the result vocabulary and fixed TSA channel key defined here. Every
          verifier result claiming baseline conformance <bcp14>MUST</bcp14> contain the
          <tt>tsa</tt> channel key, including when its status is
          <tt>pending</tt>, <tt>missing</tt>, or <tt>failed</tt>. A baseline
          <tt>success</tt> result requires successful timestamp validation.
        </t>
        <t>
          Extension data is opaque to baseline producers and verifiers. Its
          presence, absence, or contents <bcp14>MUST NOT</bcp14> change a baseline channel
          status or overall outcome. A separate specification can define an
          additional evidence mechanism and its validation result without
          changing the authoritative segment artifact or the commitment
          profile defined here.
        </t>
      </section>

      <section numbered="true" toc="include" anchor="tsa-channel-status-vocabulary">
        <name>TSA Channel Status Vocabulary</name>
        <t>
          Verifier results <bcp14>MUST</bcp14> use the following status vocabulary for the
          TSA channel:
        </t>
        <ul>
          <li><tt>verified</tt>: timestamp validation succeeded for the disclosed artifact binding.</li>
          <li><tt>pending</tt>: timestamp issuance was initiated but its response is not yet available; this is not equivalent to invalid.</li>
          <li><tt>missing</tt>: an expected timestamp response is absent without a valid pending producer timestamp state.</li>
          <li><tt>failed</tt>: validation was attempted and did not succeed.</li>
        </ul>
        <t>
          A verifier that determines that valid producer timestamp state identifies
          issuance as incomplete <bcp14>MAY</bcp14> report <tt>pending</tt> only when its
          identified verifier policy accepts two out-of-band inputs: an
          authenticated channel or signature establishing manifest provenance,
          and an authenticated creation or receipt time for the pending claim,
          obtained independently of the manifest, that falls within the
          policy-defined maximum age. This document defines no manifest
          field carrying either property. A verifier without both inputs <bcp14>MUST</bcp14>
          report <tt>missing</tt>. Producer timestamp state <tt>unavailable</tt> maps to verifier
          status <tt>missing</tt>. A baseline verifier always evaluates the
          TSA channel and uses only the four states defined above.
        </t>
        <t>
          The outcome effects of <tt>missing</tt> and <tt>pending</tt> are defined in
          <xref target="baseline-conformance"/> and
          <xref target="overall-outcome"/>.
        </t>
        <t>
          The optional TSA-result <tt>reason</tt> value is human-readable
          diagnostic text. This document defines <tt>issuance_pending</tt> as its
          only baseline machine-defined token. Any other value is free text
          and <bcp14>MUST NOT</bcp14> be interpreted as a portable machine-actionable code.
          A channel result whose status is <tt>pending</tt>, <tt>missing</tt>,
          or <tt>failed</tt> <bcp14>MUST</bcp14> include <tt>reason</tt>.
          A <tt>verified</tt> channel result <bcp14>MAY</bcp14> include it.
          Additional machine-readable details <bcp14>MAY</bcp14> be placed in the channel
          result's <tt>extensions</tt> member under keys defined by the
          applicable extension specification or deployment. They are opaque
          to baseline verification.
        </t>
      </section>

      <section numbered="true" toc="include" anchor="anchoring-contract">
        <name>Anchoring Contract</name>
        <t>
          The anchoring contract is simple: a producer computes the SHA-256
          digest of the authoritative segment artifact and submits that digest
          using RFC 3161. Verifiers <bcp14>MUST</bcp14> recompute that digest over the exact
          artifact bytes. Timestamp validation and comparison of its
          message imprint with that digest do not depend on successful CBOR
          decoding of the artifact.
        </t>
        <t>
          An RFC 3161 timestamp over the authoritative segment artifact digest binds the
          complete artifact bytes, including the in-band
          <tt>commitment_profile_id</tt>. It does not bind a disclosure class,
          producer manifest, verifier policy, or verifier result.
        </t>
        <t>
          Consequently, a producer manifest received over an unauthenticated
          channel can under-claim the available disclosure as Class C, omit
          record openings, or direct the verifier to a different valid
          authoritative artifact. Manifest digest checks establish consistency
          with the received manifest; they do not establish its provenance or
          that it names the artifact intended by the relying party. A relying
          party that needs those properties <bcp14>MUST</bcp14> obtain the authoritative
          artifact bytes or their expected digest independently through an
          authenticated mechanism and rerun verification from those bytes.
        </t>
        <t>
          Baseline timestamping and success requirements are defined in
          <xref target="baseline-conformance"/>. The producer <bcp14>MUST</bcp14> seal and
          durably write the authoritative segment artifact without waiting for
          timestamp issuance completion. Alternative timestamping or attestation
          mechanisms require a separate specification and do not alter this
          baseline contract.
        </t>
      </section>

      <section numbered="true" toc="include" anchor="rfc3161-profile">
        <name>RFC 3161 Timestamp Channel Profile</name>
        <t>
          Baseline selection and implementation requirements for this channel
          are defined in <xref target="baseline-conformance"/>.
        </t>
        <t>
          When this channel is used, the producer <bcp14>MUST</bcp14> set
          <tt>TimeStampReq.messageImprint.hashAlgorithm</tt> to SHA-256 and its
          <tt>hashedMessage</tt> to the exact 32-octet result of SHA-256 over
          the authoritative segment artifact bytes. The producer <bcp14>MUST NOT</bcp14> hash
          that 32-octet result again. The producer <bcp14>MUST</bcp14> set
          <tt>TimeStampReq.certReq</tt> to <tt>TRUE</tt>.
        </t>
        <t>
          The <tt>TimeStampReq</tt>, <tt>TimeStampResp</tt>, and timestamp
          token <bcp14>MUST</bcp14> conform to <xref target="RFC3161"/>, as updated by
          <xref target="RFC5816"/> and restricted by this section. The token
          <bcp14>MUST</bcp14> contain exactly one CMS
          <tt>SignerInfo</tt> as defined by <xref target="RFC5652"/>.
        </t>
        <t>
          A successful <tt>TimeStampResp.status.status</tt> <bcp14>MUST</bcp14> be
          <tt>granted (0)</tt>. A verifier <bcp14>MUST</bcp14> reject
          <tt>grantedWithMods (1)</tt> under this profile.
        </t>
        <t>
          The <tt>SignerInfo</tt> signed attributes <bcp14>MUST</bcp14> contain exactly one
          <tt>SigningCertificateV2</tt> attribute with exactly one attribute
          value, as defined by <xref target="RFC5035"/>. The first
          <tt>ESSCertIDv2.certHash</tt> <bcp14>MUST</bcp14> equal SHA-256 over the complete
          DER encoding of the selected signer certificate. If
          <tt>hashAlgorithm</tt> is present, it <bcp14>MUST</bcp14> identify SHA-256;
          omission denotes the SHA-256 default. If <tt>issuerSerial</tt> is
          present, it <bcp14>MUST</bcp14> identify that same certificate. The signed
          attributes <bcp14>MUST NOT</bcp14> contain a legacy
          <tt>SigningCertificate</tt> attribute.
        </t>
        <t>
          Because this profile requires
          <tt>TimeStampReq.certReq=TRUE</tt>,
          <tt>SignedData.certificates</tt> <bcp14>MUST</bcp14> contain exactly one X.509
          certificate that matches both <tt>SignerInfo.sid</tt> and the first
          <tt>ESSCertIDv2</tt>; zero or multiple matching certificates are a
          verification failure. The set <bcp14>MAY</bcp14> also contain unrelated
          certificates or certification-path certificates.
        </t>
        <t>
          These requirements deliberately define a narrower profile than
          generic RFC 3161 interoperability. In particular, this profile
          rejects <tt>grantedWithMods</tt>, the legacy
          <tt>SigningCertificate</tt> attribute, multiple
          <tt>SignerInfo</tt> values, and signer-certificate arrangements or
          ESS certificate identifiers that do not satisfy the exact rules
          above. A conforming VTL implementation therefore cannot assume that
          an arbitrary deployed RFC 3161 TSA is compatible. Deployments <bcp14>SHOULD</bcp14>
          prequalify a TSA against this profile before relying on it for
          baseline timestamping.
        </t>
        <t>
          A deployment using this channel <bcp14>MUST</bcp14> define accepted TSA trust
          anchors, accepted TSA policy identifiers, certificate-revocation
          policy, acceptable signature and certificate algorithms, and any
          additional constraints applied to the token's generation time. It
          <bcp14>MUST</bcp14> define a maximum acceptable future skew relative to the
          verifier-local time source identified by the verifier policy. That
          source <bcp14>MUST</bcp14> be available when the future-skew validation is
          performed. When operators
          control the TSA, responses <bcp14>SHOULD</bcp14> include necessary intermediates
          and <bcp14>SHOULD</bcp14> omit an already provisioned trust anchor.
          A verifier <bcp14>MUST NOT</bcp14> rewrite a received response or reject it merely
          because it contains additional nonmatching certificates.
        </t>
        <t>
          A verifier evaluating disclosed timestamp artifacts <bcp14>MUST</bcp14> recompute the
          authoritative segment artifact digest and validate the
          timestamp response and token under <xref target="RFC3161"/>, as
          updated by <xref target="RFC5816"/>. Validation <bcp14>MUST</bcp14> include a
          response status of <tt>granted (0)</tt> and required token presence;
          the CMS
          <tt>id-signedData</tt> content type and <tt>id-ct-TSTInfo</tt>
          encapsulated content type; exact SHA-256 message-imprint equality;
          the CMS signature and signed attributes; unambiguous
          signer-certificate binding; the signer certificate's single
          critical extended-key-usage extension containing only
          <tt>id-kp-timeStamping</tt>; certification-path validation under
          <xref target="RFC5280"/> using the token's <tt>TSTInfo.genTime</tt>
          as its date/time input and configured trust anchors; configured TSA
          policy and certificate-validation constraints; a
          <tt>genTime</tt> value within the selected signer certificate's
          validity interval; and the configured maximum future skew.
        </t>
        <t>
          The deployment's certificate-revocation policy <bcp14>MUST</bcp14> define acceptable
          revocation evidence and the treatment of historical certificate
          status at <tt>TSTInfo.genTime</tt>. This profile does not define a
          long-term archival-PKI validation profile beyond those policy inputs.
        </t>
        <t>
          The optional producer-manifest artifact
          <tt>artifacts.tsa_req</tt> carries the exact DER-encoded
          <tt>TimeStampReq</tt> as a non-authoritative supporting artifact. A
          producer that sends a request containing a nonce <bcp14>MUST</bcp14> retain those
          exact request bytes for at least as long as it retains the
          corresponding response bytes and <bcp14>MUST</bcp14> disclose the request with
          that response. The producer <bcp14>MUST NOT</bcp14> treat a response that omits or
          changes its request nonce as successful timestamp issuance.
        </t>
        <t>
          When a disclosed response contains a nonce, the producer manifest
          <bcp14>MUST</bcp14> reference <tt>tsa_req</tt>. Whenever <tt>tsa_req</tt> is
          disclosed, the verifier <bcp14>MUST</bcp14> validate that reference's SHA-256
          digest, require the request message-imprint algorithm to be SHA-256,
          require its <tt>hashedMessage</tt> to equal the recomputed
          authoritative segment artifact digest, and require
          <tt>certReq=TRUE</tt>. If either disclosed object contains a nonce,
          the request and response <bcp14>MUST</bcp14> both contain a nonce and the two values
          <bcp14>MUST</bcp14> be equal. A nonce-bearing response without <tt>tsa_req</tt>, a
          disclosed nonce present in only one object, unequal disclosed
          nonces, or any failure of those checks
          is a timestamp-channel verification failure reported with
          <tt>channel_failure</tt>. A nonce-free disclosed request is validated
          under the same non-nonce rules.
        </t>
        <t>
          If the response contains no nonce and <tt>tsa_req</tt> is not
          disclosed, a verifier cannot determine whether the original request
          contained a nonce. The verifier can validate the signed response and
          its artifact-digest binding, but the result makes no claim of
          request-response nonce correlation. The producer obligations above
          remain applicable and cannot be inferred from the baseline
          disclosure in this case.
        </t>
        <t>
          Any failure of the RFC 3161 validations above is a timestamp-channel verification
          failure. The corresponding TSA channel status in a verifier result
          <bcp14>MUST</bcp14> be <tt>verified</tt> on success and <tt>failed</tt> on failure.
        </t>
      </section>

      <section numbered="true" toc="include" anchor="verify">
        <name>Verification</name>
        <section numbered="true" toc="exclude" anchor="verification-inputs-scope">
          <name>Inputs and Scope</name>
        <t>
          The verifier-result contract applies only after the verifier has
          obtained the exact producer-manifest bytes, parsed them sufficiently
          to determine every mandatory result field and the exact
          <tt>artifacts.segment_cbor</tt> reference, and obtained the exact
          referenced segment-artifact bytes. Failure to obtain either primary
          input; malformed or structurally invalid producer-manifest bytes; a
          missing primary artifact reference; or unsafe resolution of either
          primary input is a bundle-processing error. A verifier <bcp14>MUST</bcp14> reject
          that bundle-processing error but <bcp14>MUST NOT</bcp14> emit a verifier result for
          it. Such an error is outside the verifier-result schema and is not
          an <tt>insufficient_disclosure</tt> conclusion.
        </t>
        <t>
          Structurally invalid producer-manifest bytes include violations of
          the JSON, CDDL, lexical, and manifest-only cross-field requirements
          that can be evaluated before authoritative artifact verification.
          In particular, <tt>present</tt> without <tt>tsa_tsr</tt>,
          <tt>pending</tt> or <tt>unavailable</tt> with <tt>tsa_tsr</tt>, and a
          missing, negative, non-integer, non-shortest, or uint64-overflowing
          manifest <tt>segment_number</tt> are bundle-processing errors for
          which no verifier result is emitted.
          A deployment-configured resource limit that prevents the verifier
          from reaching the invocation boundary above likewise produces a
          bundle-processing error without a verifier result. Once that boundary
          has been satisfied, a rejection solely because a syntactically and
          structurally valid input exceeds an identified verifier-policy limit
          uses <tt>verifier_policy_rejection</tt> as specified in
          <xref target="security-resource-exhaustion"/>.
        </t>
        <t>
          Verifiers <bcp14>MUST</bcp14> first decode the authoritative segment artifact and
          determine the applicable <tt>commitment_profile_id</tt> from its
          in-band field. Dispatch precedence is fixed: a missing or non-text
          identifier yields <tt>invalid_segment_artifact</tt>; a text value
          that is a well-formed lowercase RFC 9562 UUID but is not supported
          yields <tt>unsupported_commitment_profile</tt>; and the UUID defined
          by this document selects the commitment profile defined in Sections
          4.1 through 4.6, with structural CDDL in Appendix C. An
          unsupported UUID <bcp14>MUST NOT</bcp14> be classified as
          <tt>invalid_segment_artifact</tt> solely because it differs from this
          document's UUID. When the field can be decoded as a text string,
          the verifier result's optional <tt>commitment_profile_id</tt> <bcp14>MUST</bcp14>
          echo its exact artifact value, including when that value is
          unsupported. The producer manifest's <tt>ledger_id</tt>,
          <tt>segment_number</tt>, and
          <tt>commitment_profile_id</tt> <bcp14>MUST</bcp14> exactly match the corresponding
          artifact fields whenever those fields can be decoded. Segment-number
          comparison follows the rule in
          <xref target="segment-artifact-schema"/>.
        </t>
        <t>
          The verifier <bcp14>MUST</bcp14> treat <tt>commitment_profile_id</tt> as the semantic
          key for interpreting the authoritative segment artifact. A structurally
          well-formed authoritative segment artifact and successful timestamp validation are insufficient
          for semantic verification if the applicable
          <tt>commitment_profile_id</tt> is absent or unsupported. A producer
          manifest identity mismatch is a verification failure reported as
          <tt>commitment_mismatch</tt> even when the artifact and timestamp are
          otherwise valid.
        </t>
        <t>
          The producer manifest's <tt>disclosure_class</tt> is the producer-claimed
          class. The result's <tt>claimed_disclosure_class</tt> <bcp14>MUST</bcp14> repeat
          that value. The result's <tt>verification_scope</tt> identifies the
          scope selected for the verification invocation:
          <tt>public_recompute</tt> corresponds to
          Class A, <tt>partial_verification</tt> to Class B, and
          <tt>anchor_only</tt> to Class C. A scope is weaker in the order A,
          B, C. After satisfying the primary input boundary, the invocation
          <bcp14>MUST</bcp14> select an intended scope; selection does not assert support.
          The verifier determines support after structural artifact decoding
          and claimed-class shape validation but before scope-specific
          validation. Earlier fail-fast termination still reports the selected
          scope without claiming it succeeded. If the verifier intentionally
          exercises a weaker scope than the inputs support and no verifier policy
          requires the stronger scope, the overall result <bcp14>MUST</bcp14> be
          <tt>partial</tt>. If applicable verifier policy requires a stronger
          supported scope, the overall result <bcp14>MUST</bcp14> be <tt>failure</tt> with
          <tt>scope_not_exercised</tt>. If the disclosed inputs are genuinely
          inadequate for the claimed class or asserted scope, the result
          instead uses <tt>insufficient_disclosure</tt>. Exercising a stronger
          scope does not rewrite the producer-claimed class.
        </t>
        <t>
          The claimed class determines manifest shape; the selected scope
          determines which valid disclosed artifacts are consumed and which
          recomputation claims are made. Scope support is determined from the
          decoded artifact, disclosures, claimed class, and verifier policy.
          Inputs support a scope when they contain the manifest structure and
          artifacts required to attempt it; support does not assert that the
          scope's validations would succeed.
          Results <bcp14>MUST NOT</bcp14> claim assurances outside the exercised scope.
        </t>
        <t>
          The result's <tt>manifest_sha256</tt> <bcp14>MUST</bcp14> equal SHA-256 over the
          exact UTF-8 octets of the producer manifest that was validated, under
          the exact-octet rule in <xref target="cbor-profile"/>. This field
          identifies the validated input;
          it does not authenticate the verifier result.
        </t>
        <t>
          The result's <tt>artifact_sha256</tt> <bcp14>MUST</bcp14> equal SHA-256 over the
          exact referenced bytes of <tt>artifacts.segment_cbor</tt>, under the
          exact-octet rule in <xref target="cbor-profile"/>. It <bcp14>MUST</bcp14> be present
          even when those bytes are malformed or cannot be decoded. This result field identifies
          the authoritative artifact input and is distinct from the producer
          manifest's artifact-reference digest claim.
        </t>
        <t>
          When the exact primary artifact bytes are present but do not decode
          as a valid authoritative segment artifact under the applicable
          artifact syntax and cross-field rules, the verifier result <bcp14>MUST</bcp14> be
          <tt>failure</tt> and include <tt>invalid_segment_artifact</tt>. The
          result's <tt>verification_scope</tt> records the scope selected for
          the invocation; it does not claim that that scope succeeded. The
          verifier <bcp14>MUST</bcp14> evaluate the TSA channel independently over the exact
          artifact bytes and report it as <tt>verified</tt>, <tt>failed</tt>,
          or <tt>missing</tt> as applicable. Artifact decoding failure alone
          <bcp14>MUST NOT</bcp14> cause TSA channel status <tt>failed</tt> or
          <tt>channel_failure</tt>.
        </t>
        <t>
          The verifier <bcp14>MUST</bcp14> always compute SHA-256 over the exact referenced
          bytes of <tt>artifacts.segment_cbor</tt> and compare it with
          <tt>artifacts.segment_cbor.sha256</tt>. That value checks producer
          manifest self-consistency only; it is not an external timestamp binding
          and <bcp14>MUST NOT</bcp14> be counted as a timestamp-channel binding.
        </t>
        <t>
          For every producer manifest artifact reference consumed during verification,
          the verifier <bcp14>MUST</bcp14> compute SHA-256 over the exact referenced file
          bytes and compare it with the reference's <tt>sha256</tt> value. A
          mismatch is a verification failure. A verifier <bcp14>MAY</bcp14> reuse one
          successful file-digest computation for repeated references to the
          same bytes. Duplicate record occurrences nevertheless contribute
          once per listed occurrence to record-level and multiset
          computations.
        </t>
        </section>
        <section numbered="true" toc="exclude" anchor="verification-procedure">
          <name>Verification Procedure</name>
        <t>
          Verifiers <bcp14>SHOULD</bcp14> apply the following validation steps in fail-fast
          order, subject to the exercised verification scope:
        </t>
        <ol>
          <li>Validate manifest shape against the producer-claimed disclosure class. For non-empty Class A, <tt>record_batches</tt> opens every authoritative batch; for Class B, it opens a non-empty proper subset of the authoritative batches; and for Class C, it is absent. Apply the empty-segment exceptions in <xref target="disclosure-bundles"/>. These claimed-class requirements do not determine which valid openings a weaker selected scope consumes.</li>
          <li>Validate the authoritative segment artifact and the producer manifest, including their repeated identity fields. An artifact that is malformed or fails artifact syntax or cross-field validation yields <tt>invalid_segment_artifact</tt>; a repeated identity mismatch yields <tt>commitment_mismatch</tt>. Always validate <tt>artifacts.segment_cbor.sha256</tt>, and validate the digest of every other producer manifest artifact reference consumed during the remaining steps. Do not count the producer manifest digest as an external timestamp binding.</li>
          <li>For an epoch segment, validate serial zero and the zero predecessor value and set <tt>chain_status</tt> to <tt>epoch</tt>. For a non-epoch segment whose predecessor is disclosed, validate ledger identity, exact commitment-profile identity, contiguous serials, and <tt>prev_segment_sha256</tt>; set <tt>chain_status</tt> to <tt>validated</tt> on success or <tt>failed</tt> on failure. When the predecessor is unavailable, set <tt>chain_status</tt> to <tt>predecessor_not_disclosed</tt>.</li>
          <li>For every scope, validate <tt>record_count</tt>, the power-of-two batch limit, batch-root cardinality, and composition of <tt>batch_roots</tt> into <tt>segment_root</tt> as specified in <xref target="batch-metadata-checks"/>.</li>
          <li>For <tt>public_recompute</tt> over a non-empty segment, validate every disclosed batch opening and every canonical-record CBOR artifact under <xref target="disclosed-record-validation"/>, hash exact octets under <xref target="cbor-profile"/>, compare every recomputed batch root with the authoritative indexed root, and independently recompute <tt>segment_root</tt> from the complete sorted leaf list. For an empty segment, require <tt>record_batches</tt> to be absent, <tt>record_count</tt> and the complete leaf count to be zero, <tt>batch_roots</tt> to be empty, and <tt>segment_root</tt> to equal SHA-256 over zero octets. Do not reconstruct a record from source telemetry.</li>
          <li>For <tt>partial_verification</tt>, reject an empty or single-batch segment. Consume a non-empty proper subset of authoritative batches: selected complete openings from a valid Class A manifest, or the disclosed openings of a valid Class B manifest. Validate each consumed record, complete opening, indexed root, and adjacent consumed boundary under <xref target="disclosed-record-validation"/> and <xref target="batch-metadata-checks"/>. Unconsumed openings make no record-level or batch-opening claim and their record artifacts need not be fetched or digested. Other withheld-batch validation is deployment-specific and <bcp14>MAY</bcp14> appear in <tt>extensions</tt>.</li>
          <li>For <tt>anchor_only</tt>, do not consume <tt>record_batches</tt>, regardless of whether valid claimed-class shape requires them to be present, and do not claim record-level or batch-opening recomputation.</li>
          <li>Compare the recomputed authoritative segment artifact digest with the timestamp response's <tt>messageImprint.hashedMessage</tt>, whether or not artifact decoding succeeded. A mismatch is a timestamp-channel verification failure. A policy-accepted <tt>pending</tt> producer timestamp state can lack the external binding and yields <tt>partial</tt>. The producer-timestamp-state and <tt>tsa_tsr</tt> cross-field violations identified in <xref target="verification-inputs-scope"/> are rejected at the primary-input boundary without a verifier result.</li>
          <li>Validate the <xref target="RFC3161"/> timestamp response and report its status in the TSA channel result. A referenced response that is unavailable is <tt>missing</tt>; a response whose validation is attempted and does not succeed is <tt>failed</tt>.</li>
        </ol>
        </section>
        <section numbered="true" toc="exclude" anchor="batch-metadata-checks">
          <name>Batch-Subtree Validation</name>
        <t>
          Verifiers <bcp14>MUST</bcp14> apply the structural validations below before
          accepting any scope. Manifest-shape validation follows the claimed
          disclosure class; opening validation follows the selected scope:
        </t>
        <ul>
          <li><tt>batch_record_limit</tt> is a power of two in the permitted range;</li>
          <li>the number of 32-octet <tt>batch_roots</tt> values equals the value derived from <tt>record_count</tt>, including the empty-segment case;</li>
          <li>when <tt>record_count</tt> is zero, <tt>closure_policy.empty_mode</tt> is <tt>emit</tt>, or <tt>close_reason</tt> is <tt>shutdown</tt> or <tt>recovery</tt>;</li>
          <li>when <tt>record_count</tt> is greater than zero, composition of the ordered aligned subtree roots equals the authoritative <tt>segment_root</tt>; for an empty segment, the separate empty-root rule in <xref target="merkle-policy"/> applies;</li>
          <li>for claimed-class shape, batch-opening numbers are unique and in range; non-empty Class A opens every batch, Class B opens a non-empty proper subset, and Class C and empty Class A omit <tt>record_batches</tt>;</li>
          <li>for <tt>public_recompute</tt>, every disclosed opening is consumed, contains exactly its derived number of record occurrences, and has sorted recomputed leaves that reduce to the indexed batch root;</li>
          <li>for <tt>partial_verification</tt>, every opening selected for consumption is complete and has sorted recomputed leaves that reduce to the indexed batch root; the selected batch numbers form a non-empty proper subset of the authoritative batches;</li>
          <li>when consumed openings for batch numbers <tt>i</tt> and <tt>i+1</tt> are both disclosed, the greatest leaf hash in batch <tt>i</tt> is less than or equal to the least leaf hash in batch <tt>i+1</tt>; and</li>
          <li>for <tt>public_recompute</tt>, the globally sorted multiset of every disclosed occurrence reduces independently to <tt>segment_root</tt>.</li>
        </ul>
        <t>
          The adjacent-opening comparison is required under
          <tt>public_recompute</tt> and <tt>partial_verification</tt> whenever
          the relevant pair is consumed. A successful
          <tt>partial_verification</tt> result verifies the global sort rule
          only at those consumed boundaries;
          Class C verifies no leaf-order boundary. A later
          <tt>public_recompute</tt> result that exposes a global ordering
          violation <bcp14>MUST</bcp14> be <tt>failure</tt> with
          <tt>commitment_mismatch</tt>.
        </t>
        </section>
        <section numbered="true" toc="exclude" anchor="disclosed-record-validation">
          <name>Disclosed Canonical-Record Validation</name>
        <t>
          A verifier exercising <tt>public_recompute</tt> or
          <tt>partial_verification</tt> <bcp14>MUST</bcp14> validate every record artifact
          consumed under the exercised scope as one exact canonical-record byte string before using it as
          a leaf preimage. The bytes <bcp14>MUST</bcp14> contain exactly one CBOR data item
          with no trailing data; <bcp14>MUST</bcp14> have the seven-element array shape and
          field constraints in <xref target="canonical-record-input"/>; and
          <bcp14>MUST</bcp14> satisfy the deterministic encoding, text-only map-key,
          duplicate-key, UTF-8, tag, finite floating-point, and permitted-value
          rules in <xref target="cbor-profile"/> at every recursive payload level.
          The recursively restricted payload shape is part of this validation.
        </t>
        <t>
          The verifier <bcp14>MUST</bcp14> hash the exact validated octets under
          <xref target="cbor-profile"/>. If consumed record bytes violate any
          canonical-record rule, the
          overall result <bcp14>MUST</bcp14> be <tt>failure</tt> with
          <tt>invalid_canonical_record</tt>, even when those bytes hash to the
          leaf value committed by the producer. If a separately observed
          record digest, batch root, segment root, artifact digest, or binding
          also mismatches, the result <bcp14>MUST</bcp14> additionally include
          <tt>commitment_mismatch</tt>. Each category occurs at most once.
        </t>
        <t>
          A baseline verifier exercising <tt>public_recompute</tt> or
          <tt>partial_verification</tt> <bcp14>MUST</bcp14> accept every conforming disclosed
          canonical-record artifact consumed under the exercised scope whose total encoded length is no greater
          than 4096 octets. It <bcp14>MAY</bcp14> accept larger records under identified
          verifier policy and configured resource limits.
        </t>
        </section>
        <section numbered="true" toc="exclude" anchor="failure-reasons">
          <name>Failure Reasons</name>
        <t>
          A verifier result whose <tt>overall</tt> value is <tt>failure</tt>
          <bcp14>MUST</bcp14> contain one or more machine-usable <tt>failure_reasons</tt>.
          This profile defines the following baseline categories:
        </t>
        <dl newline="true" spacing="normal">
          <dt><tt>unsupported_commitment_profile</tt></dt>
          <dd>The in-band profile identifier is present but unsupported; this conclusion makes the overall result <tt>failure</tt>.</dd>
          <dt><tt>invalid_canonical_record</tt></dt>
          <dd>A disclosed canonical-record byte string violates the required record shape, field constraints, restricted payload model, or deterministic CBOR profile.</dd>
          <dt><tt>invalid_segment_artifact</tt></dt>
          <dd>Present authoritative segment-artifact bytes are malformed or violate the required artifact syntax or cross-field rules.</dd>
          <dt><tt>commitment_mismatch</tt></dt>
          <dd>Commitment material, including a manifest/artifact identity field, record digest, batch, Merkle root, artifact digest, or consumed digest binding, does not validate.</dd>
          <dt><tt>segment_chain_mismatch</tt></dt>
          <dd>A disclosed predecessor cannot be safely resolved or fails ledger identity, commitment-profile identity, serial-continuity, or predecessor-digest validation.</dd>
          <dt><tt>channel_failure</tt></dt>
          <dd>The timestamp response is missing, invalid, or otherwise unacceptable, or its binding to the authoritative segment artifact digest fails.</dd>
          <dt><tt>insufficient_disclosure</tt></dt>
          <dd>The disclosed artifacts do not support the producer-claimed disclosure class or the asserted verification scope.</dd>
          <dt><tt>scope_not_exercised</tt></dt>
          <dd>The disclosed inputs support a stronger scope required by identified verifier policy, but the verifier intentionally exercised a weaker scope.</dd>
          <dt><tt>verifier_policy_rejection</tt></dt>
          <dd>The inputs do not satisfy an applicable local verifier policy for a reason not more specifically represented above.</dd>
        </dl>
        <t>
          An absent referenced timestamp response is reported with TSA channel
          status <tt>missing</tt> and <tt>channel_failure</tt>. An
          absent batch opening or canonical-record artifact required by the
          claimed disclosure class is <tt>insufficient_disclosure</tt>. A
          missing primary segment artifact is a bundle-processing error under
          <xref target="verification-inputs-scope"/>. If referenced bytes are present but
          fail their declared digest or commitment check, the reason is
          <tt>commitment_mismatch</tt>.
        </t>
        <t>
          A conforming result <bcp14>MUST</bcp14> use only those baseline categories in
          <tt>failure_reasons</tt>. Deployment-specific detail belongs in the
          result's <tt>extensions</tt> member; this document creates no
          extension namespace for failure-reason values. Failure reasons are
          conclusions, not a trace of internal verifier steps. A category <bcp14>MUST</bcp14>
          NOT occur more than once in one result. Failure reasons <bcp14>MUST</bcp14> be
          absent when <tt>overall</tt> is <tt>success</tt> or <tt>partial</tt>;
          TSA channel status explains a timestamp-pending partial outcome.
        </t>
        <t>
          Verifier output states the claimed disclosure class, the
          verification scope selected for the invocation, any segment-chain conclusion,
          TSA channel status, failure reasons when applicable, and
          whether the resulting claim is public recompute, partial
          verification, or anchor-only evidence.
        </t>
        </section>
        <section numbered="true" toc="exclude" anchor="overall-outcome">
          <name>Overall Outcome</name>
        <t>
          Overall outcome is determined after checking whether the disclosed
          artifacts satisfy the producer-claimed disclosure class, applying
          the validations required by the scope actually exercised and by
          verifier policy, and determining TSA channel status. A
          <tt>chain_status</tt> of <tt>predecessor_not_disclosed</tt> does not
          by itself degrade the outcome; it makes no chain-adjacency claim.
          A <tt>chain_status</tt> of <tt>failed</tt> makes the overall outcome
          <tt>failure</tt>.
        </t>
        <t>
          The following decision table is normative. A verifier <bcp14>MUST</bcp14> evaluate
          every applicable row; <tt>failure</tt> takes precedence over
          <tt>partial</tt>, and <tt>partial</tt> takes precedence over
          <tt>success</tt>. Extension data is not a channel under this profile
          and <bcp14>MUST NOT</bcp14> affect this evaluation.
        </t>
        <table>
          <name>Overall Outcome Decision Table</name>
          <thead>
            <tr>
              <th>Condition</th>
              <th>Additional condition</th>
              <th>Overall</th>
              <th>Failure reason</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>A required structural, commitment, chain, disclosure, artifact-reference, or external-binding validation failed.</td>
              <td>Any</td>
              <td><tt>failure</tt></td>
              <td>The applicable baseline category</td>
            </tr>
            <tr>
              <td>The verifier intentionally exercised a weaker supported scope.</td>
              <td>The stronger scope is required.</td>
              <td><tt>failure</tt></td>
              <td><tt>scope_not_exercised</tt></td>
            </tr>
            <tr>
              <td>The verifier intentionally exercised a weaker supported scope.</td>
              <td>The stronger scope is not required.</td>
              <td><tt>partial</tt></td>
              <td>None</td>
            </tr>
            <tr>
              <td>The baseline TSA channel is <tt>failed</tt> or <tt>missing</tt>.</td>
              <td>Any</td>
              <td><tt>failure</tt></td>
              <td><tt>channel_failure</tt></td>
            </tr>
            <tr>
              <td>The baseline TSA channel is validly <tt>pending</tt>.</td>
              <td>Every other applicable requirement succeeded.</td>
              <td><tt>partial</tt></td>
              <td>None</td>
            </tr>
            <tr>
              <td>The TSA channel is <tt>verified</tt> and every other required validation succeeded.</td>
              <td>All applicable requirements succeeded.</td>
              <td><tt>success</tt></td>
              <td>None</td>
            </tr>
          </tbody>
        </table>
        <t>
          A manifest claim of <tt>present</tt> without the required
          <tt>tsa_tsr</tt> reference, or of <tt>pending</tt> or
          <tt>unavailable</tt> with a <tt>tsa_tsr</tt> reference, is
          structurally invalid and is rejected at the primary-input boundary
          without a verifier result. If a required <tt>tsa_tsr</tt>
          reference is present but cannot be safely resolved, the TSA channel status is
          <tt>missing</tt> and the overall outcome is <tt>failure</tt> with
          <tt>channel_failure</tt>.
        </t>
        <t>
          Every verifier result <bcp14>MUST</bcp14> include a non-empty
          <tt>verifier_policy_id</tt> that stably identifies the complete policy
          applied to the invocation. That
          policy includes RFC 3161 trust anchors, accepted TSA policy
          identifiers, revocation policy, algorithm constraints,
          generation-time constraints, future-skew constraints, and the rules
          for accepting a producer <tt>pending</tt> claim. A result <bcp14>MAY</bcp14> include
          <tt>verifier_policy_sha256</tt> only when the corresponding policy
          artifact is available to the verifier or otherwise discoverable. The
          digest <bcp14>MUST</bcp14> be SHA-256 over the exact policy-artifact bytes. A bare
          policy digest is not sufficient policy identification.
        </t>
        <t>
          Verifier output <bcp14>MUST NOT</bcp14> be represented as proving more than the
          exercised verification scope. The scope caveat in
          <xref target="disclosure-bundles"/> applies to every result.
        </t>
        </section>

        <section numbered="true" toc="exclude" anchor="chain-claim-composition">
          <name>Chain-Claim Composition</name>
          <t>
            A producer manifest and its corresponding verifier result cover one
            authoritative segment artifact. A relying party claiming continuous
            chaining across a disclosed range <bcp14>MUST</bcp14> have one validated
            producer-manifest/verifier-result pair for every segment in that
            range. Every pair <bcp14>MUST</bcp14> carry the same <tt>ledger_id</tt> and
            <tt>commitment_profile_id</tt> under their applicable exact-comparison
            rules, and segment numbers <bcp14>MUST</bcp14> be contiguous.
          </t>
          <t>
            The first result <bcp14>MUST</bcp14> have <tt>chain_status</tt> equal to
            <tt>epoch</tt>, or equal to <tt>validated</tt> after validation
            against its disclosed predecessor. Every later result <bcp14>MUST</bcp14> have
            <tt>chain_status</tt> equal to <tt>validated</tt>. A gap, identity
            mismatch, failed link, or unavailable required predecessor prevents
            a continuous-range claim. Successful composition establishes
            continuity only across that disclosed range; it does not establish
            global dataset completeness or the absence of undisclosed ledgers.
          </t>
        </section>
      </section>
    </section>

    <section numbered="true" toc="include" anchor="disclosure-bundles">
      <name>Disclosure Classes</name>
      <t>
        Verification claims depend on what artifacts are disclosed. This
        profile defines three disclosure classes, whose manifest-shape rules
        are normative in <xref target="producer-manifest"/>.
      </t>
      <ul>
        <li><strong>Class A (Public Recompute)</strong>: sufficient material for independent record-level recomputation. A non-empty Class A bundle <bcp14>MUST</bcp14> include every complete batch opening and all canonical-record artifacts required to recompute the claimed segment root, the authoritative segment artifact, the producer manifest, and the required producer timestamp state and timestamp response when that state is <tt>present</tt>. An empty Class A bundle omits <tt>record_batches</tt> and its public recomputation validates the empty construction in <xref target="merkle-policy"/>. A public-recompute claim is invalid if required record artifacts are missing, root recomputation was not performed, the in-band profile is absent or unsupported, or a required digest validation fails.</li>
        <li><strong>Class B (Partner Audit)</strong>: controlled disclosure where some record material is withheld while commitment and timestamp artifacts remain auditable. Class B outputs <bcp14>MUST NOT</bcp14> be represented as publicly recomputable. A Class B bundle <bcp14>MUST</bcp14> include the authoritative segment artifact, the producer manifest, the required producer timestamp state and timestamp response when present, and a non-empty proper subset of complete batch openings; it <bcp14>MAY</bcp14> include a policy artifact describing withheld or partitioned material. Every scope composes the complete authoritative <tt>batch_roots</tt> list into <tt>segment_root</tt>. A verifier exercising <tt>partial_verification</tt> <bcp14>MUST</bcp14> recompute each consumed batch root from its disclosed record occurrences and makes no claim about unopened batch preimages. Empty and single-batch segments cannot support Class B.</li>
        <li><strong>Class C (Anchor-Only)</strong>: segment-level commitment and timestamp artifacts without record preimages or batch openings. A Class C disclosure <bcp14>MUST</bcp14> be labeled as such, <bcp14>MUST</bcp14> omit <tt>record_batches</tt>, and <bcp14>MUST NOT</bcp14> claim record-level reproducibility. A verifier exercising <tt>anchor_only</tt> can validate artifact digest binding, producer-manifest digests, chain existence, and TSA channel status. For a non-epoch segment whose predecessor artifact is not disclosed, it <bcp14>MUST</bcp14> report <tt>chain_status</tt> as <tt>predecessor_not_disclosed</tt> rather than <tt>validated</tt>.</li>
      </ul>
      <t>
        The producer claims one disclosure class in the producer manifest.
        The verifier independently reports the scope selected for its
        invocation as specified in <xref target="verification-inputs-scope"/>.
        A verifier claim <bcp14>MUST</bcp14> be limited to the disclosed artifacts and
        validation scope actually exercised.
      </t>
      <t>
        An emitted empty segment <bcp14>MAY</bcp14> be disclosed as Class A or Class C and
        <bcp14>MUST NOT</bcp14> be disclosed as Class B. Both permitted classes omit
        <tt>record_batches</tt>; the claimed class and exercised scope
        distinguish an empty public recomputation from anchor-only
        verification.
      </t>
      <t>
        Every producer manifest <bcp14>MUST</bcp14> contain the <tt>tsa</tt> member in
        <tt>anchoring</tt>, subject to the state-to-reference rules in
        <xref target="producer-manifest"/>.
      </t>
      <t>
        This scope caveat applies to every successful result: VTL establishes
        internal consistency and timestamp binding for the disclosed bundle,
        not completeness of all observed or emitted telemetry, physical truth,
        omitted device lifecycle state, or authorization for autonomous
        action or sanctions.
      </t>
    </section>

    <section numbered="true" toc="include" anchor="versioning">
      <name>Versioning</name>
      <t>
        Document revisions are editorial and do not alter commitment output by
        themselves. Schema <tt>version</tt> fields identify individual object
        shapes; neither a document revision nor a schema version substitutes
        for the <tt>commitment_profile_id</tt> defined in
        <xref target="terminology"/>.
      </t>
      <t>
        This document defines one shape each for the canonical record, segment
        record, closure policy, producer manifest, and verifier result, so
        their CDDL rule names carry no version suffix. Their local
        <tt>version</tt> fields are fixed at <tt>1</tt>, identify object syntax,
        and do not select commitment rules. A verifier that encounters an unsupported
        well-formed UUID in <tt>commitment_profile_id</tt> <bcp14>MUST</bcp14> report
        <tt>unsupported_commitment_profile</tt> rather than applying fallback
        semantics.
      </t>
      <t>
        This document defines exactly one <tt>commitment_profile_id</tt> and
        requests no IANA registry for it; see
        <xref target="iana-considerations"/>. The
        profile UUID assigned in <xref target="terminology"/> is a randomly
        generated UUIDv4 under <xref target="RFC9562"/> and is bound
        exclusively to the commitment profile specified by this document.
        Baseline producers <bcp14>MUST</bcp14> emit exactly that UUID. Verifiers <bcp14>MUST</bcp14> apply
        dispatch in this order: a missing or non-text identifier is an
        <tt>invalid_segment_artifact</tt>; a well-formed lowercase RFC 9562 UUID
        not supported by the verifier is an
        <tt>unsupported_commitment_profile</tt>; and exact string equality with
        this document's UUID selects the commitment profile defined in
        Sections 4.1 through 4.6, with structural CDDL in Appendix C.
        Implementations <bcp14>MUST NOT</bcp14> infer profile semantics
        from a schema version, media type, filename, producer manifest,
        informal profile name, or identifier parsing.
        This document defines no general or private-use namespace for
        additional values. Reusing the UUID for different rules is
        nonconformant, <bcp14>MUST NOT</bcp14> be done, and creates ambiguous verifier semantics even though the
        identifier remains bound into the authoritative segment artifact
        digest. A verifier configured, through its identified verifier policy,
        with knowledge that this UUID has been bound to rules other than those
        defined by this document <bcp14>MUST NOT</bcp14> verify artifacts carrying it under
        this profile and <bcp14>MUST</bcp14> report <tt>verifier_policy_rejection</tt>. This
        document defines no in-band signal for such a conflict; detection is
        an out-of-band policy input.
      </t>
      <t>
        Adding, removing, or changing external timestamping or attestation
        evidence without changing canonical-record bytes, commitment
        calculations, or authoritative segment artifact bytes does not require
        a new <tt>commitment_profile_id</tt>. Such evidence is outside the
        baseline unless a separate specification defines it.
      </t>
      <t>
        A future commitment profile <bcp14>MUST</bcp14> use a distinct UUID assigned and
        published by the specification that defines that profile and <bcp14>MUST</bcp14>
        begin a new ledger epoch. Under this decentralized model, neither this
        document nor IANA assigns future values; generating a fresh UUID under
        <xref target="RFC9562"/> provides the required collision resistance.
        The first
        artifact under that profile <bcp14>MUST</bcp14> use a newly generated
        <tt>ledger_id</tt>, <tt>segment_number</tt> equal to zero, and the
        all-zero predecessor value. A producer <bcp14>MUST NOT</bcp14> create a predecessor
        link across commitment profiles. Existing sealed artifacts retain
        their original identifier and semantics. Changing the UUID in a sealed
        artifact changes its exact bytes and digest and would force
        corresponding predecessor-link changes through the chain of successor
        artifacts. Such artifacts therefore <bcp14>MUST NOT</bcp14> be renamed or
        reinterpreted in place.
      </t>
      <t>
        A deployment that introduces a future commitment profile <bcp14>SHOULD</bcp14> use a
        backward-compatible rollout that preserves verification support for
        artifacts sealed under this profile. A rollback to an earlier profile
        is another profile transition and <bcp14>MUST</bcp14> also begin a new ledger epoch.
        A rollback affects only subsequently formed artifacts; it <bcp14>MUST NOT</bcp14>
        relabel or re-encode sealed artifacts, reuse a ledger identifier or
        segment number, or create a cross-profile predecessor link.
      </t>
      <t>
        This rule makes a hash, canonicalization, or tree-profile migration an
        explicit epoch boundary rather than an in-place algorithm upgrade. A
        baseline chain claim cannot span that boundary. Deployments that need
        to associate the old and new epochs require a separately authenticated
        migration statement or operational record, and verifiers need support
        for each profile whose historical artifacts they continue to accept.
        Such a migration statement is not a VTL commitment input and does not
        turn the two epochs into one baseline chain.
      </t>
    </section>

    <section numbered="true" toc="include" anchor="conformance-vectors">
      <name>Conformance Vectors</name>
      <t>
        This section is informative; normative requirements are in Sections 4
        through 8, and the known-answer vectors in
        <xref target="appendix-a"/> are normative.
      </t>
      <t>
        Vector suites begin with exact canonical-record byte strings.
        Recommended positive coverage includes the normative integer,
        floating-point, and signed-zero cases in <xref target="appendix-a"/>;
        a conforming 4096-octet record; an epoch and linked
        successor; empty intervals in both modes, including lifecycle
        exceptions; single, odd, power-of-two, and duplicate leaf counts;
        boundary assignment; policy transitions and close-reason precedence;
        restart recovery; profile migration; multi-batch composition; complete
        Class A and proper-subset Class B openings; every outcome-table row;
        deliberate down-scoping of multi-batch Class A to
        <tt>partial_verification</tt> or <tt>anchor_only</tt>; Class B to
        <tt>anchor_only</tt>; unsupported-profile reporting; malformed
        artifact bytes with independently successful timestamp validation; and the RFC
        3161 nonce, certificate-selection, and generation-time cases in
        <xref target="rfc3161-profile"/>.
      </t>
      <t>
        Recommended negative coverage includes malformed manifest segment numbers
        rejected without a verifier result; numeric identity mismatch reported
        as <tt>commitment_mismatch</tt>; every canonical-record violation;
        serial and predecessor faults; incorrect boundary assignment; invalid
        empty-mode and policy transitions; tree and batch faults; malformed
        openings; Class B over an empty or single-batch segment;
        <tt>partial_verification</tt> over either such segment, reported as
        <tt>insufficient_disclosure</tt>; invalid TSA state/reference
        combinations rejected without a result; missing policy identity or TSA
        channel; unsafe references; malformed artifacts that incorrectly force
        successful independent timestamp validation to be reported as failed; unsupported UUIDs misclassified as
        malformed; unacceptable pending claims; a timestamp token over
        <tt>segment_root</tt>; double-hashed imprints; and every RFC 3161
        status, nonce, token, attribute, and certificate violation, including
        <tt>grantedWithMods</tt>.
      </t>
      <t>
        General close-reason accuracy is a producer-side test requiring a
        controlled elapsed-time source and injected closure conditions.
        Recommended cross-implementation checks use a fake elapsed-time source and
        injected persistence failures, verify byte-for-byte parity across at
        least two independent implementations, and carry the applicable
        <tt>commitment_profile_id</tt>.
      </t>
    </section>

    <section numbered="true" toc="include" anchor="operations">
      <name>Operational Considerations</name>
      <t>
        This section follows <xref target="RFC5706"/>. Deployments <bcp14>SHOULD</bcp14>
        expose admission, sealing, timestamp submission, timestamp issuance completion,
        retention, and verification as distinct states so delayed issuance is
        not confused with a malformed artifact.
      </t>
      <t anchor="ops-health">
        Operators <bcp14>SHOULD</bcp14> monitor canonical-record handoff, validation,
        admission and durability failures; ledger identity, sequence state,
        fencing, and serial conflicts; elapsed-timer health, closure delay,
        reason, and policy revision; encoding and size rejection; artifact
        writes, digests, and roots; RFC 3161 backlog, reachability, delay, and
        per-segment status; and storage pressure. Signals <bcp14>SHOULD</bcp14> be structured
        and machine-readable with stable event codes and sufficient
        correlation data. Uncertain handoff, durability, sequence, or timer
        continuity <bcp14>SHOULD</bcp14> be reported explicitly and does not become a
        baseline verifier-result field.
      </t>
      <t>
        Deployments <bcp14>SHOULD</bcp14> document the supported record size, admission
        backpressure, durable-write behavior, closure policy, retention,
        accepted TSA identities and policies, generation-time and skew
        constraints, and verifier policy. Effective defaults and overrides
        <bcp14>SHOULD</bcp14> be visible. Configuration rollback <bcp14>MUST</bcp14> follow the interval
        transition rules and <bcp14>MUST NOT</bcp14> mutate sealed artifacts, reuse a serial,
        or conceal a chain discontinuity.
      </t>
      <t>
        For <tt>N</tt> records and batch limit <tt>B</tt>, the artifact carries
        <tt>ceil(N/B)</tt> roots. Each 32-octet root requires 34 CBOR octets
        before array overhead; 100000 records with <tt>B = 1024</tt> produce
        98 roots and approximately 3332 octets before array and fixed-field
        overhead. Larger batches reduce artifact size but enlarge the minimum
        Class B disclosure unit. RFC 3161 request rate is one per emitted
        segment, so <tt>interval_ms</tt> and <tt>empty_mode</tt> directly
        determine TSA load.
      </t>
      <t anchor="ops-fault-results">
        Operators <bcp14>SHOULD</bcp14> periodically verify a recent representative bundle
        and alert on failures, timestamp issuance pending beyond policy, and admission,
        timer, serial, fencing, or artifact-write faults. A policy-accepted
        pending claim yields TSA channel status <tt>pending</tt> and overall
        <tt>partial</tt>; a rejected pending claim, <tt>unavailable</tt>
        producer timestamp state, or unavailable referenced response yields
        <tt>missing</tt>, <tt>channel_failure</tt>, and overall
        <tt>failure</tt>.
      </t>
      <t>
        Before first admission, an operator <bcp14>SHOULD</bcp14> durably provision a fresh
        <tt>ledger_id</tt>, validate closure policy, configure verifier policy
        and TSA trust inputs, and prequalify the TSA against
        <xref target="rfc3161-profile"/>. Long-lived deployments can use an
        external renewal profile such as <xref target="RFC4998"/>. This
        document defines no management data model, event-code registry, or
        management-protocol binding.
      </t>
    </section>

    <section numbered="true" toc="include" anchor="iana-considerations">
      <name>IANA Considerations</name>
      <t>This document has no IANA actions.</t>
      <t>
        The <tt>application/vnd.vtl.segment+cbor</tt> and
        <tt>application/vnd.vtl.manifest+json</tt> vendor-tree media types used
        by this document were submitted separately under the procedures of
        <xref target="RFC6838"/> and are currently under Expert Review. Their
        registrations are not actions requested as part of publishing this
        document; the normative references to those types in Sections 4.5 and
        5.1 depend on the separate registrations completing. No specialized
        media type is requested for verifier results,
        which use <tt>application/json</tt>.
      </t>
      <t>
        This document requests no CBOR tag, CoAP Content-Format, or IANA
        registry for <tt>commitment_profile_id</tt>. The fixed identifier is a
        randomly generated UUIDv4 under <xref target="RFC9562"/> and does not
        require central allocation. The absence of a registry does not provide
        discovery of conflicting third-party semantic bindings; that residual
        issue is addressed in <xref target="security-profile-confusion"/>. A
        future registry requires a separate specification defining its
        registration policy. This explicit no-action statement follows
        <xref target="RFC8126"/>.
      </t>
    </section>

    <section numbered="true" toc="include" anchor="security">
      <name>Security Considerations</name>
      <t>
        This profile introduces no new cryptographic primitives. Its security
        depends on a byte-preserving handoff, deterministic commitment
        encoding, trustworthy admission and elapsed-time handling, accurate
        verifier reporting, and disciplined artifact and timestamp-artifact handling. Its
        tamper-evidence properties assume the collision and second-preimage
        resistance of SHA-256 and the soundness of the RFC 9162 construction
        as specialized here. Threats are stated in the style of
        <xref target="RFC3552"/>. Unless stated otherwise, success establishes
        only internal consistency with this profile and successful timestamp
        validation.
      </t>
      <t anchor="security-object-paths">
        <em>Bundle paths and object authentication.</em> The formats contain no
        executable content or intrinsic compression, but provide no
        confidentiality. A manifest directs a verifier to bundle-relative
        paths, creating traversal, indirection, and substitution risks.
        Verifiers <bcp14>MUST</bcp14> use the safe resolver in
        <xref target="portable-artifact-references"/>; a pathname check
        followed by an independent open is unsafe. A timestamp over the
        artifact authenticates neither the manifest nor the result.
      </t>
      <t anchor="security-sequence">
        <em>Sequence rollback, fork, and truncation.</em> An attacker or failed
        multi-writer deployment can reuse or roll back a serial, emit
        conflicting artifacts, substitute a predecessor, or disclose only a
        chain fragment. Fresh ledger identity, fencing, contiguous serials,
        and predecessor-digest validation detect conflicts when the relevant
        artifacts are disclosed but do not prove global completeness. In the
        terminology of <xref target="RFC9416"/>, <tt>ledger_id</tt> is a
        dynamically selected identifier that must remain unique while
        evidence can be compared. Operators <bcp14>SHOULD</bcp14> audit its generation and
        alert on reuse of a ledger or ledger/serial pair.
      </t>
      <t anchor="security-producer-compromise">
        <em>Producer compromise and upstream substitution.</em> A compromised
        producer or handoff can fabricate, suppress, substitute, or misassign
        byte strings. VTL makes outputs tamper-evident only after commitment.
        Upstream transport, replay, credentials, decryption, mapping, and
        parsing are outside this document; successful verification <bcp14>MUST NOT</bcp14> be
        reported as validating those properties. Each admission is a distinct
        occurrence, so a replay is indistinguishable here from a genuine
        repeated observation.
      </t>
      <t anchor="security-profile-confusion">
        <em>Canonicalization, profile, and metadata confusion.</em> An attacker
        can exploit differences in CBOR validation, re-encoding, occurrence
        handling, or tree composition, or present metadata that does not match
        the artifact. Fixed syntax and encoding, exact-octet hashing, the
        authoritative artifact, its in-band profile binding, and identity
        comparison mitigate these attacks. With no profile registry, this
        document provides no discovery mechanism for a third party assigning
        different rules to the same UUID. Verifiers obtain mappings from
        identified policy, and deployments accepting unoperated producers
        <bcp14>SHOULD</bcp14> pin the expected identifier.
      </t>
      <t anchor="security-root-substitution">
        <em>Artifact mutation and root transplantation.</em> Independent
        artifact-digest recomputation detects mutation or substitution. Bare
        leaves and roots omit ledger, serial, and profile identity, so
        identical multisets produce identical roots across ledgers. A verifier
        or relying party <bcp14>MUST NOT</bcp14> substitute a bare leaf, batch root, or
        <tt>segment_root</tt> for authoritative-artifact and external-binding
        validation.
      </t>
      <t anchor="security-channel-downgrade">
        <em>Timestamp withholding, downgrade, and meaning.</em> An attacker can
        delay or withhold timestamp responses, present pending placeholders as final, or
        exploit ignored missing responses. The status vocabulary and outcome
        table constrain these cases. Successful validation depends on the TSA
        key and trust anchors: a key holder can mint a well-formed token over
        any digest and asserted <tt>genTime</tt>. Revocation policy <bcp14>SHOULD</bcp14>
        define later-compromise reevaluation and historical validation across
        key rotation. Validation proves only that bound bytes existed no later
        than the asserted time under configured policy; it proves neither
        producer or source identity nor when the segment opened.
      </t>
      <t anchor="security-timestamp-meaning">
        When a nonce-free response is disclosed without <tt>tsa_req</tt>, a
        verifier cannot determine whether the original request contained a
        nonce. Baseline success then validates the signed response and
        artifact-digest binding but provides no request-response
        nonce-correlation assurance and does not establish producer compliance
        with request-side nonce obligations.
      </t>
      <t anchor="security-segment-policy">
        <em>Elapsed-time and policy manipulation.</em> An attacker can alter
        the interval, elapsed-time source, policy, close reason, or boundary
        processing. Committing the snapshot and reason makes the claim
        tamper-evident after sealing, but does not prove honest elapsed time.
        False upstream UTC values likewise remain false admitted values; UTC
        changes <bcp14>MUST NOT</bcp14> affect membership or reopen a sealed segment.
      </t>
      <t anchor="security-resource-exhaustion">
        <em>Resource exhaustion.</em> Producers need input-size limits, rate
        controls, and backpressure. Before allocating or recursing, verifiers
        <bcp14>MUST</bcp14> enforce configured limits on lengths, depth, collection sizes,
        records, batches, DER objects, certificates, and total work using
        checked arithmetic. A limit preventing acquisition or sufficient
        parsing before the invocation boundary produces no result; afterward,
        rejection of an otherwise valid input solely for a policy limit <bcp14>MUST</bcp14>
        report <tt>verifier_policy_rejection</tt> with policy identity. This
        profile is not a complete denial-of-service defense.
      </t>
      <t anchor="security-verification-scope">
        <em>Scope, completeness, and disclosure.</em> Success can be misread as
        completeness, physical truth, or authorization. Results state scope,
        but stronger claims require external controls. Class B establishes
        sorting only within consumed openings and across consumed adjacent
        boundaries; anchor-only establishes none. A later Class A disclosure
        can reveal a global-sort violation without contradicting an earlier
        narrower result. Likewise, a segment with a non-conforming record can
        verify under <tt>anchor_only</tt> but <bcp14>MUST</bcp14> fail with
        <tt>invalid_canonical_record</tt> under any later
        <tt>public_recompute</tt> or <tt>partial_verification</tt> that consumes
        that record.
      </t>
      <t anchor="security-withheld-guessing">
        <em>Guessing, correlation, and metadata.</em> Leaf hashes are unsalted.
        Disclosed low-entropy material and any future individual leaf hashes
        permit offline guessing. A high-entropy application-layer nonce can
        help, but is outside this profile. Because batches are contiguous
        sorted slices, an opening bounds earlier and later unopened hashes;
        openings on both sides bound the intervening range. Deployments <bcp14>SHOULD</bcp14>
        minimize the number and sorted-order spread of openings. Identical
        <tt>segment_root</tt> values reveal identical multisets and <bcp14>MUST</bcp14> be
        considered when roots cross privacy domains.
      </t>
      <t anchor="privacy">
        Even without payloads, manifests, artifacts, timestamp artifacts, and summaries
        reveal counts, layout, outage windows, delay, intervals, close reasons,
        and emission cadence. Repeated pseudonymous identifiers can link
        records and enable re-identification. Operators <bcp14>SHOULD</bcp14> minimize
        personal data, separate identity metadata where possible, avoid
        unnecessary stable identifiers, assess Class A linkability, and apply
        suitable access and retention controls. Privacy-preserving disclosures
        <bcp14>MUST NOT</bcp14> be called publicly recomputable unless Class A conditions are
        met.
      </t>
      <t anchor="interop-notes">
        <em>Future extension points.</em> Separate specifications can define
        upstream admission, exported bundle types, SCITT or COSE publication,
        other timestamping or attestation, withheld-material disclosure, or
        other commitment profiles. Opaque extensions do not affect baseline
        results. A separate disclosure specification can staple RFC 9162 paths
        or a reduced-tree construction inspired by <xref target="RFC4998"/>;
        RFC 4998 objects are not interchangeable with VTL batch roots. Any
        change to commitment bytes or calculations requires a distinct
        <tt>commitment_profile_id</tt>.
      </t>
    </section>
  </middle>

  <back>
    <references>
        <name>Normative References</name>
      <reference anchor="RFC2119" target="https://www.rfc-editor.org/rfc/rfc2119">
        <front>
          <title>Key words for use in RFCs to Indicate Requirement Levels</title>
          <author fullname="Scott Bradner" initials="S." surname="Bradner"/>
          <date year="1997" month="March"/>
        </front>
        <seriesInfo name="BCP" value="14"/>
        <seriesInfo name="RFC" value="2119"/>
        <seriesInfo name="DOI" value="10.17487/RFC2119"/>
      </reference>
      <reference anchor="RFC8174" target="https://www.rfc-editor.org/info/rfc8174">
        <front>
          <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
          <author fullname="Barry Leiba" initials="B." surname="Leiba"/>
          <date year="2017" month="May"/>
        </front>
        <seriesInfo name="BCP" value="14"/>
        <seriesInfo name="RFC" value="8174"/>
        <seriesInfo name="DOI" value="10.17487/RFC8174"/>
      </reference>
      <reference anchor="RFC8949" target="https://www.rfc-editor.org/rfc/rfc8949">
        <front>
          <title>Concise Binary Object Representation (CBOR)</title>
          <author fullname="Carsten Bormann" initials="C." surname="Bormann"/>
          <author fullname="Paul Hoffman" initials="P." surname="Hoffman"/>
          <date year="2020" month="December"/>
        </front>
        <seriesInfo name="STD" value="94"/>
        <seriesInfo name="RFC" value="8949"/>
        <seriesInfo name="DOI" value="10.17487/RFC8949"/>
      </reference>
      <reference anchor="RFC9562" target="https://www.rfc-editor.org/info/rfc9562">
        <front>
          <title>Universally Unique IDentifiers (UUIDs)</title>
          <author fullname="K. Davis" initials="K." surname="Davis"/>
          <author fullname="B. Peabody" initials="B." surname="Peabody"/>
          <author fullname="P. Leach" initials="P." surname="Leach"/>
          <date year="2024" month="May"/>
        </front>
        <seriesInfo name="RFC" value="9562"/>
        <seriesInfo name="DOI" value="10.17487/RFC9562"/>
      </reference>
      <reference anchor="RFC3161" target="https://www.rfc-editor.org/rfc/rfc3161">
        <front>
          <title>Internet X.509 Public Key Infrastructure Time-Stamp Protocol (TSP)</title>
          <author fullname="C. Adams"/>
          <author fullname="P. Cain"/>
          <author fullname="D. Pinkas"/>
          <author fullname="R. Zuccherato"/>
          <date year="2001" month="August"/>
        </front>
        <seriesInfo name="RFC" value="3161"/>
        <seriesInfo name="DOI" value="10.17487/RFC3161"/>
      </reference>
      <reference anchor="RFC5035" target="https://www.rfc-editor.org/rfc/rfc5035">
        <front>
          <title>Enhanced Security Services (ESS) Update: Adding CertID Algorithm Agility</title>
          <author fullname="Jim Schaad" initials="J." surname="Schaad"/>
          <date year="2007" month="August"/>
        </front>
        <seriesInfo name="RFC" value="5035"/>
        <seriesInfo name="DOI" value="10.17487/RFC5035"/>
      </reference>
      <reference anchor="RFC5280" target="https://www.rfc-editor.org/rfc/rfc5280">
        <front>
          <title>Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile</title>
          <author fullname="David Cooper" initials="D." surname="Cooper"/>
          <author fullname="Stefan Santesson" initials="S." surname="Santesson"/>
          <author fullname="Stephen Farrell" initials="S." surname="Farrell"/>
          <author fullname="Sharon Boeyen" initials="S." surname="Boeyen"/>
          <author fullname="Russell Housley" initials="R." surname="Housley"/>
          <author fullname="Tim Polk" initials="T." surname="Polk"/>
          <date year="2008" month="May"/>
        </front>
        <seriesInfo name="RFC" value="5280"/>
        <seriesInfo name="DOI" value="10.17487/RFC5280"/>
      </reference>
      <reference anchor="RFC5652" target="https://www.rfc-editor.org/rfc/rfc5652">
        <front>
          <title>Cryptographic Message Syntax (CMS)</title>
          <author fullname="Russ Housley" initials="R." surname="Housley"/>
          <date year="2009" month="September"/>
        </front>
        <seriesInfo name="STD" value="70"/>
        <seriesInfo name="RFC" value="5652"/>
        <seriesInfo name="DOI" value="10.17487/RFC5652"/>
      </reference>
      <reference anchor="RFC5816" target="https://www.rfc-editor.org/rfc/rfc5816">
        <front>
          <title>ESSCertIDv2 Update for RFC 3161</title>
          <author fullname="Stefan Santesson" initials="S." surname="Santesson"/>
          <author fullname="Nick Pope" initials="N." surname="Pope"/>
          <date year="2010" month="March"/>
        </front>
        <seriesInfo name="RFC" value="5816"/>
        <seriesInfo name="DOI" value="10.17487/RFC5816"/>
      </reference>
      <reference anchor="RFC8610" target="https://www.rfc-editor.org/rfc/rfc8610">
        <front>
          <title>Concise Data Definition Language (CDDL): A Notational Convention to Express CBOR and JSON Data Structures</title>
          <author fullname="Carsten Bormann" initials="C." surname="Bormann"/>
          <author fullname="Paul Hoffman" initials="P." surname="Hoffman"/>
          <date year="2019" month="June"/>
        </front>
        <seriesInfo name="RFC" value="8610"/>
        <seriesInfo name="DOI" value="10.17487/RFC8610"/>
      </reference>
      <reference anchor="RFC9162" target="https://www.rfc-editor.org/rfc/rfc9162">
        <front>
          <title>Certificate Transparency Version 2.0</title>
          <author fullname="B. Laurie"/>
          <author fullname="E. Messeri"/>
          <author fullname="R. Stradling"/>
          <date year="2021" month="December"/>
        </front>
        <seriesInfo name="RFC" value="9162"/>
        <seriesInfo name="DOI" value="10.17487/RFC9162"/>
      </reference>
      <reference anchor="RFC8259" target="https://www.rfc-editor.org/rfc/rfc8259">
        <front>
          <title>The JavaScript Object Notation (JSON) Data Interchange Format</title>
          <author fullname="Tim Bray" initials="T." surname="Bray"/>
          <date year="2017" month="December"/>
        </front>
        <seriesInfo name="STD" value="90"/>
        <seriesInfo name="RFC" value="8259"/>
        <seriesInfo name="DOI" value="10.17487/RFC8259"/>
      </reference>
      <reference anchor="FIPS180-4" target="https://doi.org/10.6028/NIST.FIPS.180-4">
        <front>
          <title>Secure Hash Standard (SHS)</title>
          <author>
            <organization>National Institute of Standards and Technology</organization>
          </author>
          <date year="2015" month="August"/>
        </front>
        <seriesInfo name="FIPS PUB" value="180-4"/>
        <seriesInfo name="DOI" value="10.6028/NIST.FIPS.180-4"/>
      </reference>
    </references>

    <references>
        <name>Informative References</name>
      <reference anchor="RFC6838" target="https://www.rfc-editor.org/info/rfc6838">
        <front>
          <title>Media Type Specifications and Registration Procedures</title>
          <author fullname="Ned Freed" initials="N." surname="Freed"/>
          <author fullname="John Klensin" initials="J." surname="Klensin"/>
          <author fullname="Tony Hansen" initials="T." surname="Hansen"/>
          <date year="2013" month="January"/>
        </front>
        <seriesInfo name="BCP" value="13"/>
        <seriesInfo name="RFC" value="6838"/>
        <seriesInfo name="DOI" value="10.17487/RFC6838"/>
      </reference>
      <reference anchor="RFC8126" target="https://www.rfc-editor.org/info/rfc8126">
        <front>
          <title>Guidelines for Writing an IANA Considerations Section in RFCs</title>
          <author fullname="Michelle Cotton" initials="M." surname="Cotton"/>
          <author fullname="Barry Leiba" initials="B." surname="Leiba"/>
          <author fullname="Thomas Narten" initials="T." surname="Narten"/>
          <date year="2017" month="June"/>
        </front>
        <seriesInfo name="BCP" value="26"/>
        <seriesInfo name="RFC" value="8126"/>
        <seriesInfo name="DOI" value="10.17487/RFC8126"/>
      </reference>
      <reference anchor="RFC5706" target="https://www.rfc-editor.org/info/rfc5706">
        <front>
          <title>Guidelines for Considering Operations and Management of New Protocols and Protocol Extensions</title>
          <author fullname="David Harrington" initials="D." surname="Harrington"/>
          <date year="2009" month="November"/>
        </front>
        <seriesInfo name="RFC" value="5706"/>
        <seriesInfo name="DOI" value="10.17487/RFC5706"/>
      </reference>
      <reference anchor="RFC6234" target="https://www.rfc-editor.org/info/rfc6234">
        <front>
          <title>US Secure Hash Algorithms (SHA and SHA-based HMAC and HKDF)</title>
          <author fullname="Donald Eastlake 3rd" initials="D." surname="Eastlake 3rd"/>
          <author fullname="Tony Hansen" initials="T." surname="Hansen"/>
          <date year="2011" month="May"/>
        </front>
        <seriesInfo name="RFC" value="6234"/>
        <seriesInfo name="DOI" value="10.17487/RFC6234"/>
      </reference>
      <reference anchor="RFC9416" target="https://www.rfc-editor.org/info/rfc9416">
        <front>
          <title>Security Considerations for Transient Numeric Identifiers Employed in Network Protocols</title>
          <author fullname="Fernando Gont" initials="F." surname="Gont"/>
          <author fullname="Ivan Arce" initials="I." surname="Arce"/>
          <date year="2023" month="July"/>
        </front>
        <seriesInfo name="BCP" value="72"/>
        <seriesInfo name="RFC" value="9416"/>
        <seriesInfo name="DOI" value="10.17487/RFC9416"/>
      </reference>
      <reference anchor="RFC9052" target="https://www.rfc-editor.org/info/rfc9052">
        <front>
          <title>CBOR Object Signing and Encryption (COSE): Structures and Process</title>
          <author fullname="Jim Schaad" initials="J." surname="Schaad"/>
          <date year="2022" month="August"/>
        </front>
        <seriesInfo name="STD" value="96"/>
        <seriesInfo name="RFC" value="9052"/>
        <seriesInfo name="DOI" value="10.17487/RFC9052"/>
      </reference>
      <reference anchor="RFC9943" target="https://www.rfc-editor.org/info/rfc9943">
        <front>
          <title>An Architecture for Trustworthy and Transparent Digital Supply Chains</title>
          <author fullname="Henk Birkholz" initials="H." surname="Birkholz"/>
          <author fullname="Antoine Delignat-Lavaud" initials="A." surname="Delignat-Lavaud"/>
          <author fullname="Cédric Fournet" initials="C." surname="Fournet"/>
          <author fullname="Yogesh Deshpande" initials="Y." surname="Deshpande"/>
          <author fullname="Steve Lasker" initials="S." surname="Lasker"/>
          <date year="2026" month="June"/>
        </front>
        <seriesInfo name="RFC" value="9943"/>
        <seriesInfo name="DOI" value="10.17487/RFC9943"/>
      </reference>
      <reference anchor="RFC4998" target="https://www.rfc-editor.org/info/rfc4998">
        <front>
          <title>Evidence Record Syntax (ERS)</title>
          <author fullname="T. Gondrom" initials="T." surname="Gondrom"/>
          <author fullname="R. Brandner" initials="R." surname="Brandner"/>
          <author fullname="U. Pordesch" initials="U." surname="Pordesch"/>
          <date month="August" year="2007"/>
        </front>
        <seriesInfo name="RFC" value="4998"/>
        <seriesInfo name="DOI" value="10.17487/RFC4998"/>
      </reference>
      <reference anchor="RFC3552" target="https://www.rfc-editor.org/rfc/rfc3552">
        <front>
          <title>Guidelines for Writing RFC Text on Security Considerations</title>
          <author fullname="Eric Rescorla" initials="E." surname="Rescorla"/>
          <author fullname="B. Korver"/>
          <date year="2003" month="July"/>
        </front>
        <seriesInfo name="BCP" value="72"/>
        <seriesInfo name="RFC" value="3552"/>
        <seriesInfo name="DOI" value="10.17487/RFC3552"/>
      </reference>
      <reference anchor="RFC8785" target="https://www.rfc-editor.org/rfc/rfc8785">
        <front>
          <title>JSON Canonicalization Scheme (JCS)</title>
          <author fullname="Anders Rundgren" initials="A." surname="Rundgren"/>
          <author fullname="B. Jordan"/>
          <author fullname="S. Erdtman"/>
          <date year="2020" month="June"/>
        </front>
        <seriesInfo name="RFC" value="8785"/>
        <seriesInfo name="DOI" value="10.17487/RFC8785"/>
      </reference>
    </references>


    <section numbered="true" toc="include" anchor="appendix-a">
      <name>Compact Commitment Known-Answer Vectors</name>
      <t>
        Wrapped hexadecimal values in this appendix are presentation-only; a
        verifier or implementer obtains each exact value by concatenating
        adjacent lines without inserting whitespace.
      </t>
      <t>
        The following normative canonical-record vectors differ only in the
        final <tt>payload</tt> item. They demonstrate that the integer
        <tt>1</tt>, floating-point <tt>1.0</tt>, positive floating-point zero,
        and negative floating-point zero retain distinct deterministic
        encodings and produce distinct leaf hashes.
      </t>
      <sourcecode type="text"><![CDATA[
integer_1_record =
  87014800000000000000010100f60001
integer_1_leaf =
  61d6b5be58a51d90b833cc8f2558d3b0e30a0c41cae971a81a92596013ca4e5c

float_1_record =
  87014800000000000000010100f600f93c00
float_1_leaf =
  793c53c545002c8b872ff84d1f479c1243f36e4ba57dbc8b387ec52c47fe62df

positive_zero_record =
  87014800000000000000010100f600f90000
positive_zero_leaf =
  5cd7c34a8083929449188288272e339f87fe06f64738b2f8f84a2c317ee40c27

negative_zero_record =
  87014800000000000000010100f600f98000
negative_zero_leaf =
  a45dabed6caf13fe4901f9bd596325e65e13d006dbb1ec8f1180b671537ffccb
]]></sourcecode>
      <t>
        The following compact known-answer vector is normative for the profile
        UUID defined in <xref target="terminology"/>. Hexadecimal values are
        lowercase and unprefixed. It encodes the epoch segment: the outer
        segment uses <tt>segment_number = 0</tt>, and
        <tt>prev_segment_sha256</tt> is a 32-octet all-zero byte string. The
        segment uses <tt>batch_record_limit = 2</tt> and carries two aligned
        subtree roots.
      </t>
      <t>
        <tt>segment_cbor</tt> is 462 octets and commits three leaves in two
        aligned batch subtrees. <tt>segment_sha256</tt> is SHA-256 over those
        exact <tt>segment_cbor</tt> octets. It is the authoritative artifact
        digest submitted using RFC 3161 and carried by a successor's
        <tt>prev_segment_sha256</tt>; it is not an additional field encoded in
        this artifact.
      </t>
      <sourcecode type="text"><![CDATA[
record_1 =
  87014800000000000000010100f600f6
leaf_1 =
  b83bc27f2d8be3a66373af24e6af3eeffff99ff0696ae18c70e379e853796d26
record_2 =
  87014800000000000000020201f600f6
leaf_2 =
  b5227357cf5d0619914971d8dc5218c5a99260bc5d5e1b60cb1083a911a2acaf
record_3 =
  87014800000000000000030302f600f6
leaf_3 =
  4f82e3e7ee90a111774dd951471a31d4582e0908a0bd5fd63c0080c0231f40cc

sorted_leaves =
  4f82e3e7ee90a111774dd951471a31d4582e0908a0bd5fd63c0080c0231f40cc
  b5227357cf5d0619914971d8dc5218c5a99260bc5d5e1b60cb1083a911a2acaf
  b83bc27f2d8be3a66373af24e6af3eeffff99ff0696ae18c70e379e853796d26
batch_0_root =
  554491e4edf28061622396b83a870db4652211557127c664c6be1c4ad66471ff
batch_1_root =
  b83bc27f2d8be3a66373af24e6af3eeffff99ff0696ae18c70e379e853796d26
segment_root =
  bc6502552ed0c515f58d1c632e54db37594042609b59838eb0d5b3d5842aa054

segment_cbor =
  aa6776657273696f6e01696c65646765725f6964782062376131643565343063
  366634333865396137356462323763393666333161616b62617463685f726f6f
  7473825820554491e4edf28061622396b83a870db4652211557127c664c6be1c
  4ad66471ff5820b83bc27f2d8be3a66373af24e6af3eeffff99ff0696ae18c70
  e379e853796d266c636c6f73655f726561736f6e68696e74657276616c6c7265
  636f72645f636f756e74036c7365676d656e745f726f6f745820bc6502552ed0
  c515f58d1c632e54db37594042609b59838eb0d5b3d5842aa0546e636c6f7375
  72655f706f6c696379a66776657273696f6e016a656d7074795f6d6f64656873
  757070726573736b696e74657276616c5f6d731a05265c006c7265636f72645f
  6c696d6974f67073697a655f6c696d69745f6279746573f67262617463685f72
  65636f72645f6c696d6974026e7365676d656e745f6e756d6265720073707265
  765f7365676d656e745f73686132353658200000000000000000000000000000
  00000000000000000000000000000000000075636f6d6d69746d656e745f7072
  6f66696c655f6964782463303861646534652d313738352d346562362d393634
  382d623730303364373632383864
segment_sha256 =
  2672cb72d5f06863110af1b30660c7e5ba495c0b2ce7d084b0436e010e99388d

three_identical_record_1_root =
  05ddc48e556d67534bf7960a70209696ca9eeb6f18d5595358e7f4804ec87701
four_identical_record_1_root =
  d5d26faa3f54d81d8173700a48d9286179c9d35685d464183a99b1e966f1dfd8
]]></sourcecode>
      <t>
        The following 394-octet artifact is the empty successor to the segment
        above. It uses the same ledger, policy, and profile, sets
        <tt>segment_number</tt> to 1 and <tt>prev_segment_sha256</tt> to the
        preceding <tt>segment_sha256</tt>, and exercises the lifecycle
        exception in which an empty <tt>shutdown</tt> artifact retains
        <tt>empty_mode</tt> equal to <tt>suppress</tt>. Its empty
        <tt>batch_roots</tt> array and <tt>segment_root</tt> equal to SHA-256
        over zero octets are normative.
      </t>
      <sourcecode type="text"><![CDATA[
empty_shutdown_suppress_segment_cbor =
  aa6776657273696f6e01696c65646765725f6964782062376131643565343063
  366634333865396137356462323763393666333161616b62617463685f726f6f
  7473806c636c6f73655f726561736f6e6873687574646f776e6c7265636f7264
  5f636f756e74006c7365676d656e745f726f6f745820e3b0c44298fc1c149afb
  f4c8996fb92427ae41e4649b934ca495991b7852b8556e636c6f737572655f70
  6f6c696379a66776657273696f6e016a656d7074795f6d6f6465687375707072
  6573736b696e74657276616c5f6d731a05265c006c7265636f72645f6c696d69
  74f67073697a655f6c696d69745f6279746573f67262617463685f7265636f72
  645f6c696d6974026e7365676d656e745f6e756d6265720173707265765f7365
  676d656e745f73686132353658202672cb72d5f06863110af1b30660c7e5ba49
  5c0b2ce7d084b0436e010e99388d75636f6d6d69746d656e745f70726f66696c
  655f6964782463303861646534652d313738352d346562362d393634382d6237
  30303364373632383864
empty_shutdown_suppress_segment_sha256 =
  cde8b546adc5afa446195bb9cc4e519d4bd1c9529d1678bf6e076ef6d24e229e
]]></sourcecode>
      <t>
        <tt>three_identical_record_1_root</tt> and
        <tt>four_identical_record_1_root</tt> are <tt>segment_root</tt> values
        for segments containing respectively three and four occurrences of the
        exact <tt>record_1</tt> bytes. They are independent of
        <tt>batch_record_limit</tt>; that field changes the aligned subtree
        representation, not the RFC 9162 reduction of the complete sorted leaf
        multiset.
      </t>
      <t>
        A published machine-readable vector set can carry exact canonical
        bytes, digests, expected roots, and the applicable
        <tt>commitment_profile_id</tt>. The exact known-answer vectors in this
        appendix are normative.
      </t>
    </section>

    <section numbered="true" toc="include" anchor="appendix-b">
      <name>Producer Manifest and Verifier Result CDDL</name>
      <t>
        This appendix defines the Concise Data Definition Language
        (CDDL) (<xref target="RFC8610"/>) shape for the producer manifest and
        the separate verifier result. It captures the
        verification surface described here and
        provides explicit containers for deployment-specific additions.
        Producer manifests and verifier results <bcp14>MUST</bcp14> be UTF-8 JSON texts under
        <xref target="RFC8259"/>. Parsers <bcp14>MUST</bcp14> reject duplicate object member
        names; generators <bcp14>MUST NOT</bcp14> emit them.
      </t>
      <t>
        The producer manifest and verifier result each carry
        <tt>version</tt> equal to <tt>1</tt>. Neither value is independently
        negotiated and neither is part of the schema rule name.
      </t>
      <t>
        Baseline failure reasons are defined in
        <xref target="failure-reasons"/>. Extension member keys and their
        semantics are defined by the applicable extension specification or
        deployment and are opaque to baseline verification.
      </t>
      <t>
        The producer manifest's <tt>commitment_profile_id</tt> is a generic
        <tt>tstr</tt> so that a manifest can repeat a future or unsupported
        artifact value. It <bcp14>MUST</bcp14> exactly equal the authoritative artifact's
        in-band text value. Baseline producers conforming to this document
        <bcp14>MUST</bcp14> emit the UUID defined here; the generic structural type does not
        relax that baseline requirement.
      </t>
      <t>
        The verifier result's <tt>commitment_profile_id</tt> is optional because
        a malformed authoritative segment artifact might not be decodable far
        enough to recover it. When the artifact field is decodable as a text
        string, the result <bcp14>MUST</bcp14> include and exactly echo that value. It is a
        generic <tt>tstr</tt> so that a result can report
        <tt>unsupported_commitment_profile</tt> without replacing the
        unsupported artifact value with this document's UUID.
      </t>
      <t>
        <tt>chain_status</tt> <bcp14>MUST</bcp14> be present whenever the authoritative
        segment artifact can be decoded far enough to make one of the chain
        conclusions defined here. It <bcp14>MUST</bcp14> be absent otherwise, and absence
        makes no chain claim. Its value is <tt>epoch</tt> only after the epoch
        segment's serial and zero predecessor have been validated; <tt>validated</tt>
        only after a disclosed non-epoch predecessor and its linkage have
        been validated; <tt>predecessor_not_disclosed</tt> when that artifact
        is unavailable; and <tt>failed</tt> when an attempted chain validation
        fails. <tt>failure_reasons</tt> <bcp14>MUST</bcp14> be present and non-empty exactly
        when <tt>overall</tt> is <tt>failure</tt>. The sole TSA channel result is
        <tt>tsa</tt>, whose validation profile is defined by
        <xref target="rfc3161-profile"/>.
      </t>
      <t>
        The <tt>relative-path</tt> rule below is intentionally structural. RFC
        8610 regular expressions use the XML Schema dialect and cannot
        portably express all cross-platform path and filesystem-containment
        checks. Implementations <bcp14>MUST</bcp14> apply the semantic path rules in
        <xref target="portable-artifact-references"/> to every consumed path-
        bearing object, including extensions.
        Those rules include backslash, drive-prefix, colon, control-
        character, dot-component, containment, and safe-resolver checks.
      </t>
      <t>
        <tt>segment_cbor</tt> is universally required. For a non-empty segment,
        a Class A producer manifest <bcp14>MUST</bcp14> contain openings for every batch in
        <tt>record_batches</tt>; for an empty segment it <bcp14>MUST</bcp14> omit that member.
        Class B <bcp14>MUST</bcp14> contain a non-empty proper subset and is invalid for an
        empty segment. Class C <bcp14>MUST</bcp14> omit <tt>record_batches</tt>. JSON
        projections, standalone digest files,
        TSA-info projections, and operational summaries are not baseline
        producer manifest fields.
      </t>
      <t>
        For a producer manifest claiming Class A, B, or C,
        <tt>anchoring</tt> <bcp14>MUST</bcp14> contain exactly <tt>tsa</tt>. A baseline
        producer manifest therefore identifies producer timestamp state for every
        emitted segment.
      </t>
      <t>
        A <tt>tsa</tt> state of <tt>pending</tt> or <tt>unavailable</tt> <bcp14>MUST</bcp14>
        omit <tt>tsa_tsr</tt>.
        A state of <tt>present</tt> requires <tt>tsa_tsr</tt>.
        Violating either direction of the state/<tt>tsa_tsr</tt> rule makes the
        producer manifest structurally invalid. Whether a response contains a
        nonce is learned only by inspecting the timestamp response: a
        nonce-bearing response without <tt>tsa_req</tt> is therefore a
        timestamp-channel verification failure, not a manifest-structure
        error. A producer that used a
        nonce-bearing request has the additional retention, disclosure, and
        response-acceptance obligations in
        <xref target="rfc3161-profile"/>. When a required reference is present
        but its bytes cannot be safely obtained, the verifier reports
        <tt>missing</tt> as specified in <xref target="overall-outcome"/>.
      </t>
      <t>
        The <tt>channels</tt> map <bcp14>MUST</bcp14> contain exactly the <tt>tsa</tt> key. A
        channel <tt>reason</tt> is human-readable diagnostic text.
        <tt>issuance_pending</tt> is the only baseline machine-defined reason
        token; every other reason string is free text and is not a portable
        machine-actionable code. A <tt>reason</tt> member is required when the
        TSA channel status is <tt>pending</tt>, <tt>missing</tt>, or
        <tt>failed</tt>, and optional when it is <tt>verified</tt>.
        Extension containers are opaque and <bcp14>MUST NOT</bcp14> add channel keys or alter
        a baseline status or overall outcome.
      </t>
      <t>
        <tt>segment_number</tt> is a JSON string containing the shortest
        unsigned base-10 representation of a uint64: <tt>0</tt>, or a digit
        from <tt>1</tt> through <tt>9</tt> followed by zero or more digits. Its
        numeric value <bcp14>MUST NOT</bcp14> exceed 18446744073709551615. This avoids loss
        of precision in JSON implementations whose exact integer range ends at
        2^53-1. The lexical rules for <tt>relative-path</tt>,
        <tt>uint64-decimal</tt>, <tt>json-hex32</tt>, and
        <tt>json-hex64</tt> are normative prose constraints in addition to the
        structural CDDL. <tt>json-hex32</tt> is exactly
        32 lowercase hexadecimal characters, and <tt>json-hex64</tt> is exactly
        64 lowercase hexadecimal characters. Prose also governs finite-float
        validation, deterministic CBOR encoding, text-only CBOR map keys,
        class-to-artifact requirements, producer timestamp state-to-artifact
        dependencies, extension names, and all other
        cross-field requirements that this structural CDDL cannot express.
      </t>
      <sourcecode type="cddl"><![CDATA[
producer-manifest = {
  "version": 1,
  "ledger_id": json-hex32,
  "segment_number": uint64-decimal,
  "commitment_profile_id": tstr,
  "disclosure_class": disclosure-class,
  "artifacts": artifacts,
  "anchoring": anchoring,
  ? "extensions": { * tstr => json-data },
}

artifacts = {
  "segment_cbor": artifact-ref,
  ? "predecessor_segment_cbor": artifact-ref,
  ? "record_batches": [+ record-batch-opening],
  ? "tsa_req": artifact-ref,
  ? "tsa_tsr": artifact-ref,
  ? "extensions": { * tstr => artifact-ref }
}

record-batch-opening = {
  "batch_number": uint64-decimal,
  "records": [+ artifact-ref]
}

artifact-ref = {
  "path": relative-path,
  "sha256": json-hex64
}

anchoring = {
  "tsa": producer-tsa-state
}

producer-tsa-state = {
  "status": "present" / "pending" / "unavailable"
}

verifier-result = {
  "version": 1,
  "artifact_sha256": json-hex64,
  "manifest_sha256": json-hex64,
  ? "commitment_profile_id": tstr,
  "claimed_disclosure_class": disclosure-class,
  "verification_scope":
    "public_recompute" / "partial_verification" / "anchor_only",
  ? "chain_status": chain-status,
  "channels": channels,
  "verifier_policy_id": non-empty-tstr,
  ? "verifier_policy_sha256": json-hex64,
  "overall": "success" / "partial" / "failure",
  ? "failure_reasons": [+ baseline-failure-reason],
  ? "extensions": { * tstr => json-data }
}

chain-status =
  "epoch" /
  "validated" /
  "predecessor_not_disclosed" /
  "failed"

baseline-failure-reason =
  "unsupported_commitment_profile" /
  "invalid_canonical_record" /
  "invalid_segment_artifact" /
  "commitment_mismatch" /
  "segment_chain_mismatch" /
  "channel_failure" /
  "insufficient_disclosure" /
  "scope_not_exercised" /
  "verifier_policy_rejection"

channels = { "tsa": verifier-tsa-result }

verifier-tsa-result =
  {
    "status": "verified",
    ? "reason": tstr,
    ? "extensions": { * tstr => json-data }
  } /
  {
    "status": "pending" / "missing" / "failed",
    "reason": tstr,
    ? "extensions": { * tstr => json-data }
  }

disclosure-class = "A" / "B" / "C"
relative-path = tstr
uint64-decimal = tstr
json-hex32 = (tstr .regexp "[0-9a-f]{32}") .size 32
json-hex64 = (tstr .regexp "[0-9a-f]{64}") .size 64
non-empty-tstr = tstr .size (1..18446744073709551615)
json-data =
  ; For JSON null; finite-float restrictions are normative prose.
  nil / bool / int / float / tstr /
  [* json-data] / { * tstr => json-data }
]]></sourcecode>
    </section>

    <section numbered="true" toc="include" anchor="appendix-c">
      <name>Authoritative Segment Artifact CDDL</name>
      <t>
        This appendix gives the structural CDDL for the authoritative
        segment artifact. The lexical and cross-field requirements in
        <xref target="segment-artifact-schema"/>, the encoding rules in
        <xref target="cbor-profile"/>, the commitment-tree and empty-segment
        rules in <xref target="merkle-policy"/>, the formation rules in
        <xref target="segment-formation"/>, and the chain rules in
        <xref target="segment-chaining"/> are normative in addition to this
        structural shape.
      </t>
      <t>
        The <tt>tstr</tt> shape for <tt>commitment_profile_id</tt> does not
        relax the baseline producer requirement: a baseline producer <bcp14>MUST</bcp14> emit
        the profile UUID defined in <xref target="terminology"/>. The generic
        structural type permits a verifier to distinguish a well-formed but
        unsupported UUID as specified in <xref target="versioning"/>.
      </t>
      <t>
        The <tt>cbor-hex32</tt> rule is distinct from the JSON rule in
        <xref target="appendix-b"/> and is exactly 32 lowercase hexadecimal
        characters. Commitment digests and Merkle roots are 32-octet byte
        strings in the authoritative CBOR artifact. CDDL cannot express the
        power-of-two restriction or the upper bound of 2^63 on
        <tt>batch_record_limit</tt>; both normative prose constraints apply in
        addition to <tt>power-of-two-uint64</tt>.
      </t>
      <sourcecode type="cddl"><![CDATA[
segment-record = {
  "version": 1,
  "commitment_profile_id": tstr,
  "ledger_id": cbor-hex32,
  "segment_number": uint64,
  "closure_policy": segment-closure-policy,
  "close_reason": close-reason,
  "prev_segment_sha256": sha256-value,
  "record_count": uint64,
  "batch_roots": [* sha256-value],
  "segment_root": sha256-value
}

segment-closure-policy = {
  "version": 1,
  "interval_ms": positive-uint64,
  "batch_record_limit": power-of-two-uint64,
  "record_limit": positive-uint64 / nil,
  "size_limit_bytes": positive-uint64 / nil,
  "empty_mode": "emit" / "suppress"
}

close-reason =
  "interval" /
  "reconfigure" /
  "record_limit" /
  "size_limit" /
  "shutdown" /
  "recovery" /
  "manual"

uint64 = 0..18446744073709551615
positive-uint64 = 1..18446744073709551615
power-of-two-uint64 = positive-uint64
cbor-hex32 = (tstr .regexp "[0-9a-f]{32}") .size 32
sha256-value = bstr .size 32
]]></sourcecode>
    </section>

    <section numbered="false" toc="include" anchor="acknowledgments">
      <name>Acknowledgments</name>
      <t>
        The author thanks Joe Clarke for OPSDIR review feedback that improved
        the operational considerations and deployment guidance.
      </t>
    </section>
  </back>
</rfc>
