<?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-02"
     version="3">
  <front>
    <title abbrev="TrackOne VTL">Verifiable Telemetry Ledgers for Resource-Constrained Environments</title>
    <seriesInfo name="Internet-Draft" value="draft-elkhatabi-verifiable-telemetry-ledgers-02"/>

    <author fullname="Bilal El Khatabi" initials="B." surname="El Khatabi">
      <organization>TrackOne Project</organization>
      <address>
        <postal>
          <country>Morocco</country>
        </postal>
        <email>elkhatabibilal@gmail.com</email>
      </address>
    </author>

    <date year="2026" month="March" day="24"/>
    <area>General</area>
    <workgroup>Independent Submission</workgroup>
    <keyword>telemetry</keyword>
    <keyword>merkle</keyword>
    <keyword>timestamping</keyword>
    <keyword>iot</keyword>

    <abstract>
      <t>
        This document specifies a verifiable telemetry ledger profile for
        resource-constrained sensing environments. It defines the gateway-side
        contract for accepting framed telemetry, enforcing anti-replay policy,
        projecting accepted frames into canonical facts, computing
        deterministic daily Merkle commitments, chaining day records, and
        binding authoritative day artifacts to external timestamp evidence.
        OpenTimestamps (OTS) is the default anchoring channel; RFC 3161
        timestamp responses and peer signatures are optional parallel
        channels.
      </t>
      <t>
        The goal is interoperability and independent auditability, not new
        cryptographic primitives. Verification claims are limited by the
        disclosed artifacts, the claimed disclosure class, and the checks the
        verifier actually executes. A successful result establishes internal
        consistency and correct proof binding for the disclosed bundle; it
        does not by itself establish dataset completeness, physical truth of
        measurements, or safety for autonomous actuation.
      </t>
    </abstract>
  </front>

  <middle>
    <section numbered="true" toc="include" anchor="introduction">
      <name>Introduction</name>
      <t>
        Long-lived telemetry deployments such as environmental monitoring,
        heritage conservation, and infrastructure health need evidence that
        measurements were not silently altered after collection, even when the
        collection point has intermittent connectivity and the evidence must be
        verified long after the original ingest path is gone. Stakeholders
        such as operators, auditors, researchers, regulators, and insurers may
        need to confirm that disclosed telemetry is the same telemetry the
        gateway committed on the day it was accepted.
      </t>
      <t>
        This profile standardizes the gateway-side interoperability surface for
        that problem: admission semantics for framed telemetry, deterministic
        frame-to-fact projection, commitment encoding, day artifact structure,
        disclosure classes, and verifier-facing proof binding.
      </t>
      <t>
        TrackOne is the open-source reference implementation and
        documentation set from which this profile has been extracted. The
        reference implementation publishes machine-readable CDDL for the
        authoritative commitment family and for TrackOne SCITT statement
        payloads, together with schemas and examples, but those repository
        artifacts are implementation evidence rather than normative sources.
        See <xref target="TRACKONE"/>.
      </t>
      <t>
        Existing standards provide important building blocks:
      </t>
      <ul>
        <li>Deterministic CBOR encoding (<xref target="RFC8949"/>),</li>
        <li>Timestamping via trusted timestamp authorities (<xref target="RFC3161"/>),</li>
        <li>CBOR-based Merkle tree proofs (<xref target="COSE-MERKLE"/>), and</li>
        <li>Supply-chain transparency architectures (<xref target="SCITT"/>).</li>
      </ul>
      <t>
        This document does not replace those building blocks. It profiles them
        for a constrained batch workflow in which a gateway may need to accept
        frames locally, produce authoritative day artifacts, and complete
        external proof collection later. SCITT is relevant at publication and
        transparency boundaries, COSE Merkle proofs are relevant to proof
        encoding, and RATS is relevant to device identity attestation, but
        none of those specifications alone defines the commitment contract used
        here.
      </t>
      <t>
        The discussion below positions this profile relative to
        <xref target="SCITT"/>, <xref target="COSE-MERKLE"/>, and
        <xref target="RFC9334"/> because those documents define adjacent, but
        not identical, trust and disclosure boundaries.
      </t>
      <t>
        Concretely, this profile defines the following contract for low-power
        telemetry systems:
      </t>
      <ol>
        <li>Emit encrypted framed telemetry.</li>
        <li>Ingest and validate frames with anti-replay.</li>
        <li>Project accepted frames into canonical facts.</li>
        <li>Build deterministic daily Merkle commitments.</li>
        <li>Chain days with previous-day root linkage.</li>
        <li>Anchor the day artifact using external timestamp proofs.</li>
        <li>Verify independently of disclosed artifacts.</li>
      </ol>
      <t>
        Device reporting cadence and gateway artifact cadence are distinct. A
        pod may report at fixed or irregular intervals, but this profile uses
        one UTC day as the batching unit for authoritative artifacts. Other
        batching intervals are possible design choices for future profiles;
        they are not implicit variations of this one.
        One UTC day is used in the current profile because it gives a
        predictable rollover boundary, bounded artifact size, and a stable
        unit for later disclosure and audit.
      </t>
      <figure anchor="arch-flow">
        <name>Reference Architecture and Trust Boundaries</name>
        <artwork type="ascii-art"><![CDATA[
intermittent uplink        delayed proof / publication
+---------+  frames   +---------+  digest/proof  +-----------+
| Pod     |---------->| Gateway |--------------->| OTS/TSA/  |
| device  |           | batch & |                | peer chan |
+---------+           | anchor  |                +-----------+
                      +---------+
                           |
                           | authoritative day artifact
                           v
                      +-------------+
                      | day/YYYY-   |
                      | MM-DD.cbor  |
                      | + metadata  |
                      +-------------+
                           |
                           | disclosed bundle
                           v
                      +-----------+
                      | Verifier  |
                      +-----------+
]]></artwork>
      </figure>
      <t>
        Figure 1 shows the intended trust boundary. In the current reference
        deployment, intermittency primarily applies on the pod-to-gateway
        path.
      </t>
      <t>
        External timestamping or later publication may also be delayed, but
        those delays do not change the gateway-side commitment contract.
        A disclosed bundle MAY later be registered with a SCITT service.
      </t>
      <t>
        SCITT is not required to create the gateway-side commitment artifact.
      </t>
      <t>
        The design is informed by TrackOne reference-implementation
        validation, including constrained uplink simulation, hardware-in-loop
        testing, and day-batch verification workflows.
      </t>
      <t>
        Verification claims are intentionally scoped. A successful result
        means that the disclosed artifacts are internally consistent, that the
        authoritative day artifact was bound correctly to the disclosed proof
        material, and that the checks reported by the verifier succeeded. It
        does not prove that every observed frame was committed, that the
        measurements are physically correct, or that any downstream decision
        is safe.
      </t>

      <section numbered="true" toc="include" anchor="relationship-existing-work">
        <name>Relationship to Existing Work</name>
        <t>
          This document is complementary to, not a replacement for, the
          following work:
        </t>
        <ul>
          <li>
            <em>SCITT</em> (<xref target="SCITT"/>): SCITT defines
            transparency-service architectures for signed statements and
            receipts. This profile can be published through such systems, but
            it standardizes the ledger and verification contract that exists
            before registration with a transparency service.
          </li>
          <li>
            <em>COSE Merkle Tree Proofs</em> (<xref target="COSE-MERKLE"/>):
            COSE-MERKLE defines proof encodings. This profile defines the
            batching, canonicalization, and verification contract that such
            encodings could carry in a future revision.
          </li>
          <li>
            <em>RATS</em> (<xref target="RFC9334"/>): This profile explicitly
            defers device identity, attestation, and key lifecycle to
            deployment-specific mechanisms.
          </li>
          <li>
            <em>RFC 8949</em> (<xref target="RFC8949"/>): This profile defines a
            deterministic CBOR commitment profile for gateway-side
            commitments. It does not attempt to define a general-purpose CBOR
            profile beyond that commitment path.
          </li>
        </ul>
      </section>

      <section numbered="true" toc="include" anchor="scitt-rats-interop">
        <name>SCITT and RATS Integration Pattern</name>
        <t>
          This profile can be used alongside SCITT rather than instead of it.
          The current TrackOne implementation defines day-scoped and
          bundle-scoped SCITT statement payloads that bind verifier-visible
          TrackOne artifacts, but the transparency service remains responsible
          for statement registration, receipt issuance, and service policy.
          This document therefore standardizes the gateway-side commitment and
          disclosure contract that may later be carried inside a SCITT
          statement.
        </t>
        <t>
          Likewise, this profile does not replace RATS. Device identity,
          attestation, and evidence appraisal remain deployment-specific
          inputs. The gateway logic defined here assumes that any required
          device identity or attestation decisions have already been handled
          by local policy or by a companion architecture such as RATS.
        </t>
      </section>
    </section>

    <section numbered="true" toc="include" anchor="terminology">
      <name>Conventions and Terminology</name>
      <t>
        The key words "<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>",
        "<bcp14>REQUIRED</bcp14>", "<bcp14>SHALL</bcp14>",
        "<bcp14>SHALL NOT</bcp14>", "<bcp14>SHOULD</bcp14>",
        "<bcp14>SHOULD NOT</bcp14>", "<bcp14>RECOMMENDED</bcp14>",
        "<bcp14>NOT RECOMMENDED</bcp14>", "<bcp14>MAY</bcp14>", and
        "<bcp14>OPTIONAL</bcp14>" in this document are to be interpreted as
        described in BCP 14 <xref target="RFC2119"/> <xref target="RFC8174"/>
        when, and only when, they appear in all capitals, as shown here.
      </t>
      <t>Terms:</t>
      <ul>
        <li>Frame: One UTF-8 JSON text serialized as a single newline-delimited record, containing header and AEAD fields (<xref target="NDJSON"/>).</li>
        <li>Fact: Canonical telemetry record admitted after gateway validation and projection. The term refers to the committed record shape, not to physical truth of the underlying measurement.</li>
        <li>Commitment profile: The serialization, hash, and Merkle rules that produce deterministic commitment outputs.</li>
        <li>Ledger set for day D (F_D): The set of accepted facts committed for day D.</li>
        <li>Day artifact: The authoritative canonical day record written as <tt>day/YYYY-MM-DD.cbor</tt>.</li>
        <li>Authoritative: Used for the canonical artifact that verifiers MUST treat as the cryptographic source of truth.</li>
        <li>Projection: A non-authoritative representation (for example JSON) derived from an authoritative artifact.</li>
        <li>Block metadata: A standalone projection of a batch object (for example <tt>blocks/YYYY-MM-DD-00.block.json</tt>) exported for convenience. When disclosed, it MUST match the corresponding batch object in the authoritative day artifact.</li>
        <li>OTS metadata sidecar: <tt>day/YYYY-MM-DD.ots.meta.json</tt>, a separate non-authoritative metadata file associated with an OTS proof and authoritative day artifact, linking the artifact digest to the proof path. It is not a commitment input.</li>
        <li>Anchor evidence: The proof artifacts and binding metadata disclosed for an external timestamping or attestation channel.</li>
        <li>Peer signature quorum: A deployment-defined set or threshold of peer signatures over the same day-artifact digest or day root, treated as one optional parallel attestation channel.</li>
        <li>Replay unit: The pair <tt>(dev_id, fc)</tt>, where <tt>fc</tt> is a frame counter for device <tt>dev_id</tt>.</li>
        <li>Verification scope: The set of disclosed artifacts, checks executed, and claim boundaries that a verifier actually asserts for a verification result.</li>
        <li>Day boundary: A UTC calendar day boundary. Day labels in this profile use <tt>YYYY-MM-DD</tt> in UTC.</li>
        <li>Disclosure class: The level of artifact disclosure associated with a verification claim.</li>
      </ul>
    </section>

    <section numbered="true" toc="include" anchor="roles">
      <name>System Roles</name>
      <t>
        In this document, optional parallel attestation channels are not
        required for baseline conformance. A conforming deployment MUST
        implement at least one anchoring channel, with OTS as the default
        channel described here. RFC 3161 timestamp responses and peer
        signatures MAY be absent entirely; when present, they MUST bind to the
        same authoritative day-artifact digest and verifiers MUST report their
        results separately.
      </t>
      <ul>
        <li>Device (Pod): Produces framed telemetry.</li>
        <li>Gateway: Validates, decrypts, applies anti-replay, projects facts, batches, and anchors day artifacts.</li>
        <li>Verifier: Recomputes commitments and validates proofs from disclosed artifacts.</li>
        <li>OTS Calendar(s): Provides OTS attestations for day artifact hashes.</li>
        <li>TSA: An RFC 3161 timestamp authority over the same digest, when that optional channel is used.</li>
        <li>Peers: Co-sign daily roots for short-term provenance, when that optional channel is used.</li>
      </ul>
    </section>

    <section numbered="true" toc="include" anchor="data-model">
      <name>Data and Commitment Model</name>
      <t>
        This section separates the reference wire framing from the reusable
        commitment contract. The most deployment-specific surface is the
        framed transport in <xref target="frame-contract"/>. The interoperable
        core is the deterministic frame-to-fact projection, commitment
        encoding, Merkle calculation, day artifact, disclosure model, and
        verification behavior.
      </t>

      <section numbered="true" toc="include" anchor="frame-contract">
        <name>Frame Contract</name>
        <t>A frame is transported as newline-delimited JSON (NDJSON; <xref target="NDJSON"/>) with fields:</t>
        <figure>
          <artwork type="json"><![CDATA[
{
  "hdr": { "dev_id": 101, "msg_type": 1, "fc": 42, "flags": 0 },
  "nonce": "base64-24B",
  "ct": "base64-ciphertext",
  "tag": "base64-16B"
}
]]></artwork>
        </figure>
        <t>
          Gateways MUST validate header field presence, header ranges, and AEAD
          authentication before fact emission.
        </t>
        <ul>
          <li><tt>hdr.dev_id</tt> MUST be an unsigned integer in the range 0..65535.</li>
          <li><tt>hdr.msg_type</tt> MUST be an unsigned integer in the range 0..255.</li>
          <li><tt>hdr.fc</tt> MUST be an unsigned integer in the range 0..(2^32-1).</li>
          <li><tt>hdr.flags</tt> MUST be an unsigned integer in the range 0..255.</li>
          <li><tt>nonce</tt> MUST be base64 text that decodes to exactly 24 bytes.</li>
          <li><tt>tag</tt> MUST be base64 text that decodes to exactly 16 bytes.</li>
        </ul>
        <t>
          Frames that fail parse, range, or AEAD validation MUST be rejected
          before fact commitment and MUST NOT produce committed facts.
        </t>
        <t>
          The wire shape in this section is the TrackOne reference transport
          profile. Other deployments MAY use a different transport framing if
          they preserve the acceptance semantics needed to produce the same
          canonical fact objects under <xref target="fact-projection"/>.
        </t>
        <t>
          The minimum pod-side requirements needed to emit such frames are
          summarized in <xref target="appendix-c"/>.
        </t>
      </section>

      <section numbered="true" toc="include" anchor="anti-replay">
        <name>Anti-Replay Admission Criterion</name>
        <t>
          For framed telemetry, the replay unit is <tt>(dev_id, fc)</tt>.
          A gateway MUST commit a fact from a frame only if all of the
          following hold:
        </t>
        <ol>
          <li>No fact has already been committed for the same replay unit <tt>(dev_id, fc)</tt>.</li>
          <li>The frame counter <tt>fc</tt> is within the configured acceptance window for that device relative to durable replay state.</li>
          <li>No continuity-break, reset, or replay-state-loss condition requires explicit resynchronization before further acceptance.</li>
        </ol>
        <t>
          Frames that do not satisfy these conditions MUST NOT produce
          committed facts.
        </t>
        <t>
          The RECOMMENDED default acceptance window is 64 frame counter values
          per device. Frames with <tt>fc</tt> more than <tt>window_size</tt>
          behind the highest accepted counter for a device MUST be rejected.
          In the TrackOne reference gateway profile, frames with <tt>fc</tt>
          more than <tt>window_size</tt> ahead of the highest accepted counter
          MUST also be rejected, rather than silently accepted across a large
          discontinuity.
        </t>
        <t><strong>Structured Rejection Evidence</strong></t>
        <t>
          Gateways SHOULD produce structured rejection evidence for rejected
          frames. A rejection record SHOULD include at minimum:
        </t>
        <ul>
          <li><tt>device_id</tt>,</li>
          <li><tt>fc</tt> (or null if unavailable),</li>
          <li><tt>reason</tt>,</li>
          <li><tt>observed_at_utc</tt>, and</li>
          <li><tt>frame_sha256</tt>.</li>
        </ul>
        <t>
          Rejection evidence is an audit artifact and MUST NOT be hashed into
          ledger commitments.
        </t>
        <t><strong>Replay State Persistence</strong></t>
        <t>
          Gateways SHOULD persist replay state across restart. If replay state
          is lost, gateways SHOULD record a continuity break event and SHOULD
          NOT silently re-accept counters that could already have been
          committed.
        </t>
        <t><strong>Scope Limitation</strong></t>
        <t>
          This profile provides tamper-evidence for committed facts. It does
          not prove the absence of selective pre-commitment drops by a
          malicious gateway.
        </t>
      </section>

      <section numbered="true" toc="include" anchor="fact-projection">
        <name>Frame-to-Fact Projection</name>
        <t>
          The frame-to-fact projection transforms a validated, decrypted frame
          into a canonical fact suitable for commitment. The committed fact is
          a structured record derived from the decrypted payload, not a copy of
          transport bytes.
        </t>
        <ol>
          <li>The gateway MUST verify AEAD authentication.</li>
          <li>The gateway MUST decrypt the ciphertext.</li>
          <li>The gateway MUST parse the decrypted plaintext according to the frame's <tt>msg_type</tt>.</li>
          <li>The gateway MUST construct a fact object.</li>
          <li>The gateway MUST serialize that fact object under the gateway commitment profile.</li>
          <li>The canonical fact bytes are then hashed for Merkle inclusion.</li>
        </ol>
        <t>A committed fact under this profile MUST contain at minimum:</t>
        <ul>
          <li><tt>pod_id</tt>,</li>
          <li><tt>fc</tt>,</li>
          <li><tt>ingest_time</tt>,</li>
          <li><tt>pod_time</tt>,</li>
          <li><tt>kind</tt>, and</li>
          <li><tt>payload</tt>.</li>
        </ul>
        <t>
          Interoperability depends on two distinct layers: the projection
          contract that maps an accepted frame into a fact object, and the
          commitment profile that serializes that fact object and reduces the
          resulting digests. Independent implementations claiming the same
          result MUST agree on both layers.
        </t>
        <t>
          A commitment profile or deployment profile claiming conformance MUST
          fix the type and source of each committed field so independent
          implementations can construct identical fact bytes.
        </t>
        <t>
          For each committed field, the applicable projection contract MUST
          state whether the field is transport-derived, payload-derived,
          gateway-assigned, or deployment metadata-derived. Independent
          implementations MUST NOT substitute a different field source while
          claiming the same projection contract.
        </t>
        <t>
          For <tt>trackone-canonical-cbor-v1</tt>, the committed fact object
          has six logical fields: <tt>pod_id</tt>, <tt>fc</tt>,
          <tt>ingest_time</tt>, <tt>pod_time</tt>, <tt>kind</tt>, and
          <tt>payload</tt>. Its authoritative commitment encoding is a fixed
          CBOR array whose positional elements are:
        </t>
        <ol>
          <li>schema/version discriminator, currently <tt>1</tt>;</li>
          <li><tt>pod_id</tt> encoded as an 8-byte byte string;</li>
          <li><tt>fc</tt>;</li>
          <li><tt>ingest_time</tt>;</li>
          <li><tt>pod_time</tt> or <tt>null</tt>;</li>
          <li><tt>kind</tt> as the profile-defined family discriminator; and</li>
          <li><tt>payload</tt> encoded under the applicable payload family.</li>
        </ol>
        <t>The TrackOne-specific field definitions are:</t>
        <ul>
          <li><tt>pod_id</tt> MUST be a deterministic pod identifier. When framed telemetry is used, the profile MUST define a deterministic mapping from <tt>hdr.dev_id</tt> or equivalent deployment alias to <tt>pod_id</tt>. In reader-facing JSON projections and vector notes, the TrackOne reference profile renders the identifier as lowercase hexadecimal text such as <tt>0000000000000065</tt>. In authoritative CBOR commitment bytes, the same identifier is encoded as the corresponding 8-byte byte string.</li>
          <li><tt>fc</tt> MUST be the accepted frame counter as a non-negative integer.</li>
          <li><tt>ingest_time</tt> MUST be a UTC integer timestamp fixed by the projection contract.</li>
          <li><tt>pod_time</tt> MUST be either a pod-supplied integer timestamp or <tt>null</tt> when the pod does not supply one.</li>
          <li><tt>kind</tt> MUST identify the fact family under the applicable projection contract. In authoritative CBOR commitment bytes, this field is the numeric family discriminator defined by the commitment profile. For the current profile, the discriminator mapping is <tt>Env=1</tt>, <tt>Pipeline=2</tt>, <tt>Health=3</tt>, and <tt>Custom=250</tt>.</li>
          <li><tt>payload</tt> MUST be the parsed plaintext object associated with the accepted frame.</li>
        </ul>
        <t>
          A different deployment profile MAY define additional logical fields,
          but such an extension is not compatible with
          <tt>trackone-canonical-cbor-v1</tt> unless it is given a distinct
          <tt>commitment_profile_id</tt> and corresponding conformance
          vectors.
        </t>
        <t>
          An implementation claiming parity with
          <tt>trackone-canonical-cbor-v1</tt> MUST reproduce that exact
          logical record and its fixed array encoding before applying the
          deterministic CBOR rules in <xref target="cbor-profile"/>.
        </t>
        <t>
          Ciphertext, raw transport bytes, and the authentication tag MUST NOT
          be part of the committed fact object. The exact payload schema is
          deployment-specific; the deterministic projection contract is the
          normative requirement and MUST be published for any commitment profile
          that claims interoperability.
        </t>
        <t>
          Published conformance vectors for a commitment profile MUST include
          the post-projection fact objects used as commitment inputs, not only
          transport frames.
        </t>
      </section>

      <section numbered="true" toc="include" anchor="cbor-profile">
        <name>Deterministic CBOR Commitment Encoding</name>
        <t>
          This section does not define a new general-purpose CBOR variant. It
          records the narrow deterministic CBOR encoding used for commitment
          bytes in the TrackOne reference gateway and ledger implementation.
          The identifier <tt>trackone-canonical-cbor-v1</tt> names this
          commitment recipe so verifiers can tell which byte-level rules were
          used.
        </t>
        <t>
          The authoritative commitment artifacts, namely CBOR fact
          artifacts and the canonical day artifact, use a constrained
          subset of deterministic encoding under Section 4.2.1 of
          <xref target="RFC8949"/>. For TrackOne commitment bytes, the
          following concrete choices apply:
        </t>
        <ul>
          <li>All commitment-path items MUST use definite-length encoding.</li>
          <li>Integers MUST use the shortest encoding width permitted by <xref target="RFC8949"/>.</li>
          <li>Map keys MUST be CBOR text strings.</li>
          <li>Map keys MUST be sorted by encoded key length ascending, then by lexicographic order of the encoded key bytes.</li>
          <li>Finite floating-point values MUST be encoded using the shortest of float16, float32, or float64 that exactly preserves the value.</li>
          <li>NaN, positive infinity, and negative infinity MUST be rejected in commitment paths.</li>
          <li>CBOR tags MUST NOT appear in commitment bytes.</li>
          <li>Supported values are unsigned integers, negative integers, byte strings, text strings, arrays, maps, booleans, null, and deterministic finite floats.</li>
        </ul>
        <t>
          Implementations MUST NOT accept generic CBOR serializers as
          authoritative commitment encoders. An encoder is acceptable only
          if it yields the same bytes as these rules.
        </t>
        <t>
          JSON projections of fact artifacts and day artifacts are
          optional and non-authoritative. They MUST NOT be used as
          commitment inputs. When produced, such projections SHOULD follow
          <xref target="RFC8785"/>.
        </t>
        <t>
          Device-side or embedded components MAY use other internal encodings,
          including different deterministic CBOR layouts optimized for local
          constraints. Those encodings are not the authoritative commitment
          encoding described here unless they are explicitly identified by a
          distinct <tt>commitment_profile_id</tt> and verified under their own
          rules.
        </t>
      </section>

      <section numbered="true" toc="include" anchor="merkle-policy">
        <name>Deterministic Commitment Tree Calculation</name>
        <t>
          For a given day <tt>D</tt>, the current commitment profile computes a
          daily root from the canonical fact commitment bytes produced under
          <xref target="cbor-profile"/>. The following steps describe that
          calculation.
        </t>
        <t><strong>Leaf Digests</strong></t>
        <ul>
          <li>Each canonical fact byte string is hashed with <tt>SHA-256</tt>, yielding a 32-byte leaf digest.</li>
        </ul>
        <t><strong>Digest Ordering</strong></t>
        <ul>
          <li>To make the daily root independent of file order or ingest order, leaf digests MUST be sorted in ascending byte order before reduction.</li>
          <li>Lowercase hexadecimal is a representation format for artifacts and examples only; internal Merkle computation operates on raw hash bytes.</li>
          <li>Sorting by lowercase hexadecimal is equivalent to bytewise ascending order over the raw digests.</li>
        </ul>
        <t><strong>Pairwise Reduction</strong></t>
        <ul>
          <li>The sorted digests are reduced pairwise by computing <tt>SHA-256(left_child_bytes || right_child_bytes)</tt>, where both operands are raw 32-byte digests.</li>
          <li>If a layer has an odd number of digests, the final digest is duplicated to form the last pair.</li>
          <li>The current commitment profile does not prepend domain-separation bytes to leaf or parent hashes.</li>
        </ul>
        <t><strong>Empty Day</strong></t>
        <ul>
          <li>If no facts are committed for the day, the daily root is the <tt>SHA-256</tt> digest of zero bytes: <tt>e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855</tt>.</li>
        </ul>
        <t>
          The resulting daily root is deterministic for the set of committed
          facts. Because the leaf digests are sorted before reduction, the
          result depends on the committed fact set rather than on ingestion
          order.
        </t>
        <t>
          Any future change to this calculation that alters commitment bytes
          (for example, adding domain separation) MUST use a new
          <tt>commitment_profile_id</tt>.
        </t>
      </section>

      <section numbered="true" toc="include" anchor="day-artifact-schema">
        <name>Day Artifact Schema</name>
        <t>
          The authoritative day artifact is a CBOR-encoded day record produced
          under <xref target="cbor-profile"/>. The day record contains the
          following fields:
        </t>
        <ul>
          <li><tt>version</tt> (uint): day-record schema version, currently 1.</li>
          <li><tt>site_id</tt> (tstr): site identifier.</li>
          <li><tt>date</tt> (tstr): UTC day label in <tt>YYYY-MM-DD</tt> form.</li>
          <li><tt>prev_day_root</tt> (tstr): previous day root as 64 lowercase hexadecimal characters.</li>
          <li><tt>batches</tt> (array): array of batch objects.</li>
          <li><tt>day_root</tt> (tstr): deterministic day root as 64 lowercase hexadecimal characters.</li>
        </ul>
        <t>Each batch object contains:</t>
        <ul>
          <li><tt>version</tt> (uint): batch-record schema version, currently 1.</li>
          <li><tt>site_id</tt> (tstr): site identifier.</li>
          <li><tt>day</tt> (tstr): UTC day label in <tt>YYYY-MM-DD</tt> form.</li>
          <li><tt>batch_id</tt> (tstr): batch identifier.</li>
          <li><tt>merkle_root</tt> (tstr): batch Merkle root as 64 lowercase hexadecimal characters.</li>
          <li><tt>count</tt> (uint): number of committed facts in the batch.</li>
          <li><tt>leaf_hashes</tt> (array of tstr): sorted leaf hashes as lowercase hexadecimal strings.</li>
        </ul>
        <t>
          The batch objects embedded in the day artifact are the authoritative
          batch metadata for verification.
        </t>
        <ul>
          <li>For each batch object, <tt>count</tt> MUST equal the length of <tt>leaf_hashes</tt>.</li>
          <li>For each batch object, <tt>merkle_root</tt> MUST equal the Merkle reduction of that batch's <tt>leaf_hashes</tt> under <xref target="merkle-policy"/>.</li>
          <li>The multiset union of all batch <tt>leaf_hashes</tt> for the day MUST equal the day's leaf digest multiset from which <tt>day_root</tt> is computed.</li>
        </ul>
        <t>
          <tt>day/YYYY-MM-DD.cbor</tt> is authoritative. The corresponding
          <tt>day/YYYY-MM-DD.json</tt> file is a projection only.
        </t>
        <t>
          This document uses normative field tables rather than CDDL. A future
          revision may add a formal CDDL appendix if broader independent
          implementations require it.
        </t>
      </section>

      <section numbered="true" toc="include" anchor="day-chaining">
        <name>Day Chaining</name>
        <t>Day records include <tt>prev_day_root</tt>.</t>
        <ul>
          <li>The genesis day for a site MUST set <tt>prev_day_root</tt> to 64 ASCII zero characters, representing 32 zero bytes.</li>
          <li>Non-genesis days MUST set <tt>prev_day_root</tt> to the previous committed day's <tt>day_root</tt>.</li>
        </ul>
        <t>
          Because day labels are UTC-based, chaining semantics are also
          defined on UTC day boundaries.
        </t>
      </section>
    </section>

    <section numbered="true" toc="include" anchor="artifacts">
      <name>Artifacts and Verification Bundles</name>
      <t>Illustrative artifact layout:</t>
      <ul>
        <li><tt>facts/&lt;fact-id&gt;.cbor</tt> - authoritative canonical facts</li>
        <li><tt>facts/&lt;fact-id&gt;.json</tt> - optional projections</li>
        <li><tt>day/YYYY-MM-DD.cbor</tt> - authoritative canonical day artifact</li>
        <li><tt>day/YYYY-MM-DD.json</tt> - optional projection</li>
        <li><tt>blocks/YYYY-MM-DD-00.block.json</tt> - optional standalone block-metadata projection of one batch object</li>
        <li><tt>day/YYYY-MM-DD.cbor.sha256</tt> - convenience digest</li>
        <li><tt>day/YYYY-MM-DD.cbor.ots</tt> - OTS proof</li>
        <li><tt>day/YYYY-MM-DD.ots.meta.json</tt> - OTS binding metadata</li>
      </ul>
      <t>
        Deployments MAY store artifacts differently and MAY export them as
        bundles. The path shapes above are illustrative.
      </t>
      <t>
        Standalone block metadata files are convenience projections of batch
        objects already carried in the authoritative day artifact. They are not
        additional commitment inputs. Verifiers that process disclosed
        standalone block-metadata projections MUST compare them with the
        corresponding batch object in the authoritative day artifact and
        reject mismatches.
      </t>
      <t>
        Every verification bundle MUST disclose the
        <tt>commitment_profile_id</tt>. A verifier-facing bundle SHOULD
        disclose it in a machine-readable verification manifest together with
        artifact digests, disclosure class, channel status, and the executed
        or skipped verification checks. If a
        deployment uses other local verifier metadata, the resulting
        verification scope MUST still be made explicit in verifier output.
      </t>
      <t>
        In the TrackOne reference workflow, the verification manifest is the
        normal machine-readable contract presented to verifiers. This document
        therefore treats the manifest as the primary disclosure surface for
        bundle-level verification metadata. A minimum interoperable manifest
        shape is defined in <xref target="appendix-d"/>. The current TrackOne
        workflow also publishes a stricter JSON Schema-backed manifest that
        carries additional deployment-local pipeline fields, but those extra
        fields are not required by this document.
      </t>
      <t>At minimum, an OTS sidecar MUST bind:</t>
      <ul>
        <li><tt>artifact</tt>,</li>
        <li><tt>artifact_sha256</tt>, and</li>
        <li><tt>ots_proof</tt>.</li>
      </ul>
      <t>
        Verifiers MUST recompute the day artifact digest and compare it with
        the sidecar before accepting any proof validation result.
      </t>
    </section>

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

      <section numbered="true" toc="include" anchor="anchoring-contract">
        <name>Anchoring Contract</name>
        <t>
          The generic anchoring contract is simple: a gateway computes the
          SHA-256 digest of the authoritative day artifact and submits that
          digest to one or more external timestamping channels. Verifiers MUST
          first recompute the day artifact digest locally; proof validation
          occurs only after digest binding validation succeeds.
        </t>
        <t>
          A deployment conforming to this profile MUST use at least one
          anchoring channel. OTS is the default channel described by this
          document; RFC 3161 and peer signatures are optional parallel
          channels.
        </t>
        <figure anchor="time-flow">
          <name>Illustrative Commitment and Proof Lifecycle</name>
          <artwork type="ascii-art"><![CDATA[
time ------------------------------------------------------------>

Pod      |--frame-->|        |--frame-->|               |--frame-->|
Gateway  | validate | commit | validate | commit        | validate |
         |------ accepted records accumulate in one UTC day -------|
         |             write day/YYYY-MM-DD.cbor                   |
         |------------- submit digest to OTS / TSA --------------->|
Channel  |                pending / delayed proof        | upgrade |
Verifier |                                      verify later from  |
         |<---------------- disclosed bundle --------------------->|
]]></artwork>
        </figure>
        <t>
          <xref target="time-flow"/> illustrates the current lifecycle. The
          pod-to-gateway transport may be intermittent, while proof
          completion or later publication may lag behind the authoritative
          day-artifact write.
        </t>
      </section>

      <section numbered="true" toc="include" anchor="ots-profile">
        <name>OTS Anchoring Profile</name>
        <t>
          When <xref target="OTS"/> is used, the gateway stamps
          <tt>SHA-256(day/YYYY-MM-DD.cbor)</tt> and stores an OTS proof plus an
          OTS sidecar.
        </t>
        <t>
          OpenTimestamps is referenced here as a deployed public timestamping
          ecosystem rather than an IETF-standardized proof format.
          Implementations claiming OTS support depend on the interoperable
          behavior of the public OTS project, its calendar servers, and
          compatible client tooling. OTS proof-format interoperability is
          therefore defined operationally by that ecosystem and its reference
          implementations.
        </t>

        <section numbered="true" toc="include" anchor="ots-lifecycle">
          <name>OTS Anchoring Lifecycle</name>
          <ol>
            <li><em>Submission</em>: the gateway submits the day artifact digest to one or more OTS calendars.</li>
            <li><em>Pending</em>: a calendar may return an incomplete proof while awaiting Bitcoin commitment.</li>
            <li><em>Upgrade</em>: the gateway or a background process may later upgrade the proof to include completed attestations.</li>
            <li><em>Verification</em>: a verifier recomputes the artifact digest and validates the proof.</li>
          </ol>
          <t>
            Gateways SHOULD submit to multiple independent calendars to reduce
            single-calendar unavailability risk.
          </t>
        </section>

        <section numbered="true" toc="include" anchor="delayed-anchoring">
          <name>Handling Delayed or Failed Anchoring</name>
          <t>
            If OTS submission fails, times out, or yields only an
            incomplete proof, the gateway MUST still write the
            authoritative day artifact and MUST treat OTS as a separate
            channel whose state is not yet complete. The gateway MAY
            retain a placeholder or incomplete proof artifact and MAY
            later replace or upgrade it as additional OTS evidence
            becomes available. Until a valid proof is disclosed and
            verified, verifiers MUST report the OTS channel as
            <tt>pending</tt>, <tt>missing</tt>, or <tt>failed</tt>
            according to the disclosed artifacts and local policy,
            rather than treating the day artifact itself as invalid. Any
            later replacement or upgrade of the OTS proof MUST continue
            to bind to the same authoritative day-artifact digest.
          </t>
          <t>
            Gateways MUST retain disclosed OTS proof artifacts for at
            least the operational retention period of the corresponding
            day artifacts.
          </t>
        </section>

        <section numbered="true" toc="include" anchor="proof-status-vocabulary">
          <name>Proof Status Vocabulary</name>
          <t>
            Verifiers and bundle manifests SHOULD use a consistent status
            vocabulary for OTS and optional parallel attestation channels:
          </t>
          <ul>
            <li><tt>verified</tt>: proof validation succeeded for the disclosed artifact binding.</li>
            <li><tt>pending</tt>: a proof exists but is incomplete or awaiting upgrade; this is not equivalent to invalid.</li>
            <li><tt>missing</tt>: the expected proof or channel artifact is absent.</li>
            <li><tt>failed</tt>: validation was attempted and did not succeed.</li>
            <li><tt>skipped</tt>: validation was not attempted because of disclosure class, verifier configuration, or local policy.</li>
          </ul>
          <t>
            Whether <tt>missing</tt>, <tt>pending</tt>, or <tt>skipped</tt>
            is verifier-fatal depends on the disclosure class, local verifier
            policy, and whether the relevant channel is required.
          </t>
        </section>
      </section>

      <section numbered="true" toc="include" anchor="parallel-attestation">
        <name>Optional Parallel Attestation</name>
        <t>Deployments MAY also produce:</t>
        <ul>
          <li>An <xref target="RFC3161"/> timestamp response over the same day-artifact digest.</li>
          <li>A peer signature quorum over <tt>(site_id, day, day_root, context)</tt>.</li>
        </ul>
        <t>
          When multiple channels are present, verifiers SHOULD validate all
          available channels independently and report per-channel results.
        </t>
        <t>
          If a verifier is configured in strict mode for optional channels,
          failure of those channels MUST cause overall verification failure.
        </t>
      </section>

      <section numbered="true" toc="include" anchor="verify">
        <name>Verification</name>
        <t>
          Verifiers MUST first determine the applicable
          <tt>commitment_profile_id</tt> from disclosed bundle metadata. When
          the authoritative day artifact does not carry that identifier
          in-band, the verifier MUST obtain it from the verification manifest
          or equivalent bundle metadata and MUST reject absent or unsupported
          values.
        </t>
        <t>
          Verifiers MUST determine the applicable verification scope from the
          disclosed artifacts, the claimed disclosure class, and local
          verifier policy. Reported outcomes MUST NOT claim checks or
          assurances outside that scope.
        </t>
        <t>
          Verifiers SHOULD apply checks in the following fail-fast order,
          subject to the claimed disclosure class:
        </t>
        <ol>
          <li>Validate that disclosed artifacts are sufficient for the claimed disclosure class and disclose a <tt>commitment_profile_id</tt>.</li>
          <li>Validate the authoritative day artifact and any disclosed verification manifest or equivalent bundle metadata.</li>
          <li>For Class A bundles, recompute canonical fact leaf digests from disclosed fact CBOR artifacts, validate the batch metadata contract, and recompute <tt>day_root</tt>. Compare the recomputed result to the authoritative <tt>day_root</tt>.</li>
          <li>For Class B bundles, validate the authoritative day artifact, validate any disclosed batch metadata, and report that public fact-level recomputation was not attempted for withheld material. If the bundle discloses withheld-material commitments or policy artifacts, validate those artifacts under the applicable bundle policy.</li>
          <li>For Class C bundles, skip fact-level and batch-level recomputation and treat the result as anchor-only evidence.</li>
          <li>Recompute <tt>SHA-256(day/YYYY-MM-DD.cbor)</tt> and compare it to the sidecar <tt>artifact_sha256</tt>.</li>
          <li>Validate the OTS proof when OTS is required or present.</li>
          <li>Validate optional RFC 3161 and peer attestations as configured.</li>
        </ol>
        <t>
          When batch metadata is within the exercised verification scope,
          verifiers MUST apply the following checks before accepting a result:
        </t>
        <ul>
          <li>each batch <tt>count</tt> equals the length of its <tt>leaf_hashes</tt>;</li>
          <li>each batch <tt>merkle_root</tt> equals the Merkle reduction of its <tt>leaf_hashes</tt>;</li>
          <li>the union multiset of batch <tt>leaf_hashes</tt> equals the leaf digest multiset derived from disclosed facts when fact artifacts are available; and</li>
          <li>any standalone block-metadata projection matches the corresponding batch object in the authoritative day artifact.</li>
        </ul>
        <t>
          Verifier implementations SHOULD expose machine-usable failure
          categories:
        </t>
        <ul>
          <li>malformed or missing artifacts,</li>
          <li>missing or unsupported <tt>commitment_profile_id</tt>,</li>
          <li>Merkle mismatch,</li>
          <li>batch metadata mismatch,</li>
          <li>missing or invalid OTS proof,</li>
          <li>sidecar mismatch or digest mismatch,</li>
          <li>insufficient disclosure for the claimed verification level, and</li>
          <li>optional-channel failure.</li>
        </ul>
        <t>
          Verifier output SHOULD state the claimed disclosure class, the
          verification scope actually exercised, the per-channel proof
          status, which checks were executed, which checks were skipped, and
          whether the resulting claim is public recompute, partial
          verification, or anchor-only evidence.
        </t>
        <t>
          Verifier output MUST NOT be represented as proving more than the
          exercised verification scope. In particular, a successful result does
          not by itself establish dataset completeness, physical truth of
          measurements, or suitability for autonomous actuation or sanctions.
        </t>
      </section>
    </section>

    <section numbered="true" toc="include" anchor="disclosure-bundles">
      <name>Disclosure Classes</name>
      <t>
        Verification claims depend on what artifacts are disclosed. This
        profile defines three disclosure classes.
      </t>
      <ul>
        <li><strong>Class A (Public Recompute)</strong>: sufficient material for independent fact-level recomputation.</li>
        <li><strong>Class B (Partner Audit)</strong>: controlled disclosure with redacted or partitioned fact material.</li>
        <li><strong>Class C (Anchor-Only)</strong>: existence and timestamp evidence only.</li>
      </ul>
      <t>
        A verifier claim for any disclosure class MUST be limited to the
        verification scope supported by the disclosed artifacts.
      </t>
      <t>
        Class A is the public-recompute case. A Class A bundle MUST include:
      </t>
      <ul>
        <li>all canonical fact artifacts required to recompute the claimed day root,</li>
        <li>the canonical day artifact, including its authoritative batch objects,</li>
        <li>any disclosed standalone block-metadata projections, and</li>
        <li>the OTS proof plus its sidecar metadata.</li>
      </ul>
      <t>
        A Class A bundle SHOULD also include a machine-readable verification
        manifest and SHOULD record the <tt>commitment_profile_id</tt>.
      </t>
      <t>
        Class A permits fact-level recomputation, batch-metadata
        validation, day-root recomputation, and anchor validation when the
        corresponding artifacts are disclosed and checked.
      </t>
      <t>
        Class B is the controlled-disclosure case. Class B outputs MUST NOT be
        represented as publicly recomputable. A Class B bundle SHOULD include
        the canonical day artifact, any disclosed standalone block-metadata
        projections, at least one timestamp proof plus its binding metadata,
        any disclosed commitments covering withheld material, and a policy
        artifact describing the withheld or partitioned material.
      </t>
      <t>
        This document defines the reporting boundary for Class B but does not
        require one universal withheld-material artifact format. Class B
        validation is therefore limited to the authoritative day artifact,
        disclosed batch metadata, any disclosed withheld-material commitments,
        and any anchor channels present in the bundle. Verifier output SHOULD
        explicitly state when fact-level recomputation was partial or was not
        attempted for withheld material.
      </t>
      <t>
        A Class C disclosure MUST be labeled as existence and timestamp
        evidence only and MUST NOT claim fact-level reproducibility.
      </t>
      <t>A Class C bundle MUST include:</t>
      <ul>
        <li>the canonical day artifact, and</li>
        <li>at least one timestamp proof artifact plus the metadata needed to bind it to the day artifact digest and disclose <tt>commitment_profile_id</tt>.</li>
      </ul>
      <t>
        Class C verification validates artifact-digest binding and external
        timestamp evidence only. It does not establish fact-level
        reproducibility.
      </t>
      <t>
        Class C verifier output SHOULD be reported as anchor-only evidence.
      </t>
      <t><strong>Bundle Selection Guidance</strong></t>
      <ul>
        <li>Class A is appropriate when the goal is public recomputation from disclosed canonical facts and authoritative artifacts, for example when a regulator or external researcher needs independent replay of the disclosed day.</li>
        <li>Class B is appropriate when the goal is partner or regulator review over a controlled disclosure set that still carries commitment and anchor evidence, for example when some record content must remain withheld while the committed day artifact is still audited.</li>
        <li>Class C is appropriate when the goal is existence and timestamp evidence without public fact-level reproducibility, for example when a party only needs to show that a committed artifact existed by a given time.</li>
      </ul>
      <t>
        When a verification manifest is present, it SHOULD include:
      </t>
      <ul>
        <li><tt>disclosure_class</tt>,</li>
        <li><tt>commitment_profile_id</tt>,</li>
        <li>artifact path and digest entries,</li>
        <li>per-channel anchor status,</li>
        <li>a list of checks executed, and</li>
        <li>a list of checks skipped together with the reason for each skip.</li>
      </ul>
    </section>

    <section numbered="true" toc="include" anchor="versioning">
      <name>Versioning</name>
      <t>
        This profile has several independent version surfaces:
      </t>
      <ul>
        <li>Document revision (for example <tt>-00</tt>, <tt>-01</tt>) is editorial and is not part of commitment output.</li>
        <li>Artifact schema versions are carried by the <tt>version</tt> fields in day and batch records.</li>
        <li><tt>commitment_profile_id</tt> identifies the canonical CBOR, hash, and Merkle rules that define commitment outputs.</li>
      </ul>
      <t>
        The commitment profile defined in this document is
        <tt>trackone-canonical-cbor-v1</tt>. If a verifier encounters an unsupported
        <tt>commitment_profile_id</tt>, it MUST reject the verification claim
        rather than silently using a fallback interpretation.
      </t>
      <t>
        This revision defines exactly one <tt>commitment_profile_id</tt> and
        does not define an allocation policy or registry for additional
        profile identifiers. Future <tt>commitment_profile_id</tt> values are
        out of scope for this document and would require separate
        specification and review.
      </t>
      <t>
        Bundles disclose the applicable <tt>commitment_profile_id</tt> via a
        verification manifest or equivalent bundle metadata. The required OTS
        sidecar metadata does not currently carry that identifier.
      </t>
    </section>

    <section numbered="true" toc="include" anchor="conformance-vectors">
      <name>Conformance Vectors</name>
      <t>
        Determinism claims in this profile are testable. When conformance
        vectors are published for a commitment profile, implementations that
        claim conformance to that profile MUST be able to reproduce them. For
        <tt>trackone-canonical-cbor-v1</tt>, the authoritative
        machine-readable vector corpus is published alongside the TrackOne
        reference implementation. The appendix in this document is
        explanatory only.
      </t>
      <t>Published vector sets SHOULD include coverage for:</t>
      <ul>
        <li>post-projection fact fixtures with fixed field types and values,</li>
        <li>empty day,</li>
        <li>single fact,</li>
        <li>odd leaf count,</li>
        <li>power-of-two leaf count,</li>
        <li>duplicate leaf hashes,</li>
        <li>genesis chaining,</li>
        <li>non-genesis chaining, and</li>
        <li>a full Class A disclosure example.</li>
      </ul>
      <t>
        Cross-implementation checks MUST verify byte-for-byte parity across
        independent implementations. Any mismatch in canonical bytes or roots
        is a conformance failure.
      </t>
      <t>
        Published vector bundles MUST include the
        <tt>commitment_profile_id</tt>.
      </t>
    </section>

    <section numbered="true" toc="include" anchor="security">
      <name>Security Considerations</name>
      <t>
        This profile does not introduce new cryptographic primitives. Its
        security depends on correct composition of existing primitives,
        accurate verifier reporting, and operational discipline around replay
        state, artifact handling, and proof collection.
      </t>
      <t><strong>Replay and Duplicate Suppression</strong></t>
      <t>
        The <tt>(dev_id, fc)</tt> replay unit enforces single-consumption: at
        most one committed fact per unique replay unit.
      </t>
      <t><strong>Tamper Evidence</strong></t>
      <t>
        Once a day artifact is anchored, mutation of that artifact changes its
        digest and invalidates the proof. Day chaining extends this property
        across days.
      </t>
      <t><strong>Proof Substitution</strong></t>
      <t>
        Sidecar metadata binds an artifact digest to a proof path. Verifiers
        MUST recompute the artifact digest independently.
      </t>
      <t><strong>Calendar Trust and Withholding</strong></t>
      <t>
        A compromised or unavailable calendar can delay or withhold proofs.
        Multi-calendar submission reduces single-calendar dependency but does
        not eliminate coordinated compromise risk.
      </t>
      <t><strong>Operational Misuse</strong></t>
      <t>
        Test, placeholder, or incomplete proofs MUST NOT be treated as
        production attestations.
      </t>
      <t><strong>Decision Boundary</strong></t>
      <t>
        This profile is not a standalone safety case. A successful
        verification result MUST NOT be used as the sole basis for autonomous
        actuation, safety-critical control, or regulatory sanction without
        deployment-specific policy, corroborating evidence, and human review.
      </t>
      <t><strong>Confidentiality Boundary</strong></t>
      <t>
        This profile addresses integrity and timing provenance only. Payload
        confidentiality remains the responsibility of the deployment's AEAD and
        key-management layers.
      </t>
      <t><strong>Pre-Commitment Censorship</strong></t>
      <t>
        This profile proves inclusion and timestamping of committed facts. It
        does not prove completeness of all observed or emitted frames.
      </t>
      <t><strong>Hash-Domain Separation</strong></t>
      <t>
        The current commitment profile does not prepend domain-separation
        bytes to leaf or parent hashes. This is acceptable for
        <tt>trackone-canonical-cbor-v1</tt> because the profile is frozen around the
        published implementation and conformance vectors, but implementers
        MUST treat that choice as part of the profile contract rather than as
        an accidental omission. Any future profile that introduces explicit
        leaf or parent domain separation MUST use a new
        <tt>commitment_profile_id</tt>.
      </t>
    </section>

    <section numbered="true" toc="include" anchor="privacy">
      <name>Privacy Considerations</name>
      <t>
        Telemetry payloads may include sensitive operational data. Operators
        SHOULD:
      </t>
      <ul>
        <li>minimize personally identifiable data in committed artifacts,</li>
        <li>separate identity metadata from measurement payload when possible,</li>
        <li>apply retention and access controls, and</li>
        <li>publish only data appropriate for the chosen disclosure class.</li>
      </ul>
      <t>
        Privacy-preserving disclosures remain valid, but they MUST NOT be
        described as publicly recomputable unless Class A conditions are met.
      </t>
    </section>

    <section numbered="true" toc="include" anchor="iana">
      <name>IANA Considerations</name>
      <t>This document has no IANA actions.</t>
      <t>It does not request:</t>
      <ul>
        <li>a CBOR tag allocation,</li>
        <li>a media type registration, or</li>
        <li>a new registry entry.</li>
      </ul>
      <t>
        The current profile is identified by in-band version and profile
        fields, not by IANA allocation.
      </t>
      <t>
        In particular, this revision defines only the document-specific
        <tt>commitment_profile_id</tt> <tt>trackone-canonical-cbor-v1</tt>.
        It does not establish a registry or general allocation mechanism for
        future commitment-profile identifiers.
      </t>
    </section>

    <section numbered="true" toc="include" anchor="interop-notes">
      <name>Interoperability Notes and Open Questions</name>
      <ul>
        <li>Media type strategy for canonical CBOR day artifacts.</li>
        <li>Whether a future revision should require a verification manifest for every interoperable producer profile rather than treating equivalent local bundle metadata as deployment-specific.</li>
        <li>How a future revision should reference the published commitment-family CDDL and vector corpus once multiple independent producers rely on them as primary conformance artifacts.</li>
        <li>Whether a future revision should standardize a universal Class B withheld-material artifact format.</li>
        <li>Whether future disclosure bundles should adopt COSE-MERKLE proof encodings.</li>
        <li>Registry strategy for disclosure and anchor-status vocabularies.</li>
        <li>Whether a future commitment profile should introduce domain separation.</li>
      </ul>
    </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="RFC8174" target="https://www.rfc-editor.org/info/rfc8174">
        <front>
          <title>Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words</title>
          <author fullname="Benjamin 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>
      </references>

      <references>
        <name>Informative References</name>
      <reference anchor="RFC3161" target="https://www.rfc-editor.org/rfc/rfc3161">
        <front>
          <title>Internet X.509 Public Key Infrastructure Timestamp 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="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>
      <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="NDJSON" target="https://github.com/ndjson/ndjson-spec">
        <front>
          <title>NDJSON: Newline Delimited JSON</title>
          <author>
            <organization>NDJSON Project</organization>
          </author>
          <date/>
        </front>
      </reference>
      <reference anchor="TRACKONE" target="https://github.com/bilalobe/trackone">
        <front>
          <title>TrackOne Reference Implementation</title>
          <author>
            <organization>TrackOne Project</organization>
          </author>
          <date year="2026"/>
        </front>
      </reference>
      <reference anchor="SCITT" target="https://datatracker.ietf.org/doc/draft-ietf-scitt-architecture/">
        <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="Cedric Fournet" initials="C." surname="Fournet"/>
          <author fullname="Yogesh Deshpande" initials="Y." surname="Deshpande"/>
          <author fullname="Steve Lasker" initials="S." surname="Lasker"/>
          <date year="2024"/>
        </front>
        <seriesInfo name="Internet-Draft" value="draft-ietf-scitt-architecture"/>
      </reference>
      <reference anchor="COSE-MERKLE" target="https://datatracker.ietf.org/doc/draft-ietf-cose-merkle-tree-proofs/">
        <front>
          <title>COSE Merkle Tree Proofs</title>
          <author fullname="Orie Steele" initials="O." surname="Steele"/>
          <author fullname="Henk Birkholz" initials="H." surname="Birkholz"/>
          <author fullname="Antoine Delignat-Lavaud" initials="A." surname="Delignat-Lavaud"/>
          <author fullname="Cedric Fournet" initials="C." surname="Fournet"/>
          <date year="2025"/>
        </front>
        <seriesInfo name="Internet-Draft" value="draft-ietf-cose-merkle-tree-proofs"/>
      </reference>
      <reference anchor="OTS" target="https://opentimestamps.org/">
        <front>
          <title>OpenTimestamps Protocol and Tooling</title>
          <author>
            <organization>OpenTimestamps Project</organization>
          </author>
          <date year="2016"/>
        </front>
      </reference>
      <reference anchor="RFC9334" target="https://www.rfc-editor.org/rfc/rfc9334">
        <front>
          <title>Remote ATtestation procedureS (RATS) Architecture</title>
          <author fullname="Henk Birkholz" initials="H." surname="Birkholz"/>
          <author fullname="Dave Thaler" initials="D." surname="Thaler"/>
          <author fullname="Michael Richardson" initials="M." surname="Richardson"/>
          <author fullname="Ned Smith" initials="N." surname="Smith"/>
          <author fullname="Wei Pan" initials="W." surname="Pan"/>
          <date year="2023" month="January"/>
        </front>
        <seriesInfo name="RFC" value="9334"/>
        <seriesInfo name="DOI" value="10.17487/RFC9334"/>
      </reference>
      </references>
    </references>

    <section numbered="true" toc="include" anchor="appendix-a">
      <name>Example Day Record (JSON Projection)</name>
      <t>
        This appendix shows a non-authoritative JSON projection of a day
        artifact. The authoritative artifact is the corresponding CBOR file.
      </t>
      <figure>
        <artwork type="json"><![CDATA[
{
  "version": 1,
  "site_id": "an-001",
  "date": "2025-10-07",
  "prev_day_root": "<64 zero hex chars>",
  "batches": [
    {
      "version": 1,
      "site_id": "an-001",
      "day": "2025-10-07",
      "batch_id": "an-001-2025-10-07-00",
      "merkle_root": "9d1f...c2",
      "count": 10,
      "leaf_hashes": [
        "01ab...",
        "7fe2..."
      ]
    }
  ],
  "day_root": "9d1f...c2"
}
]]></artwork>
      </figure>
    </section>

    <section numbered="true" toc="include" anchor="appendix-b">
      <name>Illustrative Conformance Vector Bundle</name>
      <t>
        The authoritative machine-readable conformance vector corpus for
        <tt>trackone-canonical-cbor-v1</tt> is published with the TrackOne
        reference implementation. The figure below is a reader-oriented sketch
        of the bundle shape and naming only; it is not the authoritative
        vector source.
      </t>
      <t>
        Wrapped hexadecimal values in this appendix are presentation-only; a
        verifier or implementer should concatenate adjacent lines without
        inserting whitespace.
      </t>
      <t>
        The fixtures below are reader-oriented logical record sketches, not
        the authoritative CBOR array encoding. They show the current
        post-projection logical content and the active commitment profile
        identifier, while the published vector corpus carries the exact
        encoded bytes and digests.
      </t>
      <t>
        In these reader-oriented sketches, <tt>kind</tt> is shown using the
        symbolic family name. In authoritative CBOR commitment bytes, the
        same field carries the numeric discriminator defined by the current
        profile; for the fixtures below, <tt>Custom</tt> corresponds to
        <tt>250</tt>.
      </t>
      <figure>
        <artwork type="ascii-art"><![CDATA[
commitment_profile_id:
  trackone-canonical-cbor-v1

fixture fact_a:
  pod_id: "0000000000000065"
  fc: 1
  ingest_time: 1772366400
  pod_time: null
  kind: Custom
  payload.temp_c: 21.5

fixture fact_b:
  pod_id: "0000000000000066"
  fc: 2
  ingest_time: 1772367000
  pod_time: null
  kind: Custom
  payload.temp_c: 22.0

fixture fact_c:
  pod_id: "0000000000000067"
  fc: 3
  ingest_time: 1772367600
  pod_time: null
  kind: Custom
  payload.temp_c: 22.5

class-a-bundle-v1:
  disclosure_class: A
  commitment_profile_id: trackone-canonical-cbor-v1
  required_artifact_1: facts/<fact-id>.cbor
  required_artifact_2: day/YYYY-MM-DD.cbor
  required_artifact_3: day/YYYY-MM-DD.cbor.ots
  required_artifact_4: day/YYYY-MM-DD.ots.meta.json
  verifier_check_1: day_artifact_validation
  verifier_check_2: fact_level_recompute
  verifier_check_3: ots_verification
]]></artwork>
      </figure>
      <t>
        The published machine-readable vector set carries the exact canonical
        bytes, digests, expected roots, and the applicable
        <tt>commitment_profile_id</tt>. This appendix remains illustrative and
        is not an authoritative conformance corpus.
      </t>
    </section>

    <section numbered="true" toc="include" anchor="appendix-c">
      <name>Minimal Pod Requirements</name>
      <t>
        This appendix records the minimum expectations for a constrained pod
        that emits framed telemetry under the current TrackOne reference
        transport profile. It is descriptive of the current deployment model,
        not a claim that all conforming deployments share identical hardware.
      </t>
      <ul>
        <li>The pod is not required to sign assertions or to emit SCITT statements.</li>
        <li>The pod MUST be able to produce framed transport messages consistent with <xref target="frame-contract"/>, including fresh 24-byte transport nonces under the local AEAD policy.</li>
        <li>Nonce generation MUST rely on a cryptographically strong pseudorandom source or an equivalent construction with explicit seed discipline. Weak or predictable PRNG state is out of profile.</li>
        <li>The pod or an immediately adjacent trusted transport component MUST preserve enough durable state to avoid replay ambiguity across the intended connectivity window.</li>
        <li>If uplink availability is intermittent, accepted-but-unsubmitted telemetry MUST either be durably buffered or be retransmittable from durable local state according to deployment policy.</li>
        <li>This document does not require one fixed storage budget. The practical tradeoff is between expected outage duration, frame rate, local retention policy, and the gateway's replay/admission contract.</li>
      </ul>
      <t>
        In the current reference deployment, the intermittency assumption
        primarily applies on the pod-to-gateway path. External timestamping or
        publication channels may also be delayed, but those delays do not
        change the pod-side framing requirements.
      </t>
    </section>

    <section numbered="true" toc="include" anchor="appendix-d">
      <name>Verification Manifest CDDL</name>
      <t>
        This appendix gives a minimum interoperable CDDL
        (<xref target="RFC8610"/>) shape for a verifier-facing manifest. It
        captures the bundle metadata needed by this document. A concrete
        deployment MAY publish a stricter JSON Schema or carry additional
        deployment-local fields, but it MUST NOT omit these fields when
        claiming parity with this manifest shape.
      </t>
      <sourcecode type="cddl"><![CDATA[
verification-manifest = {
  "disclosure_class": disclosure-class,
  "commitment_profile_id": tstr,
  "artifacts": { + tstr => artifact-ref },
  "channels": {
    ? "ots": channel-status,
    ? "tsa": channel-status,
    ? "peers": channel-status
  },
  "checks_executed": [* tstr],
  "checks_skipped": [* skipped-check]
}

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

skipped-check = {
  "check": tstr,
  "reason": tstr
}

channel-status = {
  "status":
    "verified" / "pending" / "missing" / "failed" / "skipped",
  ? "detail": tstr
}

disclosure-class = "A" / "B" / "C"
hex64 = text .regexp "[0-9a-f]{64}"
]]></sourcecode>
    </section>

    <section numbered="false" toc="include" anchor="acknowledgments">
      <name>Acknowledgments</name>
      <t>
        Early structural drafts of this document were prepared with AI writing
        assistance. All technical content, design decisions, and normative
        requirements were reviewed against the TrackOne implementation.
      </t>
      <t>
        The author thanks the OpenTimestamps project for the public calendar
        infrastructure used during validation.
      </t>
    </section>
  </back>
</rfc>
