<?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-11"
     xml:lang="en"
     tocInclude="true"
     tocDepth="3"
     symRefs="true"
     sortRefs="true"
     version="3">
  <front>
    <title abbrev="VTL">Verifiable Telemetry Ledgers</title>
    <seriesInfo name="Internet-Draft" value="draft-elkhatabi-verifiable-telemetry-ledgers-11"/>
    <author fullname="Bilal El Khatabi" initials="B." surname="El Khatabi">
      <organization>Independent</organization>
      <address>
        <postal>
          <city>Rabat</city>
          <country>Morocco</country>
        </postal>
        <email>elkhatabibilal@gmail.com</email>
      </address>
    </author>
    <date year="2026" month="September" day="6"/>

    <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
        their admission into 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 artifact digest through a
        required external timestamp channel. Segment closure uses a
        deployment-configured elapsed-time interval and does not depend on
        calendar dates.
      </t>
      <t>
        The profile enables independent recomputation and audit of disclosed
        evidence from the admitted bytes onward. Transport framing, decryption,
        anti-replay processing, payload interpretation, and
        source-telemetry-to-record mapping are outside it, as are device
        onboarding, end-to-end security of sensor values, and 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 much
        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 the timestamp
        artifacts are mutually consistent. This profile standardizes the second
        question only.
      </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>
        Segment intervals are ledger batching rules, not source-reporting
        periods or civil-time claims. Segment membership follows admission into
        intervals governed by a non-decreasing elapsed-time source; timestamps
        carried in records do not select membership
        (<xref target="segment-normal-timing"/>).
      </t>
      <t>
        The profile boundary is admission of an already-formed
        canonical-record byte string. This document specifies admission and the
        subsequent commitment, disclosure, and verification of those bytes.
      </t>

      <section numbered="true" toc="include" anchor="admission-audit-example">
        <name>Example: From Admission to Audit</name>
        <t>
          This informative example shows why the machinery in the rest of this
          document exists. It is illustrative only; every rule it depends on is
          specified normatively later.
        </t>
        <t>
          A factory gateway admits sensor readings as canonical-record byte
          strings throughout the day. At each interval boundary it fixes the
          membership of a segment. It then hashes the exact admitted bytes,
          sorts the resulting leaf hashes, computes a segment root, seals a
          segment artifact naming the ledger, the segment's serial number, its
          closure claim, and the digest of its predecessor, and submits SHA-256
          over the artifact bytes to a Timestamp Authority.
        </t>
        <t>
          Months later a customer disputes one shipment. For this example, the
          disputed readings fall within two batches of a segment containing
          several batches. The operator does not want to disclose all the
          segment's telemetry, so it supplies a producer manifest, the segment
          artifact, its predecessor artifact, the timestamp response, and
          any request required for nonce correlation, along with complete
          openings for those two batches. Because batches are slices of the
          sorted leaf-hash list, those openings also disclose any unrelated
          records in the same batches.
        </t>
        <t>
          The auditor recomputes the two batch roots from the disclosed record
          bytes, checks that the artifact's complete list of batch roots
          composes to the committed segment root, confirms that the timestamp
          token binds the exact artifact bytes, and validates the artifact's
          link to its predecessor.
        </t>
        <t>
          The auditor's result then says exactly that much: the two disclosed
          batches were recomputed and matched, the artifact existed no later
          than the timestamp under the auditor's stated policy, and the
          predecessor link held. It claims nothing about the batches that were
          not opened, nothing about whether the readings were true, and nothing
          about whether other segments exist.
        </t>
        <t>
          Disclosing some batches but not all is one of three disclosure levels
          a producer can claim. They are defined normatively in
          <xref target="disclosure-bundles"/>; in outline:
        </t>
        <ul spacing="compact">
          <li><strong>Class A</strong> discloses everything needed to recompute
          the whole segment.</li>
          <li><strong>Class B</strong> discloses complete selected batches, so
          a partner can check that material against the commitment without
          seeing the rest.</li>
          <li><strong>Class C</strong> discloses the segment artifact without
          record openings; successful verification requires valid timestamp
          evidence.</li>
        </ul>
        <t>
          What a producer discloses and what a verifier actually checks are
          separate throughout this document. A Class A bundle does not by
          itself mean anyone performed full recomputation, and a successful
          narrower check makes no claim about unopened records. Every verifier
          result states the scope it exercised, and that scope bounds what the
          result asserts.
        </t>
      </section>

      <section numbered="true" toc="include" anchor="relationship-ietf-work">
        <name>Relationship to Existing Work</name>
        <t>
          VTL reuses the Merkle Tree Hash construction of
          <xref target="RFC9162"/> to commit a producer-local segment. It
          defines no Certificate Transparency log, transparency service, public
          append-only log, statement-registration protocol, receipt, inclusion
          or consistency proof, gossip protocol, or log-auditing API. Unlike
          Certificate Transparency, VTL sorts leaf hashes before reduction and
          so commits to a multiset rather than an append-ordered sequence: the
          root is independent of admission order and supports no append-order,
          prefix, or consistency claim between partial snapshots. Chaining
          orders sealed artifacts, not records within a segment.
        </t>
        <t>
          The SCITT architecture in <xref target="RFC9943"/> defines signed
          statements, registration with transparency services, and receipts;
          <xref target="RFC9052"/> defines COSE signing and encryption
          structures. Neither is used by the VTL baseline: the authoritative
          artifact is not a COSE object and no producer signature is required. A
          separate specification can publish or wrap VTL artifacts through
          either without altering the rules defined here.
        </t>
      </section>

      <section numbered="false" toc="exclude" anchor="profile-boundary-figure">
        <name>Profile Boundary</name>
        <t>
          The following informative figure shows the profile boundary and the
          artifact and timestamp flows used for baseline verification.
        </t>
        <figure anchor="arch-flow">
        <name>VTL Profile Boundary and Processing Flow</name>
        <artset>
          <artwork type="svg" align="center"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="384" width="552" viewBox="0 0 552 384" class="diagram" text-anchor="middle" font-family="monospace" font-size="13px" stroke-linecap="round">
              <title>VTL profile boundary and processing flow</title>
              <desc>Source telemetry passes through an upstream admission system before exact canonical-record bytes cross the VTL profile boundary. The ledger producer creates an authoritative segment artifact and submits its digest to a Timestamp Authority. The verifier receives the artifact and timestamp response.</desc>
              <path d="M 8,64 L 8,112" fill="none" stroke="black"/>
              <path d="M 8,176 L 8,240" fill="none" stroke="black"/>
              <path d="M 56,32 L 56,56" fill="none" stroke="black"/>
              <path d="M 64,288 L 64,320" fill="none" stroke="black"/>
              <path d="M 120,96 L 120,168" fill="none" stroke="black"/>
              <path d="M 120,240 L 120,280" fill="none" stroke="black"/>
              <path d="M 120,320 L 120,352" fill="none" stroke="black"/>
              <path d="M 176,288 L 176,320" fill="none" stroke="black"/>
              <path d="M 240,64 L 240,112" fill="none" stroke="black"/>
              <path d="M 240,176 L 240,240" fill="none" stroke="black"/>
              <path d="M 456,288 L 456,368" fill="none" stroke="black"/>
              <path d="M 544,192 L 544,368" fill="none" stroke="black"/>
              <path d="M 8,64 L 240,64" fill="none" stroke="black"/>
              <path d="M 8,112 L 240,112" fill="none" stroke="black"/>
              <path d="M 8,142 L 376,142" fill="none" stroke="black"/>
              <path d="M 8,146 L 376,146" fill="none" stroke="black"/>
              <path d="M 8,176 L 240,176" fill="none" stroke="black"/>
              <path d="M 240,192 L 544,192" fill="none" stroke="black"/>
              <path d="M 8,240 L 240,240" fill="none" stroke="black"/>
              <path d="M 64,288 L 176,288" fill="none" stroke="black"/>
              <path d="M 456,288 L 544,288" fill="none" stroke="black"/>
              <path d="M 64,320 L 176,320" fill="none" stroke="black"/>
              <path d="M 120,352 L 160,352" fill="none" stroke="black"/>
              <path d="M 328,352 L 448,352" fill="none" stroke="black"/>
              <path d="M 456,368 L 544,368" fill="none" stroke="black"/>
              <polygon class="arrowhead" points="552,280 540,274.4 540,285.6" fill="black" transform="rotate(90,544,280)"/>
              <polygon class="arrowhead" points="456,352 444,346.4 444,357.6" fill="black" transform="rotate(0,448,352)"/>
              <polygon class="arrowhead" points="128,280 116,274.4 116,285.6" fill="black" transform="rotate(90,120,280)"/>
              <polygon class="arrowhead" points="128,168 116,162.4 116,173.6" fill="black" transform="rotate(90,120,168)"/>
              <polygon class="arrowhead" points="64,56 52,50.4 52,61.6" fill="black" transform="rotate(90,56,56)"/>
              <g class="text">
                <text x="68" y="20">Source telemetry</text>
                <text x="312" y="68">OUTSIDE VTL</text>
                <text x="120" y="84">Upstream admission system</text>
                <text x="68" y="100">auth, replay</text>
                <text x="172" y="100">projection</text>
                <text x="244" y="132">exact canonical-record bytes</text>
                <text x="460" y="148">profile boundary</text>
                <text x="396" y="180">authoritative segment artifact</text>
                <text x="80" y="196">Ledger producer</text>
                <text x="104" y="212">admit, assign, commit</text>
                <text x="76" y="228">seal and chain</text>
                <text x="192" y="260">artifact digest</text>
                <text x="124" y="308">TSA</text>
                <text x="500" y="308">Verifier</text>
                <text x="244" y="356">timestamp artifact</text>
              </g>
            </svg></artwork>
          <artwork type="ascii-art" align="center"><![CDATA[
Source telemetry
      |
      v
.----------------------------.   OUTSIDE VTL
| Upstream admission system  |
| auth, replay, projection   |
'-------------+--------------'
              | exact canonical-record bytes
==============+================================ profile boundary
              v
.----------------------------.    authoritative segment artifact
| Ledger producer            +-------------------------------------.
| admit, assign, commit      |                                     |
| seal and chain             |                                     |
'-------------+--------------'                                     |
              | artifact digest                                    |
              v                                                    v
       .-------------.                                  .----------.
       |     TSA     |                                  |          |
       '------+------'                                  | Verifier |
              |                                         |          |
              '----- timestamp artifact --------------->+          |
                                                        '----------'
]]></artwork>
        </artset>
        </figure>
      </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>
      <dl newline="false" spacing="normal">
        <dt>Upstream admission system:</dt>
        <dd>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.</dd>

        <dt>Canonical-record byte string:</dt>
        <dd>The exact deterministic-CBOR byte string presented at the profile
        boundary and admitted as one commitment input. "Canonical" describes
        its byte encoding, not its physical truth or upstream derivation.</dd>

        <dt>Commitment profile:</dt>
        <dd>An immutable set of rules for validating canonical-record bytes and
        constructing commitment outputs, selected by
        <tt>commitment_profile_id</tt>. This document assigns the UUIDv4
        <tt>c08ade4e-1785-4eb6-9648-b7003d76288d</tt>; identifier handling is
        specified in <xref target="versioning"/>.</dd>

        <dt>Ledger:</dt>
        <dd>An ordered chain of segment artifacts identified by one
        <tt>ledger_id</tt>. Segment numbers are scoped to that identifier.</dd>

        <dt>Ledger epoch:</dt>
        <dd>The lifetime of one ledger sequence under one
        <tt>ledger_id</tt>. Its first segment is number zero and carries the
        all-zero predecessor value.</dd>

        <dt>Segment:</dt>
        <dd>The multiset of canonical-record occurrences assigned to one
        emitted interval. It can be empty when the profile permits emission of
        an empty interval.</dd>

        <dt>Admission linearization point:</dt>
        <dd>The serialization point at which one exact record is accepted and
        assigned to the open interval. It is not a wall-clock instant.</dd>

        <dt>Boundary-logic resolution:</dt>
        <dd>The smallest difference between elapsed-time readings that the
        producer's interval-boundary logic can distinguish.</dd>

        <dt>Closed-unsealed interval:</dt>
        <dd>Internal producer state whose membership, policy snapshot, close
        reason, counts, and serial allocation are durably fixed but whose
        artifact is not yet durably persisted.</dd>

        <dt>Authoritative segment artifact:</dt>
        <dd>The deterministic-CBOR record for one emitted segment and the
        cryptographic source of truth for its verification. It is referenced by
        <tt>artifacts.segment_cbor</tt> and is also called the segment artifact.</dd>

        <dt>Projection:</dt>
        <dd>Any non-authoritative representation derived from an authoritative
        segment artifact.</dd>

        <dt>Producer manifest:</dt>
        <dd>A non-authoritative JSON object that claims a disclosure class and
        identifies disclosed artifacts, their digests, and producer timestamp
        state.</dd>

        <dt>Verifier result:</dt>
        <dd>The verifier-authored output reporting exercised scope, chain
        conclusion, TSA channel status, overall outcome, and failure reasons.
        It is neither a commitment input nor a producer claim.</dd>

        <dt>Evidence bundle:</dt>
        <dd>The producer manifest and disclosed artifacts presented to a
        verifier as one unit.</dd>

        <dt>Bundle root:</dt>
        <dd>The single logical container relative to which every manifest path
        is resolved. It can be a directory, archive, object-store prefix, or
        equivalent closed namespace.</dd>

        <dt>Safe resolver:</dt>
        <dd>A resolver that confines every consumed object to the bundle root
        and prevents substitution between resolution and consumption.</dd>

        <dt>Disclosure class:</dt>
        <dd>The level of artifact disclosure claimed by the producer, as
        defined in <xref target="disclosure-bundles"/>.</dd>

        <dt>Verification scope:</dt>
        <dd>The validation boundaries a verifier actually exercised and
        asserts in its result.</dd>

        <dt>Verifier policy:</dt>
        <dd>The complete identified set of local inputs governing scope, TSA
        trust and validation, resource limits, and other policy decisions.</dd>

        <dt>Primary-input boundary:</dt>
        <dd>The point at which the verifier-result contract begins, as defined
        in <xref target="verification-inputs-scope"/>.</dd>

        <dt>Bundle-processing error:</dt>
        <dd>A rejection before the primary-input boundary. This document
        defines no verifier-result object for it.</dd>

        <dt>Baseline producer:</dt>
        <dd>A producer claiming the conformance defined in
        <xref target="baseline-conformance"/>.</dd>

        <dt>Baseline verifier:</dt>
        <dd>A verifier claiming the conformance defined in
        <xref target="baseline-conformance"/>.</dd>

        <dt>Baseline TSA channel:</dt>
        <dd>The mandatory timestamp channel defined in
        <xref target="rfc3161-profile"/>. Its verifier-result key is
        <tt>tsa</tt>.</dd>

        <dt>Timestamp Authority (TSA):</dt>
        <dd>An authority that issues timestamp responses over submitted
        digests.</dd>

        <dt>Timestamp artifacts:</dt>
        <dd>The exact <tt>TimeStampResp</tt> and any disclosed supporting
        <tt>TimeStampReq</tt>.</dd>
      </dl>
      <t>
        Batch subtrees and batch openings are defined where they are specified,
        in <xref target="segment-batch-subtrees"/> and
        <xref target="producer-manifest"/>.
      </t>
</section>

    <section numbered="true" toc="include" anchor="roles">
      <name>System Roles</name>
      <t>
        These roles participate at different sides of the profile boundary;
        conformance is defined in <xref target="baseline-conformance"/>. The
        <strong>upstream admission system</strong> produces canonical-record
        byte strings after deployment-specific source validation and mapping and
        is outside this profile. The <strong>ledger producer</strong> accepts
        those exact byte strings at the profile boundary, assigns them to
        serial-numbered segments, constructs segment artifacts, and submits
        their digests for timestamping; one physical gateway can implement both
        roles, but conformance begins only at the byte-level handoff. The
        <strong>verifier</strong> recomputes commitments and validates timestamp
        artifacts from disclosed bundles. The <strong>Timestamp
        Authority</strong> issues timestamp responses over artifact digests.
      </t>
    </section>

    <section numbered="true" toc="include" anchor="data-model">
      <name>Data and Commitment Model</name>
      <t>
        The input to this section is an exact canonical-record byte string
        already produced by an upstream admission system. This section covers
        admission, segment assignment, deterministic hashing and tree
        calculation, segment formation, artifact construction, and chaining.
      </t>

      <section numbered="true" toc="include" anchor="canonical-record-input">
        <name>Canonical-Record Input Boundary</name>
        <t>
          The profile input is one exact canonical-record byte string. It
          <bcp14>MUST</bcp14> encode exactly one CBOR data item using the record
          shape below and the deterministic encoding constraints in
          <xref target="cbor-profile"/>, and a ledger producer
          <bcp14>MUST</bcp14> reject an 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 and whose <tt>payload</tt> nesting depth is no
          greater than 16. Payload nesting depth is zero when <tt>payload</tt>
          is a scalar; each array or map on a path beginning at
          <tt>payload</tt> increases depth by one, the payload depth is the
          maximum over all such paths, and the outer seven-element record array
          is not counted. A producer <bcp14>MAY</bcp14> accept conforming
          records outside this shared acceptance envelope under its documented
          resource policy, but a configured maximum below either dimension does
          not satisfy baseline producer conformance. These are minimum
          acceptance capabilities for bounded-resource interoperability, not
          protocol maxima, and the octet value is not derived from a network
          MTU. A record outside the envelope is not thereby nonconforming, but a
          producer that admits one can produce bundles a conforming baseline
          verifier rejects under identified policy. An implementation
          <bcp14>MAY</bcp14> validate a byte string incrementally, but admission
          applies to one complete byte string encoding exactly one canonical
          record; an upstream system <bcp14>MAY</bcp14> instead produce multiple
          independently conforming records, each a separate admitted occurrence,
          which this profile does not treat as chunks of one record.
        </t>
        <t>
          Once admitted, the exact supplied octets are authoritative. The
          producer <bcp14>MUST</bcp14> use those octets, without modification,
          as the leaf preimage under <xref target="merkle-policy"/>, and
          <bcp14>MUST NOT</bcp14> decode and re-encode, normalize, enrich,
          remove, reorder, or otherwise substitute a different byte string. Each
          admission event contributes one record occurrence, including when two
          occurrences have identical byte strings. Source transport, framing,
          authentication, decryption, anti-replay processing,
          duplicate-submission policy, identifier and message-type mapping,
          payload interpretation, and construction of the byte string are
          upstream of this boundary and are neither specified nor verified here;
          a physical gateway <bcp14>MAY</bcp14> perform those functions and
          ledger production together, but its interoperability claim begins only
          with the exact byte string passed across this boundary.
        </t>
        <t>
          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 and do not move source-to-record mapping into this profile.
          <tt>version</tt> is the unsigned integer <tt>1</tt>;
          <tt>device_id</tt> is an opaque 8-octet identifier assigned upstream;
          <tt>fc</tt> is an unsigned upstream-supplied sequence value with no
          replay or duplicate-suppression semantics defined here;
          <tt>ingest_time</tt> is an unsigned count of whole non-leap seconds
          since <tt>1970-01-01T00:00:00Z</tt> and <tt>device_time</tt> is an
          unsigned application timestamp or <tt>null</tt> whose epoch and unit
          are upstream semantics. Neither value selects segment membership;
          <tt>kind</tt> is an unsigned application discriminator;
          and <tt>payload</tt> is one recursively restricted CBOR data item
          whose schema and meaning are outside this profile.
        </t>
        <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, as
          are positive and negative floating-point zero, whose shortest exact
          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. A different record array shape or 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 field meanings, but successful
          verification does not validate those external semantics.
        </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; and 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, including negative floating-point
          zero. The exact type, sign, and encoded-octet distinctions in
          <xref target="canonical-record-input"/> are preserved by admission and
          verification.
        </t>
        <t>
          Because this profile permits only text-string map keys in their
          preferred deterministic encodings, bytewise ordering of their encoded
          heads orders them first by UTF-8 byte length and then by encoded
          bytes, coinciding with the length-first order of Section 4.2.3 of
          <xref target="RFC8949"/>.
        </t>
        <t>
          JSON projections are optional, 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. Unless a
          rule explicitly says otherwise, every digest in this document is
          computed over the exact received or disclosed octets, and an
          implementation <bcp14>MUST NOT</bcp14> 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, this 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.
        </t>
        <t>
          Every SHA-256 invocation in this profile <bcp14>MUST</bcp14> produce
          the complete 32-octet digest; a truncated digest or a different SHA-2
          function is nonconformant. For tree hashing an implementation
          <bcp14>MUST</bcp14> use exactly the <tt>0x00</tt> leaf prefix and
          <tt>0x01</tt> internal-node prefix 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 lexicographic (bytewise) 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 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>.
          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.
        </t>
        <t>
          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. 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, and weaker scopes provide only the
          ordering assurances defined for them in
          <xref target="batch-metadata-checks"/>. 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>
          This section specifies how admitted records are assigned to logical
          intervals, how those intervals close, how durable state survives
          restart, and how the committed batch subtrees are derived.
        </t>

        <section numbered="true" toc="include" anchor="segment-normal-timing">
          <name>Normal Interval Timing and Admission</name>
          <t>
            Segment formation uses a non-decreasing producer elapsed-time source
            that <bcp14>MUST</bcp14> progress during normal operation. Its
            boundary-logic resolution <bcp14>MUST</bcp14> be no coarser than the
            smaller of 1000 milliseconds and
            <tt>closure_policy.interval_ms</tt>; finer sampling is permitted.
            The interval is a fixed positive uint64 millisecond duration and
            <bcp14>MUST NOT</bcp14> be aligned to civil-time events. The first
            interval opens when the producer durably activates the ledger, and
            reactivation resumes durable state after shutdown. Every closure
            except <tt>shutdown</tt> opens the next interval immediately.
            Intervals continue across idle periods; <tt>suppress</tt> affects
            emission and serial consumption, not the elapsed 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>: a record whose acceptance
            linearizes before <tt>T</tt> belongs to the current interval; at
            <tt>T</tt> or later the producer <bcp14>MUST</bcp14> process the
            boundary before another acceptance can linearize, so a record
            admitted at or after <tt>T</tt> belongs to the next interval even
            when its upstream processing began earlier. 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.
          </t>
          <t>
            Processing the boundary means completing the durable close
            transition in <xref target="segment-recovery"/>, not sorting leaves,
            encoding or persisting the artifact, submitting its digest, or
            obtaining a response. Deadline expiry <bcp14>MUST</bcp14> use
            checked elapsed-time subtraction, not potentially wrapping addition,
            and an unsafe elapsed-time comparison <bcp14>MUST</bcp14> invoke
            recovery before another record is accepted.
          </t>
        </section>

        <section numbered="true" toc="include" anchor="segment-policy-changes">
          <name>Policy Changes and Early Closure</name>
          <t>
            The producer <bcp14>MUST</bcp14> keep the opening-time
            <tt>closure_policy</tt> snapshot unchanged through closure. A policy
            update that can wait applies to the next interval. A reconfiguration
            request that is to take effect before the current interval would
            otherwise close makes the <tt>reconfigure</tt> condition true. The
            producer <bcp14>MUST</bcp14> close the current interval under its
            old snapshot before applying the change. When another condition is also true,
            <xref target="segment-close-reasons"/> selects the committed
            reason. Early closure is permitted only for its committed reason.
            Late processing <bcp14>MUST NOT</bcp14> move a
            post-deadline admission into the expired interval and
            <bcp14>SHOULD</bcp14> emit an operational signal as described in
            <xref target="ops-health"/>.
          </t>
          <t>
            The <tt>manual</tt> condition is true only when closure is requested
            through a producer-provided administrative interface that is not
            driven by elapsed-time, <tt>record_limit</tt>, or
            <tt>size_limit_bytes</tt> evaluation. The producer
            <bcp14>MUST NOT</bcp14> select <tt>manual</tt> without such a
            request. Whether a human operator or automation acting through that
            interface initiated it does not change the condition. The request
            <bcp14>MUST</bcp14> be serialized with admission and close under the
            current snapshot; the committed reason follows
            <xref target="segment-close-reasons"/> when multiple conditions are
            true. A manual closure opens a successor and empty emission follows
            <tt>empty_mode</tt>. <tt>shutdown</tt> closes for orderly cessation,
            <bcp14>MUST NOT</bcp14> open a successor until reactivation, and
            <bcp14>MUST</bcp14> emit and consume a serial even for an empty
            <tt>suppress</tt> interval.
          </t>
        </section>

        <section numbered="true" toc="include" anchor="segment-close-reasons">
          <name>Limits and Close-Reason Selection</name>
          <t>
            <tt>interval</tt> applies at the snapshotted deadline when no higher
            condition applies. A non-null <tt>record_limit</tt> is the maximum
            admitted count; on reaching it the producer <bcp14>MUST</bcp14>
            close the interval before another acceptance can linearize. A
            non-null <tt>size_limit_bytes</tt> is a close threshold for the
            summed admitted-record lengths; at or above it the producer
            <bcp14>MUST</bcp14> close before another acceptance. The triggering
            record remains assigned, so the field is not a pre-admission maximum
            and a single oversized record forms a one-record interval.
            Byte-count updates and comparisons <bcp14>MUST</bcp14> use checked
            arithmetic; before acknowledging an unrepresentable total the
            producer <bcp14>MUST</bcp14> enter recovery or stop acceptance.
          </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. The selected
            reason does not change which acceptances already linearized into the
            interval.
          </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>
        </section>

        <section numbered="true" toc="include" anchor="segment-empty-intervals">
          <name>Empty Intervals and Timer Continuity</name>
          <t>
            With timer continuity, <tt>emit</tt> produces an artifact for every
            interval, using the empty construction when needed. An empty
            <tt>suppress</tt> interval emits nothing and consumes no serial,
            except that <tt>shutdown</tt> and <tt>recovery</tt> always emit and
            consume one. The next artifact remains contiguous. Suppression makes
            no completeness or no-event claim.
          </t>
          <t>
            A host suspend interval counts toward the current logical interval
            when the producer's elapsed-time source advances across the suspend.
            When it does not, or when elapsed-time-source continuity is
            otherwise uncertain, recovery <bcp14>MUST</bcp14> precede another
            acceptance.
          </t>
        </section>

        <section numbered="true" toc="include" anchor="segment-recovery">
          <name>Recovery and Durable State</name>
          <t>
            Before post-restart or failover acceptance, the producer
            <bcp14>MUST</bcp14> recover ledger identity, next serial, policy,
            open state, and the ordered closed-unsealed queue. It
            <bcp14>MUST NOT</bcp14> infer an uncertain boundary from wall time;
            it <bcp14>MUST</bcp14> instead stop or close recoverable open
            material as <tt>recovery</tt>, and that closure
            <bcp14>MUST</bcp14> emit and consume a serial, including when empty
            under <tt>suppress</tt>. The producer <bcp14>MUST NOT</bcp14>
            synthesize missed historical empty artifacts. A previously fixed
            close reason <bcp14>MUST</bcp14> survive recovery;
            <tt>recovery</tt> applies only when the interval remained open or
            its open state was uncertain at failure.
          </t>
          <t>
            Admission is a durable transaction boundary: before acknowledgment
            the producer <bcp14>MUST</bcp14> atomically make the exact record,
            membership, counts, and recovery state durable or recoverable, and
            after a crash an acceptance <bcp14>MUST</bcp14> be recovered exactly
            once in the same interval or <bcp14>MUST</bcp14> be treated as never
            completed. The producer <bcp14>MUST</bcp14> serialize close with
            admission. The close transition <bcp14>MUST</bcp14> atomically
            preserve an emitting interval's exact membership, policy, reason,
            counts, allocated serial, and ordered closed-unsealed state, and
            except at shutdown <bcp14>MUST</bcp14> also make the successor state
            recoverable before an admission to that successor is acknowledged. A
            suppressed empty interval creates neither queue entry nor serial,
            except for the shutdown and recovery cases above.
          </t>
          <t>
            After close, successor admission and commitment preparation
            <bcp14>MAY</bcp14> proceed while intervals remain unsealed.
            Artifacts <bcp14>MUST</bcp14> be finalized durably in serial order
            with the exact predecessor and digest available for each non-epoch
            artifact; sealing <bcp14>MUST NOT</bcp14> alter fixed membership,
            policy, reason, counts, or serial, and <bcp14>MUST</bcp14>
            atomically preserve the artifact, digest, queue advancement, and
            timestamp-submission obligation, after which submission and response
            acquisition can be asynchronous. Open, closed-unsealed, and merely
            locally queued states have no conforming manifest: only an attempted
            submission can be <tt>pending</tt>, a usable response is
            <tt>present</tt>, a terminal attempt without one is
            <tt>unavailable</tt>, and a local job alone
            <bcp14>MUST NOT</bcp14> be represented as <tt>pending</tt>.
          </t>
          <t>
            Outstanding state <bcp14>MUST</bcp14> have finite recoverable
            capacity. Before acknowledging an admission that would exceed it the
            producer <bcp14>MUST</bcp14> apply backpressure or stop acceptance,
            and before lifecycle closures exhaust it the producer
            <bcp14>MUST</bcp14> drain or shut down. Loss of exact
            closed-unsealed state <bcp14>MUST</bcp14> stop acceptance under that
            ledger; a new epoch is permitted, but the producer
            <bcp14>MUST NOT</bcp14> skip, reuse, or fabricate material for the
            affected old-ledger serial. These are observable outcomes, not
            mandated storage calls.
          </t>
</section>

        <section numbered="true" toc="include" anchor="segment-batch-subtrees">
          <name>Deterministic Aligned Batch Subtrees</name>
          <t>
            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"/> and partition it 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, and so on; only the last batch can contain fewer
            than <tt>B</tt>. Compute each <tt>batch_roots[i]</tt> as
            <tt>VTLRoot</tt> over that batch's already-computed leaf hashes.
            This is the sole baseline batch partitioning rule and is independent of storage flushes, worker scheduling, or input-file layout. An implementation <bcp14>MAY</bcp14> obtain the required global leaf order through an order-maintaining index or external sort and reduce each aligned batch incrementally, but sorting tentative input chunks or batches independently is not equivalent and <bcp14>MUST NOT</bcp14> replace the global sort; every optimization <bcp14>MUST</bcp14> reproduce the exact commitment and artifact bytes defined here.
            Requiring a power of two makes every full batch align with a
            recursive <tt>VTLRoot</tt> split, so an aligned batch root can
            substitute directly for its subtree without an auxiliary sibling
            path.
          </t>
          <t>
            Let <tt>N</tt> be <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 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, which is a batch boundary because <tt>B</tt> is
            a power of two, recursively compose the roots before and after that
            boundary, and 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 CT wire object.
          </t>
        </section>
      </section>

      <section numbered="true" toc="include" anchor="segment-artifact-schema">
        <name>Authoritative Segment Artifact Schema</name>
        <t>
          The segment artifact is a deterministic CBOR-encoded segment record
          produced under <xref target="cbor-profile"/> and 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, and is not a transport envelope,
          publication statement, or complete verification claim. A JSON
          projection, filename, and storage path are non-authoritative, and a
          verifier <bcp14>MUST NOT</bcp14> trust a path or filename as the
          segment number. The 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. Profile dispatch follows
          <xref target="versioning"/>.
        </t>
        <t>
          The segment record contains exactly these fields:
        </t>
        <ul spacing="compact">
          <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.</li>
          <li><tt>ledger_id</tt> (tstr): 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): the immutable segment closure policy snapshot, 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>.</li>
          <li><tt>prev_segment_sha256</tt> (bstr): 32-octet SHA-256 digest of the exact bytes of the previous segment artifact, or the epoch predecessor value 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; empty for an empty emitted segment.</li>
          <li><tt>segment_root</tt> (bstr): 32-octet deterministic segment root.</li>
        </ul>
        <t>
          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>, the mandatory lifecycle artifacts that retain a
          committed <tt>suppress</tt> value; any other empty artifact under
          <tt>suppress</tt> is invalid. 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>, with
          root count, final-batch width, and composed segment root derived as in
          <xref target="segment-batch-subtrees"/>.
        </t>
        <t>
          A verifier <bcp14>MUST</bcp14> validate that the producer manifest
          <tt>segment_number</tt> is the shortest unsigned decimal form defined
          in <xref target="appendix-b"/>, parse it as a uint64, and compare that
          numeric value with the decoded CBOR uint. A non-shortest decimal form
          is a manifest schema violation and therefore a bundle-processing
          error; after a valid parse, a numeric mismatch with the artifact is
          <tt>commitment_mismatch</tt>. The artifact uses the registered
          <tt>application/cbor</tt> media type when media-type metadata is
          carried, and implementations <bcp14>SHOULD</bcp14> use
          <tt>application/vnd.vtl.segment+cbor</tt> once registered. Media-type
          metadata does not determine artifact conformance or profile selection.
        </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> and 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 SHA-256 over the exact bytes of the predecessor's 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 one with a new <tt>ledger_id</tt>.</li>
          <li>Configuration rollback follows these same transition rules and <bcp14>MUST NOT</bcp14> mutate sealed artifacts, reuse a serial, or conceal a chain discontinuity. A closure-policy change <bcp14>MUST</bcp14> take effect only in a newly opened logical interval and does not reset <tt>segment_number</tt> or <tt>ledger_id</tt>.</li>
        </ul>
        <t>
          When a new ledger 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. If durable sequence state cannot be recovered unambiguously, a
          producer <bcp14>MUST</bcp14> stop acceptance or begin a new ledger
          with a fresh identifier and <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 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 omitting 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, segment artifacts, producer
        manifests, verifier results, and timestamp artifacts in any 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. Every bundle
        claiming a disclosure class <bcp14>MUST</bcp14> disclose the segment
        artifact and a producer manifest.
      </t>

      <section numbered="true" toc="include" anchor="producer-manifest">
        <name>Producer Manifest</name>
        <t>
          The producer manifest repeats the ledger identity, segment number,
          commitment profile, claimed disclosure class, artifact digests, and
          claimed producer timestamp state; the artifact's in-band
          <tt>commitment_profile_id</tt> remains the cryptographically bound
          one. The manifest <bcp14>MUST NOT</bcp14> contain a chain conclusion,
          verifier status, failure reason, or overall outcome. Its schema is in
          <xref target="appendix-b"/> and its shape per claimed class in
          <xref target="disclosure-bundles"/>. It uses
          <tt>application/json</tt>, and
          <tt>application/vnd.vtl.manifest+json</tt> once registered, on the
          same terms as the segment artifact. Deployment-specific data can be
          carried only in explicit extension containers, whose presence
          <bcp14>MUST NOT</bcp14> alter the semantics defined here, select an
          additional evidence channel, or affect the baseline outcome.
        </t>
        <t>
          For a non-epoch segment, a predecessor is disclosed for baseline
          verification if and only if
          <tt>artifacts.predecessor_segment_cbor</tt> is present and its
          referenced bytes are safely resolved; an extension member or
          out-of-band artifact does not substitute for it or change
          <tt>chain_status</tt>.
        </t>
        <t>
          A <em>batch opening</em> is an <tt>artifacts.record_batches</tt> entry
          disclosing every canonical-record occurrence committed by the aligned
          batch subtree identified by its <tt>batch_number</tt>, permitting
          recomputation of that indexed root without disclosing other batches.
          Each nested <tt>records</tt> entry represents one admitted occurrence.
          Duplicate entries are permitted and <bcp14>MUST</bcp14> be counted
          separately; occurrences with identical bytes <bcp14>MAY</bcp14>
          reference the same disclosed artifact and a verifier
          <bcp14>MAY</bcp14> reuse a successful digest computation, but the leaf
          hash <bcp14>MUST</bcp14> contribute once per listed occurrence, and
          reference order does not assert admission order. An opening
          <bcp14>MUST</bcp14> disclose exactly the number of occurrences derived
          for that batch from <tt>record_count</tt> and
          <tt>batch_record_limit</tt>, and after hashing and sorting those exact
          octets their <tt>VTLRoot</tt> value <bcp14>MUST</bcp14> equal the
          indexed <tt>batch_roots</tt> value.
        </t>
        <t>
          Producer timestamp state is <tt>present</tt> when the 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; manifests
          <bcp14>MUST NOT</bcp14> use verifier states such as
          <tt>verified</tt> or <tt>failed</tt>. A <tt>pending</tt> or
          <tt>unavailable</tt> state <bcp14>MUST</bcp14> omit
          <tt>tsa_tsr</tt> and a <tt>present</tt> state <bcp14>MUST</bcp14>
          reference it. 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 in
          <xref target="rfc3161-profile"/>.
        </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 result states the exercised scope, any chain
          conclusion, TSA channel status, verifier-policy identifier, overall
          outcome, and failure reasons; local diagnostics are
          implementation-specific. A producer manifest and a verifier result
          <bcp14>MUST NOT</bcp14> be represented as the same object. A verifier
          <bcp14>MAY</bcp14> serialize its result as JSON; a serialized result
          claiming conformance <bcp14>MUST</bcp14> use the schema in
          <xref target="appendix-b"/> and the <tt>application/json</tt> media
          type.
        </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
          manifest artifact reference or an extension object,
          <bcp14>MUST</bcp14> satisfy this subsection. Each path is a UTF-8
          string interpreted relative to the 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, and <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. These are semantic requirements
          and do not depend on a regular-expression dialect or operating-system
          pathname behavior.
        </t>
        <t>
          Every artifact listed in the manifest <bcp14>MUST</bcp14> carry a
          lowercase hexadecimal SHA-256 digest entry. The manifest's
          <tt>ledger_id</tt>, <tt>segment_number</tt>, and
          <tt>commitment_profile_id</tt> <bcp14>MUST</bcp14> match the
          corresponding artifact fields whenever those fields can be decoded;
          segment-number comparison follows
          <xref target="segment-artifact-schema"/> and profile selection follows
          <xref target="versioning"/>. Failure mapping for unsafe or
          digest-mismatched references is given once, in
          <xref target="failure-reasons"/>.
        </t>
      </section>
    </section>

    <section numbered="true" toc="include" anchor="anchoring-verification">
      <name>Anchoring and Verification</name>
      <t>
        This section defines baseline conformance, the required timestamp
        channel, verification inputs and scopes, and the result reduction rules.
      </t>

      <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 here, construct segment
          artifacts and producer manifests under this profile, and initiate
          timestamp submission through the baseline TSA channel for every
          emitted segment. Issuance <bcp14>MAY</bcp14> remain <tt>pending</tt>
          while incomplete.
        </t>
        <t>
          A baseline verifier <bcp14>MUST</bcp14> implement this commitment
          profile and the baseline TSA channel, obtain the profile identifier
          from the segment artifact, and use the result vocabulary and fixed TSA
          channel key defined here. Every result claiming baseline conformance
          <bcp14>MUST</bcp14> contain the <tt>tsa</tt> channel key, including
          when its status is <tt>pending_claim</tt>, <tt>missing</tt>, or
          <tt>failed</tt>, and a baseline <tt>success</tt> result requires
          successful timestamp validation.
        </t>
        <t>
          A baseline verifier <bcp14>MUST</bcp14> configure finite resource
          limits for variable-length primary and secondary inputs, decoded
          collections, record and batch counts, certificate counts, and parser
          recursion. Its canonical-record length and depth limits
          <bcp14>MUST</bcp14> admit the shared acceptance envelope in
          <xref target="canonical-record-input"/>. This document defines no
          mandatory acceptance floor for the other dimensions. Rejection before
          the primary-input boundary is a bundle-processing error; rejection
          after it solely because an otherwise valid input exceeds identified
          policy uses <tt>verifier_policy_rejection</tt>.
        </t>
        <t>
          Extension data is opaque to baseline producers and verifiers, and 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 without changing the
          segment artifact or this commitment profile.
        </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 exactly this vocabulary for
          the TSA channel: <tt>verified</tt>, timestamp validation succeeded for
          the disclosed artifact binding; <tt>pending_claim</tt>, the manifest
          claims submission was attempted but no terminal response is disclosed,
          an incomplete producer claim rather than an independently verified
          fact; <tt>missing</tt>, an expected response is absent or is
          referenced but cannot be safely resolved; and <tt>failed</tt>,
          validation was attempted and did not succeed. Producer state
          <tt>pending</tt> maps deterministically to <tt>pending_claim</tt> and
          <tt>unavailable</tt> maps to <tt>missing</tt>. Baseline verification
          does not authenticate the claim or change its status based on elapsed
          time, manifest provenance, receipt context, or other out-of-band
          inputs; a later bundle disclosing a terminal response is a different
          fixed-byte input. Outcome effects are in
          <xref target="overall-outcome"/>.
        </t>
        <t>
          The TSA-result <tt>reason</tt> value is human-readable diagnostic
          text. <tt>producer_pending_claim</tt> is the 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 <tt>pending_claim</tt> result
          <bcp14>MUST</bcp14> set <tt>reason</tt> to
          <tt>producer_pending_claim</tt>; a <tt>missing</tt> or
          <tt>failed</tt> result <bcp14>MUST</bcp14> include a free-text
          <tt>reason</tt>; a <tt>verified</tt> result
          <bcp14>MUST NOT</bcp14> include one. Additional machine-readable
          detail <bcp14>MAY</bcp14> be placed in the channel result's
          <tt>extensions</tt> member and is opaque to baseline verification.
        </t>
      </section>

      <section numbered="true" toc="include" anchor="anchoring-contract">
        <name>Anchoring Contract</name>
        <t>
          A producer computes the SHA-256 digest of the segment artifact and
          submits it through the baseline TSA channel; verifiers
          <bcp14>MUST</bcp14> recompute that digest over the exact artifact
          bytes. Timestamp validation and message-imprint comparison do not
          depend on successful CBOR decoding of the artifact. A token that
          validates with the artifact digest as its message imprint binds the
          complete artifact bytes, including the in-band
          <tt>commitment_profile_id</tt>, but binds no disclosure class,
          producer manifest, verifier policy, or verifier result.
        </t>
        <t>
          Consequently, a 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 artifact. Manifest digest
          checks establish consistency with the received manifest, not its
          provenance. A relying party needing 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>
          The producer <bcp14>MUST</bcp14> seal and durably write the segment
          artifact without waiting for 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>Baseline TSA Channel</name>
        <t>
          This channel uses the timestamp protocol of
          <xref target="RFC3161"/>, as updated by <xref target="RFC5816"/> and
          restricted here. The <tt>TimeStampReq</tt>, <tt>TimeStampResp</tt>,
          and token <bcp14>MUST</bcp14> conform to those specifications, and the
          token <bcp14>MUST</bcp14> contain exactly one CMS
          <tt>SignerInfo</tt> as defined by <xref target="RFC5652"/>. These
          restrictions define a narrower channel than generic use of that
          protocol, so a conforming implementation cannot assume an arbitrary
          deployed TSA is compatible; deployments <bcp14>SHOULD</bcp14>
          prequalify a TSA before relying on it.
        </t>
        <t>
          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 segment artifact bytes, <bcp14>MUST NOT</bcp14> hash that result
          again, and <bcp14>MUST</bcp14> set <tt>certReq</tt> to <tt>TRUE</tt>.
          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>, and a
          producer receiving it <bcp14>MUST</bcp14> treat the terminal attempt
          as <tt>unavailable</tt> and <bcp14>MUST NOT</bcp14> publish that
          response as usable baseline evidence.
        </t>
        <t>
          The signed attributes <bcp14>MUST</bcp14> contain exactly one
          <tt>SigningCertificateV2</tt> attribute with exactly one value, as
          defined by <xref target="RFC5035"/>, whose first
          <tt>ESSCertIDv2.certHash</tt> <bcp14>MUST</bcp14> equal SHA-256 over
          the complete DER encoding of the selected signer certificate; a
          present <tt>hashAlgorithm</tt> <bcp14>MUST</bcp14> identify SHA-256,
          omission denoting that default, and a present <tt>issuerSerial</tt>
          <bcp14>MUST</bcp14> identify that same certificate. The signed
          attributes <bcp14>MUST NOT</bcp14> contain the legacy
          <tt>SigningCertificate</tt> attribute of <xref target="RFC2634"/>.
          Because <tt>certReq</tt> is <tt>TRUE</tt>,
          <tt>SignedData.certificates</tt> <bcp14>MUST</bcp14> contain exactly
          one X.509 certificate matching both <tt>SignerInfo.sid</tt> and that
          first <tt>ESSCertIDv2</tt>; zero or multiple matches are a
          verification failure. The set <bcp14>MAY</bcp14> also contain
          unrelated or path certificates, and a verifier
          <bcp14>MUST NOT</bcp14> rewrite a received response or reject it
          merely for containing additional nonmatching certificates.
        </t>
        <t>
          A baseline verifier <bcp14>MUST NOT</bcp14> report this channel as
          <tt>verified</tt> unless its identified verifier policy supplies
          accepted trust anchors, accepted TSA policy identifiers, revocation
          policy including acceptable evidence and the treatment of historical
          certificate status at <tt>TSTInfo.genTime</tt>, acceptable signature
          and certificate algorithms and strengths, any additional
          generation-time constraints, a maximum acceptable future skew, and the
          verifier-local time source used for that check. This document defines
          no long-term archival-PKI validation profile beyond those inputs.
          Missing policy input after the primary-input boundary is
          <tt>verifier_policy_rejection</tt>; if the identified time source is
          unavailable at runtime, validation fails, the channel status is
          <tt>failed</tt>, and the result includes <tt>channel_failure</tt>.
        </t>
        <t>
          <tt>artifacts.tsa_tsr</tt> carries the exact DER-encoded
          <tt>TimeStampResp</tt>. A verifier <bcp14>MUST</bcp14> validate those
          exact referenced bytes, <bcp14>MUST NOT</bcp14> re-encode the response
          before any digest or channel check, and <bcp14>MUST</bcp14> recompute
          the segment artifact digest. Validation <bcp14>MUST</bcp14> include:
        </t>
        <ul spacing="compact">
          <li>response status <tt>granted (0)</tt> and required token presence;</li>
          <li>the CMS <tt>id-signedData</tt> and <tt>id-ct-TSTInfo</tt> content types;</li>
          <li>exact SHA-256 message-imprint equality with the recomputed digest;</li>
          <li>the CMS signature, signed attributes, and unambiguous signer-certificate binding;</li>
          <li>the signer certificate's single critical extended-key-usage extension containing only <tt>id-kp-timeStamping</tt>;</li>
          <li>path validation under <xref target="RFC5280"/> using <tt>TSTInfo.genTime</tt> as the date/time input and configured trust anchors;</li>
          <li>configured TSA policy and certificate-validation constraints;</li>
          <li>a <tt>genTime</tt> within the signer certificate's validity interval; and</li>
          <li>the configured maximum future skew.</li>
        </ul>
        <t>
          The optional <tt>artifacts.tsa_req</tt> carries the exact DER-encoded
          <tt>TimeStampReq</tt> as a non-authoritative supporting artifact. A
          producer sending a nonce-bearing request <bcp14>MUST</bcp14> retain
          those exact bytes at least as long as the corresponding response,
          <bcp14>MUST</bcp14> disclose the request with that response, and
          <bcp14>MUST NOT</bcp14> treat a response that omits or changes its
          nonce as successful issuance. Whenever <tt>tsa_req</tt> is disclosed
          the verifier <bcp14>MUST</bcp14> validate its SHA-256 digest, require
          the request message-imprint algorithm to be SHA-256 and its
          <tt>hashedMessage</tt> to equal the recomputed artifact digest, and
          require <tt>certReq=TRUE</tt>. If either disclosed object contains a
          nonce, both <bcp14>MUST</bcp14> contain one and the values
          <bcp14>MUST</bcp14> be equal. A nonce-bearing response without
          <tt>tsa_req</tt>, a nonce present in only one object, unequal nonces,
          or any failure of these checks is a timestamp-channel verification
          failure reported with <tt>channel_failure</tt>. If the response
          carries no nonce and <tt>tsa_req</tt> is not disclosed, a verifier
          cannot determine whether the original request contained one and the
          result makes no nonce-correlation claim. Any failure of the
          validations in this section is a timestamp-channel verification
          failure; the channel status <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>
        <t>
          Verification addresses four distinct questions. The verifier result
          identifies the selected scope, reports chain and timestamp status,
          and combines applicable checks into an overall outcome.
        </t>
        <dl newline="true" spacing="normal">
          <dt>Artifact validity:</dt>
          <dd>Do the exact disclosed bytes decode as a segment artifact under a
          supported commitment profile, with internally consistent counts,
          batch roots, and segment root?</dd>
          <dt>Record recomputation:</dt>
          <dd>Do the disclosed occurrences reproduce their indexed batch roots?
          Under public recomputation, does the complete globally sorted record
          multiset also reproduce the segment root?</dd>
          <dt>Chain continuity:</dt>
          <dd>Does an epoch artifact carry the required initial values, or are
          the artifact's serial number and predecessor digest consistent with a
          disclosed predecessor?</dd>
          <dt>Timestamp validation:</dt>
          <dd>Does a timestamp token bind the exact artifact bytes under the
          identified verifier policy?</dd>
        </dl>
        <t>
          These conclusions must be distinguished. An artifact that fails to
          decode can still carry a valid timestamp over its bytes, and a valid
          timestamp establishes nothing about record contents. Verification
          therefore begins at the primary-input boundary, selects one exercised
          scope, applies the validations that scope supports, and reduces the
          resulting conclusions to the verifier-result schema. The subsections
          below fix the inputs and scope selection
          (<xref target="verification-inputs-scope"/>), the order in which
          validations are applied (<xref target="verification-procedure"/>),
          the structural and record-level checks themselves
          (<xref target="batch-metadata-checks"/> and
          <xref target="disclosed-record-validation"/>), and how conclusions reduce to
          one outcome (<xref target="failure-reasons"/> and
          <xref target="overall-outcome"/>).
        </t>

        <section numbered="true" toc="include" 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, fully parsed them as a
            UTF-8 JSON producer manifest, applied every structural, lexical, and
            manifest-only cross-field check that does not depend on the segment
            artifact, determined every mandatory result field and the exact
            <tt>artifacts.segment_cbor</tt> reference, and obtained the exact
            referenced artifact bytes. Failure to obtain either primary input,
            structurally invalid manifest bytes, a missing primary artifact
            reference, or unsafe resolution of either primary input is a
            bundle-processing error, which a verifier <bcp14>MUST</bcp14> reject
            but for which it <bcp14>MUST NOT</bcp14> emit a verifier result; it
            is outside the result schema and is not an
            <tt>insufficient_disclosure</tt> conclusion. Structurally invalid
            manifest bytes include <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 <tt>segment_number</tt> or
            <tt>batch_number</tt>; a configured resource limit preventing the
            verifier from reaching the boundary likewise produces one. After
            artifact decoding, duplicate or out-of-range batch-opening numbers
            yield <tt>insufficient_disclosure</tt>.
          </t>
          <t>
            Verifiers <bcp14>MUST</bcp14> then decode the artifact and determine
            the applicable <tt>commitment_profile_id</tt> from its in-band
            field, applying the dispatch precedence in
            <xref target="versioning"/>. When that field decodes as a text
            string the result's optional <tt>commitment_profile_id</tt>
            <bcp14>MUST</bcp14> echo its exact value, including when
            unsupported. The identifier is the semantic key for interpreting the
            artifact: a structurally well-formed artifact and successful
            timestamp validation are insufficient for semantic verification when
            it is absent or unsupported. When the exact artifact bytes are
            present but do not decode as a valid segment artifact, the result
            <bcp14>MUST</bcp14> be <tt>failure</tt> and include
            <tt>invalid_segment_artifact</tt>; the verifier
            <bcp14>MUST</bcp14> still evaluate the TSA channel independently
            over those exact bytes, and decoding failure alone
            <bcp14>MUST NOT</bcp14> cause channel status <tt>failed</tt> or
            <tt>channel_failure</tt>.
          </t>
          <t>
            The manifest's <tt>disclosure_class</tt> is the producer-claimed
            class and the result's <tt>claimed_disclosure_class</tt>
            <bcp14>MUST</bcp14> repeat it. The result's
            <tt>verification_scope</tt> identifies the scope selected for the
            invocation: <tt>public_recompute</tt> corresponds to Class A,
            <tt>disclosed_batch_recompute</tt> to Class B, and
            <tt>anchor_only</tt> to Class C, ordered from strongest to weakest.
            After satisfying the primary-input boundary the invocation
            <bcp14>MUST</bcp14> select an intended scope; selection does not
            assert support, which the verifier determines after artifact
            decoding and claimed-class shape validation, and earlier fail-fast
            termination still reports the selected scope without claiming it
            succeeded. The claimed class determines manifest shape; the selected
            scope determines which artifacts are consumed and which
            recomputation claims are made. Results <bcp14>MUST NOT</bcp14> claim
            assurances outside the exercised scope, and exercising a stronger
            scope does not rewrite the claimed class. A verifier exercising
            <tt>anchor_only</tt> <bcp14>MUST NOT</bcp14> consume
            <tt>record_batches</tt>, even when valid claimed-class shape
            requires those entries to be present, and <bcp14>MUST NOT</bcp14>
            claim record-level or batch-opening recomputation.
          </t>
          <t>
            The result's <tt>manifest_sha256</tt> <bcp14>MUST</bcp14> equal
            SHA-256 over the UTF-8 octets of the validated manifest, and
            <tt>artifact_sha256</tt> <bcp14>MUST</bcp14> equal SHA-256 over the
            referenced bytes of <tt>artifacts.segment_cbor</tt>, both under the
            exact-octet rule in <xref target="cbor-profile"/>, with
            <tt>artifact_sha256</tt> present even when those bytes are
            malformed. These fields identify the validated inputs and do not
            authenticate the result. The verifier <bcp14>MUST</bcp14> always
            compare the recomputed artifact digest with
            <tt>artifacts.segment_cbor.sha256</tt>, which checks manifest
            self-consistency only and <bcp14>MUST NOT</bcp14> be counted as a
            timestamp binding, and <bcp14>MUST</bcp14> likewise verify the
            <tt>sha256</tt> value of every other manifest reference consumed. A
            verifier <bcp14>MAY</bcp14> reuse one successful digest computation
            for repeated references to the same bytes; duplicate occurrences
            nevertheless contribute once per listed occurrence.
          </t>
</section>

        <section numbered="true" toc="include" anchor="verification-procedure">
          <name>Verification Procedure</name>
          <t>
            A verifier <bcp14>MUST</bcp14> perform every applicable validation
            required by the sections referenced below. It
            <bcp14>SHOULD</bcp14> apply them in the fail-fast order shown. This
            list summarizes ordering and does not create requirements beyond
            those referenced sections.
          </t>
          <ol spacing="compact">
            <li>Manifest shape against the claimed disclosure class (<xref target="disclosure-bundles"/>). Claimed-class requirements do not determine which valid openings a weaker selected scope consumes.</li>
            <li>Segment artifact and manifest, including repeated identity fields and the digest of every manifest reference consumed in later steps (<xref target="verification-inputs-scope"/>, <xref target="portable-artifact-references"/>).</li>
            <li>Chain status: serial zero and the zero predecessor for an epoch segment, or ledger identity, exact commitment-profile identity, contiguous serials, and <tt>prev_segment_sha256</tt> against a disclosed predecessor (<xref target="segment-chaining"/>).</li>
            <li>Structural batch validations for every scope, including <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> (<xref target="batch-metadata-checks"/>).</li>
            <li>Scope-specific record and opening validation for <tt>public_recompute</tt> or <tt>disclosed_batch_recompute</tt>, including independent recomputation of <tt>segment_root</tt> under the stronger scope (<xref target="batch-metadata-checks"/>, <xref target="disclosed-record-validation"/>).</li>
            <li>Comparison of the recomputed artifact digest with the response's <tt>messageImprint.hashedMessage</tt>, whether or not decoding succeeded; a mismatch is a timestamp-channel verification failure, and a producer <tt>pending</tt> claim lacks the external binding and yields <tt>pending_claim</tt>.</li>
            <li>Timestamp response validation and channel status (<xref target="rfc3161-profile"/>). A referenced response that is unavailable is <tt>missing</tt>; one whose validation is attempted and does not succeed is <tt>failed</tt>.</li>
          </ol>
</section>

        <section numbered="true" toc="include" 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 class; opening validation follows the selected scope.
          </t>
          <ul spacing="compact">
            <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> and <tt>batch_record_limit</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 empty-root rule in <xref target="merkle-policy"/> applies;</li>
            <li>for claimed-class shape, batch-opening numbers are unique and in range and <tt>record_batches</tt> matches <xref target="disclosure-bundles"/>;</li>
            <li>for <tt>public_recompute</tt>, every disclosed opening is consumed, contains exactly its derived number of occurrences, and has sorted recomputed leaves that reduce to the indexed batch root, and the globally sorted multiset of every disclosed occurrence reduces independently to <tt>segment_root</tt>;</li>
            <li>for <tt>disclosed_batch_recompute</tt>, every opening selected for consumption is complete and reduces to its indexed root, and the selected batch numbers form a non-empty proper subset of the authoritative batches; and</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>.</li>
          </ul>
          <t>
            The adjacent-opening comparison is required under either recompute
            scope whenever the relevant pair is consumed. A successful
            <tt>disclosed_batch_recompute</tt> result verifies the global sort
            rule only at those consumed boundaries, and Class C verifies no
            leaf-order boundary. A later <tt>public_recompute</tt> result
            exposing a global ordering violation <bcp14>MUST</bcp14> be
            <tt>failure</tt> with <tt>commitment_mismatch</tt>.
          </t>
        </section>

        <section numbered="true" toc="include" anchor="disclosed-record-validation">
          <name>Disclosed Canonical-Record Validation</name>
          <t>
            A verifier exercising <tt>public_recompute</tt> or
            <tt>disclosed_batch_recompute</tt> <bcp14>MUST</bcp14> validate
            every record artifact consumed under that scope as one exact
            canonical-record byte string before using it as a leaf preimage. The
            verifier <bcp14>MUST</bcp14> use the exact disclosed artifact bytes
            and <bcp14>MUST NOT</bcp14> reconstruct a record from source
            telemetry. 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, including the restricted payload shape.
          </t>
          <t>
            The verifier <bcp14>MUST</bcp14> hash the exact validated octets. If
            consumed bytes violate any canonical-record rule the result
            <bcp14>MUST</bcp14> be <tt>failure</tt> with
            <tt>invalid_canonical_record</tt>, even when those bytes hash to the
            leaf value the producer committed; 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>.
          </t>
          <t>
            A baseline verifier exercising either scope <bcp14>MUST</bcp14>
            accept every conforming disclosed canonical-record artifact consumed
            under that scope that lies within the shared acceptance envelope of
            <xref target="canonical-record-input"/>. It <bcp14>MAY</bcp14>
            accept conforming records outside that envelope under identified
            policy. A conforming record outside the envelope is not an
            <tt>invalid_canonical_record</tt>; rejection after the primary-input
            boundary is <tt>verifier_policy_rejection</tt>.
          </t>
        </section>

        <section numbered="true" toc="include" anchor="failure-reasons">
          <name>Failure Reasons</name>
          <t>
            A result whose <tt>overall</tt> value is <tt>failure</tt>
            <bcp14>MUST</bcp14> contain one or more machine-usable
            <tt>failure_reasons</tt> drawn only from the categories below. A
            category <bcp14>MUST NOT</bcp14> occur more than once in one result,
            and failure reasons <bcp14>MUST</bcp14> be absent when
            <tt>overall</tt> is <tt>success</tt> or <tt>incomplete</tt>.
            Deployment-specific detail belongs in <tt>extensions</tt>; this
            document creates no extension namespace for failure-reason values.
            A missing primary segment artifact is a bundle-processing error, not
            a failure reason.
          </t>
          <dl newline="false" spacing="compact">
            <dt><tt>unsupported_commitment_profile</tt>:</dt>
            <dd>The in-band profile identifier is present but unsupported.</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 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, or artifact digest, does not validate. A safely resolved reference whose bytes fail their declared digest uses this category.</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. The accompanying <tt>chain_status</tt> is <tt>failed</tt>.</dd>
            <dt><tt>channel_failure</tt>:</dt>
            <dd>The timestamp response is missing, invalid, or otherwise unacceptable, or its binding to the artifact digest fails. An absent or unsafely referenced response is reported with channel status <tt>missing</tt> and this category.</dd>
            <dt><tt>insufficient_disclosure</tt>:</dt>
            <dd>The disclosed artifacts do not support the claimed class or
            asserted scope. This includes a required batch opening or record
            artifact that is absent or cannot be safely resolved.</dd>
            <dt><tt>scope_not_exercised</tt>:</dt>
            <dd>The inputs support a stronger scope required by identified policy, but the verifier intentionally exercised a weaker one.</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>
        </section>

        <section numbered="true" toc="include" anchor="overall-outcome">
          <name>Overall Outcome</name>
          <t>
            A <tt>chain_status</tt> of <tt>predecessor_not_disclosed</tt> does
            not by itself degrade the outcome; it makes no chain-adjacency
            claim. The following reduction is normative and total after the
            primary-input boundary has been satisfied and the exercised scope
            and identified verifier policy have been fixed. A verifier
            <bcp14>MUST</bcp14> evaluate every applicable failure condition and
            include every distinct failure reason it reaches; multiple failure
            conditions can apply to one invocation, and the two terminal
            conditions apply only when no failure condition applies. Extension
            data is not a channel and <bcp14>MUST NOT</bcp14> affect this
            evaluation.
          </t>
          <table anchor="outcome-table">
            <name>Overall Outcome Reduction</name>
            <thead>
              <tr><th>Condition</th><th>Required effect</th></tr>
            </thead>
            <tbody>
              <tr><td>The in-band profile identifier is a well-formed but unsupported UUID.</td><td>Add <tt>unsupported_commitment_profile</tt>.</td></tr>
              <tr><td>After the primary-input boundary, an otherwise valid input or required validation is rejected solely by identified verifier policy, including a configured resource limit or missing required policy input.</td><td>Add <tt>verifier_policy_rejection</tt>.</td></tr>
              <tr><td>The verifier intentionally exercises a weaker supported scope when identified policy requires the stronger scope.</td><td>Add <tt>scope_not_exercised</tt>.</td></tr>
              <tr><td>A required structural, commitment, chain, disclosure, artifact-reference, canonical-record, or other non-channel validation fails.</td><td>Add every applicable baseline failure category.</td></tr>
              <tr><td>The baseline TSA channel is <tt>failed</tt> or <tt>missing</tt>.</td><td>Add <tt>channel_failure</tt>.</td></tr>
              <tr><td>One or more failure reasons were added above.</td><td>Set <tt>overall</tt> to <tt>failure</tt>.</td></tr>
              <tr><td>No failure condition applies and the channel is <tt>pending_claim</tt>.</td><td>Set <tt>overall</tt> to <tt>incomplete</tt>; <tt>failure_reasons</tt> absent.</td></tr>
              <tr><td>No failure condition applies and the channel is <tt>verified</tt>.</td><td>Set <tt>overall</tt> to <tt>success</tt>; <tt>failure_reasons</tt> absent.</td></tr>
            </tbody>
          </table>
          <t>
            Exercising a weaker supported scope has no independent outcome
            effect when identified policy does not require the stronger scope,
            though the selected scope still limits the result's claims. A
            bundle-processing error produces no result and does not enter this
            reduction.
          </t>
          <t>
            Every result <bcp14>MUST</bcp14> include a non-empty
            <tt>verifier_policy_id</tt> that stably identifies the complete
            policy applied to the invocation within the issuing verifier's
            namespace, and the same issuing verifier <bcp14>MUST NOT</bcp14>
            reuse one identifier for materially different policies. That policy
            includes trust anchors, accepted TSA policy identifiers, revocation
            policy, algorithm constraints, and generation-time and future-skew
            constraints, and baseline pending-claim reduction does not depend on
            it or on out-of-band context. When exact bytes of a corresponding
            policy artifact are available the result <bcp14>MUST</bcp14> include
            <tt>verifier_policy_sha256</tt> computed over those exact bytes;
            otherwise that member <bcp14>MAY</bcp14> be absent, and a bare
            digest is not sufficient policy identification. Verifier output
            <bcp14>MUST NOT</bcp14> be represented as proving more than the
            exercised scope.
          </t>
</section>

        <section numbered="true" toc="include" anchor="chain-claim-composition">
          <name>Chain-Claim Composition</name>
          <t>
            A manifest and its verifier result cover one segment artifact. A
            relying party claiming continuous chaining across a disclosed range
            <bcp14>MUST</bcp14> have one validated manifest/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. The first result
            <bcp14>MUST</bcp14> have <tt>chain_status</tt> equal to
            <tt>epoch</tt>, or to <tt>validated</tt> after validation against
            its disclosed predecessor, and every later result
            <bcp14>MUST</bcp14> have <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 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 is disclosed. This section is the
        single normative statement of manifest shape per claimed class. The
        producer claims one class in the manifest; the verifier independently
        reports the scope selected for its invocation
        (<xref target="verification-inputs-scope"/>).
      </t>
      <table anchor="class-table">
        <name>Disclosure Classes and Manifest Shape</name>
        <thead>
          <tr><th>Class</th><th>Required <tt>record_batches</tt> shape</th><th>Supported scope</th></tr>
        </thead>
        <tbody>
          <tr>
            <td>A (Public Recompute)</td>
            <td>Non-empty segment: <bcp14>MUST</bcp14> open every batch exactly once, with all record artifacts needed to recompute the claimed segment root. Empty segment: <bcp14>MUST</bcp14> omit.</td>
            <td><tt>public_recompute</tt> or <tt>anchor_only</tt>;
            <tt>disclosed_batch_recompute</tt> only when the artifact contains
            at least two batches</td>
          </tr>
          <tr>
            <td>B (Partner Audit)</td>
            <td><bcp14>MUST</bcp14> open a non-empty proper subset of a non-empty segment's batches, each opening complete. Empty and single-batch segments cannot support Class B.</td>
            <td><tt>disclosed_batch_recompute</tt> or weaker</td>
          </tr>
          <tr>
            <td>C (Anchor-Only)</td>
            <td><bcp14>MUST</bcp14> omit.</td>
            <td><tt>anchor_only</tt></td>
          </tr>
        </tbody>
      </table>
      <t>
        The <tt>disclosed_batch_recompute</tt> scope is supported only when the
        authoritative artifact contains at least two batches and the verifier
        consumes a non-empty proper subset of them. Selecting that scope for an
        empty or single-batch segment <bcp14>MUST</bcp14> produce
        <tt>failure</tt> with <tt>insufficient_disclosure</tt>; a verifier can
        instead select <tt>anchor_only</tt>.
      </t>
      <t>
        Every bundle <bcp14>MUST</bcp14> include the segment artifact, the
        producer manifest, and the <tt>tsa</tt> member in <tt>anchoring</tt>,
        with the response disclosed when the producer state is
        <tt>present</tt>. 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 omit <tt>record_batches</tt>, and the claimed class and
        exercised scope distinguish an empty public recomputation from
        anchor-only verification.
      </t>
      <t>
        A Class A manifest claims disclosure sufficient for
        <tt>public_recompute</tt>; it does not claim that a verifier exercised
        that scope. A missing required opening or record artifact yields
        <tt>insufficient_disclosure</tt>. A successful
        <tt>public_recompute</tt> result additionally requires complete record
        and root recomputation; unsupported profiles, invalid records, and
        digest or commitment failures use their separately defined reasons.
        Class B outputs
        <bcp14>MUST NOT</bcp14> be represented as publicly recomputable; a Class
        B bundle <bcp14>MAY</bcp14> include a policy artifact describing
        withheld material, and a verifier exercising
        <tt>disclosed_batch_recompute</tt> makes no claim about unopened batch
        preimages. Every scope composes the complete authoritative
        <tt>batch_roots</tt> list into <tt>segment_root</tt>. Class C does not
        mean without leaf hashes: a singleton batch root equals its unsalted
        leaf hash, so Class C is not a confidentiality guarantee for
        low-entropy records. A Class C disclosure <bcp14>MUST</bcp14> be labeled
        as such and <bcp14>MUST NOT</bcp14> claim record-level reproducibility.
      </t>
      <t>
        This caveat applies to every successful result: VTL establishes internal
        consistency and timestamp binding for the disclosed bundle, not
        completeness of observed or emitted telemetry, physical truth, omitted
        device lifecycle state, or authorization for autonomous action.
      </t>
    </section>

    <section numbered="true" toc="include" anchor="versioning">
      <name>Versioning</name>
      <t>
        A document revision does not select commitment semantics, and schema
        <tt>version</tt> fields identify only individual object shapes; neither
        substitutes for <tt>commitment_profile_id</tt>. 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. The first four carry a local <tt>version</tt> value
        of <tt>1</tt>; an incompatible change to one of them
        <bcp14>MUST</bcp14> increment that value and a parser
        <bcp14>MUST</bcp14> reject an unsupported one, but that needs a new
        commitment identifier only if commitment semantics also change. The
        verifier result carries no version member: it is verifier-authored
        output rather than a producer-supplied input, and the
        <tt>verifier_policy_id</tt> required by
        <xref target="overall-outcome"/> already identifies the rules under
        which it was produced. A consumer <bcp14>MUST</bcp14> interpret a
        verifier result under the member semantics defined in
        <xref target="appendix-b"/> and
        <bcp14>MUST NOT</bcp14> infer them from a version member, a media type,
        a filename, storage, or carriage; none of these are dispatch inputs.
      </t>
      <t>
        This document defines one randomly generated UUIDv4
        <tt>commitment_profile_id</tt> and requests no registry for it
        (<xref target="iana-considerations"/>). Baseline producers
        <bcp14>MUST</bcp14> emit exactly that UUID, and verifiers
        <bcp14>MUST</bcp14> apply dispatch in this order:
      </t>
      <ol spacing="compact">
        <li>a missing or non-text identifier, or a text value that is not a well-formed lowercase RFC 9562 UUID, is an <tt>invalid_segment_artifact</tt>;</li>
        <li>a well-formed lowercase UUID the verifier does not support is an <tt>unsupported_commitment_profile</tt>, and <bcp14>MUST NOT</bcp14> be classified as <tt>invalid_segment_artifact</tt> solely because it differs from this document's UUID; and</li>
        <li>exact string equality with this document's UUID selects the semantics defined here.</li>
      </ol>
      <t>
        A verifier encountering an unsupported well-formed UUID
        <bcp14>MUST</bcp14> report <tt>unsupported_commitment_profile</tt>
        rather than applying fallback semantics. The identifier selects the
        canonical-record syntax (<xref target="canonical-record-input"/>),
        deterministic byte encoding (<xref target="cbor-profile"/>), tree
        calculation (<xref target="merkle-policy"/>), aligned-subtree
        calculation (<xref target="segment-batch-subtrees"/>), artifact bytes
        (<xref target="segment-artifact-schema"/>), and chain-link calculation
        (<xref target="segment-chaining"/>). It does not select minimum-size
        capability, output-preserving scheduling or persistence, media
        registration or carriage, manifest or result schemas, or external
        evidence profiles, and implementations <bcp14>MUST NOT</bcp14> infer
        commitment semantics from those properties, a filename, a manifest, an
        informal name, or identifier parsing. No namespace for additional values
        is defined.
      </t>
      <t>
        A selected-semantic change <bcp14>MUST</bcp14> use a new identifier and
        ledger epoch; an excluded, output-preserving change does not, and the
        UUID <bcp14>MUST NOT</bcp14> be rebound. A verifier with policy
        knowledge of conflicting semantics <bcp14>MUST NOT</bcp14> use this
        profile and <bcp14>MUST</bcp14> report
        <tt>verifier_policy_rejection</tt>. A future profile
        <bcp14>MUST</bcp14> publish a distinct UUID and begin a new epoch with a
        fresh <tt>ledger_id</tt>, serial zero, and the all-zero predecessor;
        producers <bcp14>MUST NOT</bcp14> link across profiles or relabel,
        re-encode, or reinterpret sealed artifacts. Rollout
        <bcp14>SHOULD</bcp14> preserve historical verification support and
        rollback <bcp14>MUST</bcp14> begin another new epoch. A baseline chain
        claim cannot cross a profile boundary; associating epochs requires a
        separately authenticated statement that is not a VTL commitment input.
        Until RFC publication the identifier binding is provisional and
        artifacts make only an experimental Internet-Draft conformance claim.
        If the selected commitment semantics change before publication, the
        changed profile <bcp14>MUST</bcp14> use a new UUID. Publication can
        retain this UUID only if those selected semantics remain unchanged.
      </t>
</section>

    <section numbered="true" toc="include" anchor="conformance-vectors">
      <name>Conformance Vectors</name>
      <t>
        This section is informative. <xref target="appendix-a"/> supplies the
        normative commitment known-answer vectors: exact record bytes and
        numeric distinctions, leaf hashes, aligned batch roots, a segment root
        and artifact, empty lifecycle closure, and duplicate occurrences. It
        does not supply a complete protocol test suite or timestamp-response
        fixtures; a non-normative machine-readable corpus maintained with the
        draft source can carry the larger and malformed cases.
      </t>
      <t>
        A positive suite ought to cover:
      </t>
      <ul spacing="compact">
        <li>a 4096-octet record at payload depth 16 and a conforming record at
        depth 17 outside the mandatory envelope;</li>
        <li>linked and empty segments, varied and duplicate leaf counts, and a
        five-leaf, three-batch recursive composition;</li>
        <li>boundary ordering, close-reason precedence, recovery, profile
        migration, ordered closed-unsealed queues, and backpressure;</li>
        <li>Classes A through C, deliberate down-scoping, every outcome
        condition, and unsupported profiles; and</li>
        <li>one nonce-bearing valid request and response satisfying
        <xref target="rfc3161-profile"/>.</li>
      </ul>
      <t>
        A negative suite ought to cover:
      </t>
      <ul spacing="compact">
        <li>primary-input rejection and identity, record, boundary, policy,
        serial, predecessor, tree, batch, opening, and single-batch faults;</li>
        <li>sorting performed only within tentative batches;</li>
        <li>lost or relabeled closed state, omitted mandatory empty
        <tt>shutdown</tt> or <tt>recovery</tt> artifacts, and out-of-order
        sealing;</li>
        <li>invalid timestamp-state and reference combinations, unsafe
        references, malformed-versus-unsupported profile classification, and
        locally queued work represented as <tt>pending</tt>; and</li>
        <li>imprint, nonce, token, attribute, and certificate violations,
        including <tt>grantedWithMods</tt>, multiple <tt>SignerInfo</tt> values,
        and the legacy <tt>SigningCertificate</tt> attribute.</li>
      </ul>
      <t>
        Cross-implementation checks verify byte parity across at least two
        implementations. The
        normative vector's <tt>interval_ms</tt> value of 86400000 is an elapsed
        duration retained for vector continuity and implies no civil-day,
        time-zone, daylight-saving, or leap-second alignment.
      </t>
    </section>

    <section numbered="true" toc="include" anchor="operations">
      <name>Operational Considerations</name>
      <section numbered="true" toc="include" anchor="ops-health">
        <name>Operational Signals and Deployment</name>
        <t>
          This section follows <xref target="RFC5706"/> and is guidance; the
          normative rules are in the sections referenced. Deployments
          <bcp14>SHOULD</bcp14> expose admission, sealing, submission, issuance
          completion, and verification as distinct states so delayed issuance is
          not confused with a malformed artifact, and <bcp14>SHOULD</bcp14>
          emit structured signals with stable event codes for handoff and
          durability failures, ledger identity and serial conflicts,
          elapsed-timer health and closure delay, artifact writes and roots, TSA
          backlog and per-segment status, and storage pressure. Deployments
          <bcp14>SHOULD</bcp14> document the supported record size and depth,
          admission backpressure, closure policy, retention, accepted TSA
          identities and policies, generation-time and skew constraints,
          verifier policy, and whether reconfiguration can request application
          before the current interval would otherwise close; and
          <bcp14>SHOULD</bcp14> periodically verify a recent representative
          bundle, alerting on failures and on issuance pending beyond policy.
          Before first admission an operator <bcp14>SHOULD</bcp14> durably
          provision a fresh <tt>ledger_id</tt>, 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>
        <t>
          For predictable bounded operation a deployment
          <bcp14>SHOULD</bcp14> configure at least one of
          <tt>record_limit</tt> or <tt>size_limit_bytes</tt>, or enforce a
          finite admission capacity with backpressure; capacity planning for
          <tt>size_limit_bytes</tt> needs to accommodate the admitted record
          that crosses the threshold. For <tt>N &gt; 0</tt> records and batch
          limit <tt>B</tt> the artifact carries <tt>1 + ((N - 1) / B)</tt>
          roots, each costing 34 CBOR octets, so 100000 records with
          <tt>B = 1024</tt> produce 98 roots and about 3332 octets. Larger
          batches reduce artifact size but enlarge the minimum Class B
          disclosure unit, and when a non-null <tt>record_limit</tt> is no
          greater than <tt>batch_record_limit</tt> every segment formed under
          that policy has at most one batch and cannot support Class B.
          Timestamp request rate is one per emitted segment, so sealing and
          response acquisition <bcp14>SHOULD</bcp14> be decoupled through finite
          recoverable state sized on the maximum emission rate and the expected
          service outage rather than on <tt>interval_ms</tt> alone. Verifiers
          <bcp14>SHOULD</bcp14> avoid resolving artifacts outside the selected
          scope and <bcp14>MAY</bcp14> cache a successful record digest for
          identical referenced bytes while counting every disclosed occurrence
          separately.
        </t>
      </section>
    </section>

    <section numbered="true" toc="include" anchor="iana-considerations">
      <name>IANA Considerations</name>
      <t>
        This document has no IANA actions. The
        <tt>application/vnd.vtl.segment+cbor</tt> and
        <tt>application/vnd.vtl.manifest+json</tt> media types used by this
        profile are being registered independently of this document under
        <xref target="RFC6838" section="3.2" sectionFormat="of"/>; the vendor
        tree is used for these project-specific VTL artifact and manifest
        formats, and this Independent Submission requests no standards-tree
        registration. Until those registrations complete, implementations use
        the registered generic <tt>application/cbor</tt> and
        <tt>application/json</tt> types as specified in
        <xref target="segment-artifact-schema"/> and
        <xref target="producer-manifest"/>. No specialized media type is
        requested for verifier results, which use <tt>application/json</tt>.
      </t>
      <t>
        This document also 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 needs no
        central allocation. The absence of a registry provides no discovery of
        conflicting third-party semantic bindings, a residual issue addressed in
        <xref target="security-profile-confusion"/>; a future registry requires
        a separate specification defining its registration policy. The explicit
        statement of no IANA actions 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 handling, and assumes
        the collision and second-preimage resistance of SHA-256 and the
        soundness of the <xref target="RFC9162"/> 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>
        The specialization sorts leaf hashes before reduction and so commits to
        a multiset rather than an ordered list. Because mapping a multiset of
        leaf hashes, including occurrence counts, to its ascending sorted list
        is injective, distinct multisets yield distinct ordered inputs and the
        collision-resistance argument of <xref target="RFC9162"/> applies
        unchanged. The <tt>0x00</tt> leaf and <tt>0x01</tt> parent prefixes
        preserve domain separation and prevent a leaf hash from being
        reinterpreted as an internal node without finding a collision.
      </t>


      <section numbered="true" toc="include" anchor="security-profile-confusion">
        <name>Artifact and Bundle Integrity</name>
        <t>
          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"/>, because a
          pathname check followed by an independent open is unsafe. A timestamp
          over the artifact authenticates neither the manifest nor the result.
        </t>
        <t>
          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 in-band profile binding, and identity comparison mitigate
          these. With no profile registry there is no discovery mechanism for a
          third party assigning different commitment semantics to the same UUID,
          so verifiers obtain mappings from identified policy and deployments
          accepting unoperated producers <bcp14>SHOULD</bcp14> pin the expected
          identifier. Independent artifact-digest recomputation detects mutation
          or substitution, but 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>
</section>

      <section numbered="true" toc="include" anchor="security-sequence">
        <name>Producer, Sequence, and Lifecycle Threats</name>
        <t>
          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. A <tt>ledger_id</tt> must remain unique while evidence
          can be compared, whereas predictability of <tt>segment_number</tt> is
          a required consequence of serial contiguity; operators
          <bcp14>SHOULD</bcp14> audit identifier generation and alert on reuse
          of a ledger or ledger/serial pair.
        </t>
        <t>
          A compromised producer or upstream handoff can fabricate, suppress,
          substitute, replay, or misassign byte strings. VTL makes outputs
          tamper-evident only after commitment; upstream transport, credentials,
          decryption, mapping, and parsing are outside this document, and
          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, and successful verification of a false record can make it
          durably and independently recomputable: a relying party
          <bcp14>MUST NOT</bcp14> treat a successful result as corroboration of
          the recorded value.
        </t>
        <t>
          An attacker can alter the interval, elapsed-time source, policy, close
          reason, or boundary processing. Committing the snapshot and reason
          makes the producer claim tamper-evident after sealing but does not
          prove honest elapsed time or the event that caused closure; a verifier
          cannot distinguish an honest <tt>manual</tt> or <tt>reconfigure</tt>
          claim from another asserted close reason. False upstream UTC values
          remain false admitted values, and UTC changes
          <bcp14>MUST NOT</bcp14> affect membership or reopen a sealed segment.
          A closed-unsealed interval has no artifact or external binding, so
          compromise or loss of that state before sealing can block finalization
          of every later artifact in the chain; durable close state, ordered
          sealing, finite recoverable queues, and backpressure limit accidental
          loss but do not make that state externally tamper-evident. An operator
          <bcp14>MUST NOT</bcp14> represent such state as a sealed segment or a
          locally queued timestamp job as initiated issuance.
        </t>
</section>

      <section numbered="true" toc="include" anchor="security-channel-downgrade">
        <name>TSA Trust and Algorithm Lifetime</name>
        <t>
          This profile defines no producer signing key. The TSA is the only
          signing authority in the baseline and signs an artifact digest rather
          than attesting the producer's identity or the truth of producer
          claims; deployments requiring producer attribution
          <bcp14>MUST</bcp14> obtain it outside this profile.
        </t>
        <t>
          An attacker can delay or withhold responses, present pending
          placeholders as final, or exploit ignored missing responses; the
          status vocabulary and outcome reduction constrain these cases. An
          <tt>incomplete</tt> outcome contains no validated external binding and
          is the outcome an adversary can induce by suppressing a response, so a
          relying party <bcp14>MUST NOT</bcp14> treat <tt>incomplete</tt> as
          equivalent to <tt>success</tt> and <bcp14>SHOULD</bcp14> reverify from
          a later bundle disclosing a terminal response. 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>.
          Validation proves only that bound bytes existed no later than the
          asserted time under identified policy; it proves neither producer nor
          source identity, nor when the segment opened. A nonce-free response
          disclosed without <tt>tsa_req</tt> provides no nonce-correlation
          assurance.
        </t>
        <t>
          The identified verifier policy controls acceptable signature and key
          strength; this profile sets no additional universal strength floor.
          That policy <bcp14>MUST</bcp14> define later-compromise reevaluation,
          acceptable historical revocation evidence, and whether a retired trust
          anchor remains acceptable for a token at its <tt>TSTInfo.genTime</tt>,
          and a verifier <bcp14>MUST NOT</bcp14> report <tt>verified</tt> unless
          the selected path and anchor are acceptable under the policy
          identified in that result. Relying parties comparing results from
          different verifiers therefore need to compare policy identifiers and,
          when present, policy digests.
        </t>
        <t>
          SHA-256 is embedded in every commitment in this profile. Retiring it
          requires a new commitment profile, and <xref target="versioning"/>
          requires that profile to begin a new epoch with a fresh
          <tt>ledger_id</tt> and serial zero. No VTL commitment links the
          terminated chain to its successor; association requires a separately
          authenticated statement. Deployments whose retention horizon can
          exceed the acceptable service life of SHA-256 <bcp14>MUST</bcp14> plan
          how pre-migration evidence remains verifiable and how the epoch
          boundary is authenticated. An external renewal profile such as
          <xref target="RFC4998"/> can support long-term preservation but is not
          defined here.
        </t>
</section>

      <section numbered="true" toc="include" anchor="security-resource-exhaustion">
        <name>Resource Exhaustion</name>
        <t>
          Producers need input-size limits, rate controls, finite recoverable
          queues, and backpressure, with the normative rules in
          <xref target="segment-recovery"/>. Verifiers need finite limits on
          encoded lengths, collection and certificate counts, and recursion,
          with baseline requirements and failure mapping in
          <xref target="baseline-conformance"/> and
          <xref target="overall-outcome"/>. Limits need checking before
          unbounded allocation or recursion, and arithmetic needs to be checked.
          A limit preventing acquisition or sufficient parsing before the
          primary-input boundary produces no result; after that boundary,
          rejection of an otherwise valid input solely for an identified policy
          limit reports <tt>verifier_policy_rejection</tt>. Because this
          document sets acceptance floors only for canonical-record length and
          depth, two conforming verifiers can differ on inputs exceeding their
          other limits. These controls reduce exposure but are not a complete
          denial-of-service defense.
        </t>
      </section>

      <section numbered="true" toc="include" anchor="security-verification-scope">
        <name>Verification Scope, Disclosure, and Privacy</name>
        <t>
          Success can be misread as completeness, physical truth, or
          authorization; the caveat in <xref target="disclosure-bundles"/>
          applies to every result and stronger claims require external controls.
          Class B establishes sorting only within consumed openings and across
          consumed adjacent boundaries and anchor-only establishes none, so 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 scope consuming that record.
        </t>
        <t>
          Leaf hashes are unsalted and a singleton batch root is exactly its
          leaf hash, which occurs for every batch when
          <tt>batch_record_limit</tt> is one and for the final batch whenever
          the record count modulo the batch limit is one; even a Class C
          artifact can therefore disclose individual unsalted leaf hashes, and
          disclosed low-entropy material permits offline guessing, since
          omitting record preimages does not omit leaf hashes. 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 and openings on both sides bound the intervening
          range, so 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>
          Even without payloads, manifests, artifacts, and timestamp artifacts
          reveal counts, layout, outage windows, delay, intervals, close
          reasons, and emission cadence, and repeated pseudonymous identifiers
          can link records and enable re-identification. Operators
          <bcp14>SHOULD</bcp14> minimize personal data, 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>
</section>

      <section numbered="true" toc="include" anchor="interop-notes">
        <name>Extension Boundaries</name>
        <t>
          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"/>, whose 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>
    </section>
  </middle>

  <back>
    <references>
      <name>References</name>
      <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="RFC2634" target="https://www.rfc-editor.org/info/rfc2634">
        <front>
          <title>Enhanced Security Services for S/MIME</title>
          <author fullname="Paul Hoffman" initials="P." surname="Hoffman"/>
          <date year="1999" month="June"/>
        </front>
        <seriesInfo name="RFC" value="2634"/>
        <seriesInfo name="DOI" value="10.17487/RFC2634"/>
      </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="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>
    </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 through the baseline TSA channel 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 CDDL (<xref target="RFC8610"/>) shape for the
        producer manifest and the separate verifier result. Both
        <bcp14>MUST</bcp14> be UTF-8 JSON texts under
        <xref target="RFC8259"/>; parsers <bcp14>MUST</bcp14> reject duplicate
        object member names and generators <bcp14>MUST NOT</bcp14> emit them.
      </t>
      <t>
        These prose constraints apply in addition to the shape below.
        <tt>json-hex32</tt> is exactly 32 lowercase hexadecimal characters and
        <tt>json-hex64</tt> exactly 64. <tt>segment_number</tt> is a JSON string
        holding the shortest unsigned base-10 form of a uint64 (<tt>0</tt>, or a
        digit <tt>1</tt> through <tt>9</tt> followed by zero or more digits)
        whose value <bcp14>MUST NOT</bcp14> exceed 18446744073709551615, which
        avoids loss of precision where a JSON implementation's exact integer
        range ends at 2^53-1. <tt>relative-path</tt> is intentionally structural
        because RFC 8610 regular expressions cannot portably express
        cross-platform 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.
      </t>
      <t>
        Both <tt>commitment_profile_id</tt> members are generic <tt>tstr</tt> so
        that a manifest can repeat, and a result can echo, a future or
        unsupported artifact value; neither relaxes the baseline producer
        requirement in <xref target="versioning"/>, and the result member is
        optional because a malformed artifact might not decode far enough to
        recover it. <tt>chain_status</tt> <bcp14>MUST</bcp14> be present
        whenever the artifact decodes far enough to support one of the chain
        conclusions defined here and <bcp14>MUST</bcp14> be absent otherwise,
        absence making no chain claim; <tt>failure_reasons</tt>
        <bcp14>MUST</bcp14> be present and non-empty exactly when
        <tt>overall</tt> is <tt>failure</tt>. Both the <tt>anchoring</tt> and
        <tt>channels</tt> maps <bcp14>MUST</bcp14> contain exactly the
        <tt>tsa</tt> key, and extension containers <bcp14>MUST NOT</bcp14> add
        channel keys or alter a baseline status or outcome. Violating either
        direction of the state-to-reference rule in
        <xref target="producer-manifest"/> makes the manifest structurally
        invalid, whereas a nonce-bearing response without <tt>tsa_req</tt> is a
        timestamp-channel verification failure rather than a manifest-structure
        error, because a nonce is learned only by inspecting the response.
      </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 = {
  "artifact_sha256": json-hex64,
  "manifest_sha256": json-hex64,
  ? "commitment_profile_id": tstr,
  "claimed_disclosure_class": disclosure-class,
  "verification_scope":
    "public_recompute" / "disclosed_batch_recompute" / "anchor_only",
  ? "chain_status": chain-status,
  "channels": channels,
  "verifier_policy_id": non-empty-tstr,
  ? "verifier_policy_sha256": json-hex64,
  "overall": "success" / "incomplete" / "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",
    ? "extensions": { * tstr => json-data }
  } /
  {
    "status": "pending_claim",
    "reason": "producer_pending_claim",
    ? "extensions": { * tstr => json-data }
  } /
  {
    "status": "missing" / "failed",
    "reason": non-empty-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
        shape. <tt>cbor-hex32</tt> is distinct from the JSON rule in
        <xref target="appendix-b"/> and is exactly 32 lowercase hexadecimal
        characters. CDDL cannot express the power-of-two restriction or the
        upper bound of 2^63 on <tt>batch_record_limit</tt>; both 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>
