<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>
<?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
<!-- generated by https://github.com/cabo/kramdown-rfc version 1.7.39 (Ruby 2.6.10) -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-holmgren-at-synchronization-00" category="std" submissionType="IETF" tocInclude="true" sortRefs="true" symRefs="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.34.0 -->
  <front>
    <title abbrev="AT Sync">Authenticated Transfer: Synchronization</title>
    <seriesInfo name="Internet-Draft" value="draft-holmgren-at-synchronization-00"/>
    <author fullname="Daniel Holmgren">
      <organization>Bluesky Social</organization>
      <address>
        <email>daniel@blueskyweb.xyz</email>
      </address>
    </author>
    <author fullname="Bryan Newbold">
      <organization>Bluesky Social</organization>
      <address>
        <email>bryan@blueskyweb.xyz</email>
      </address>
    </author>
    <date year="2026" month="June" day="04"/>
    <area>Applications and Real-Time Area</area>
    <workgroup>Authenticated Transfer</workgroup>
    <abstract>
      <?line 58?>

<t>This document describes synchronization mechanisms for public repositories as part of the Authenticated Transfer Protocol (ATP). It specifies both a low-latency streaming protocol over WebSocket, and a full-repository fetch mechanism over HTTP.</t>
    </abstract>
    <note removeInRFC="true">
      <name>About This Document</name>
      <t>
        Status information for this document may be found at <eref target="https://datatracker.ietf.org/doc/draft-holmgren-at-synchronization/"/>.
      </t>
      <t>
        Discussion of this document takes place on the
        Authenticated Transfer Working Group mailing list (<eref target="mailto:atp@ietf.org"/>),
        which is archived at <eref target="https://mailarchive.ietf.org/arch/browse/atp/"/>.
        Subscribe at <eref target="https://www.ietf.org/mailman/listinfo/atp/"/>.
      </t>
      <t>Source for this draft and an issue tracker can be found at
        <eref target="https://github.com/ietf-wg-atp/drafts"/>.</t>
    </note>
  </front>
  <middle>
    <?line 62?>

<section anchor="intro">
      <name>Introduction</name>
      <t>The Authenticated Transfer Protocol (ATP) enables the creation of decentralized networks for publication of self-certifying data. An introduction to the overall protocol architecture is given in <xref target="AT-ARCH"/>.</t>
      <t>The protocol provides efficient synchronization mechanisms for propagating public repository state changes across the network, supporting both low-latency streaming updates and bulk synchronization scenarios. Synchronization can take place between any two parties, from an upstream publisher to a downstream consumer. Intermediate parties can redistribute ("relay") data, and consumers can cryptographically verify the integrity and authenticity of received repository data. This allows for flexibility in network topology to improve overall network resilience and efficiency.</t>
      <t>Repositories are complete (they contain all current public records for the account), and consumers can confirm the integrity over the entire repository to detect dropped or withheld updates. The protocol allows consumers to maintain partial replicas (eg, of only specific record types). It is also possible to request verifiable "inclusion proofs" for individual records on demand.</t>
      <t>This document describes two synchronization mechanisms. Complete repositories can be serialized (as described in <xref target="ATREPO"/>) and fetched over HTTP as a snapshot. Updates to one or more repositories can be distributed as a stream of messages. This document describes both a generic structure and semantics for streaming messages, and a specific WebSocket transport and message encoding scheme.</t>
    </section>
    <section anchor="accounts">
      <name>Account Hosting</name>
      <t>Each node in the network which synchronizes, stores, and distributes repository data maintains hosting status for each account. The status indicates whether the account is overall "active", or has been temporarily or permanently removed from the network, in which case repository data should not be synchronized further. Hosting status can be set by the account holder themselves or their canonical hosting provider, and changes propagate to downstream consumers throughout the network. Each downstream service or node in the network may set a local inactive hosting status, declining to distribute that account's repository data.</t>
      <t>Each account has a persistent identifier which can be resolved to both a public key and a canonical hosting location. Account identifier systems and their resolution mechanisms are out of scope for this document. Account hosting status is maintained and transmitted over the synchronization protocol, separate from the lifecycle of account identifiers.</t>
      <t>The hosting status itself for accounts may always be redistributed, even for inactive accounts.</t>
      <section anchor="account-status">
        <name>Hosting Status</name>
        <t>Account hosting status at any point in time can be summarized as the boolean state of being "active" or not. If the account hosting status is not active, repository data for that account MUST NOT be redistributed. Additional context may be provided using a "status" vocabulary, represented as a string. Account status is represented and transmitted as an <tt>active</tt> boolean and a <tt>status</tt> string together.</t>
        <t>The defined status values and their meanings are:</t>
        <ul spacing="normal">
          <li>
            <t><tt>deleted</tt> (<tt>active</tt> is false): the user or host has deleted the account. Account data SHOULD be removed from the service's infrastructure within a reasonable time frame. Implied to be permanent, but MAY be reverted.</t>
          </li>
          <li>
            <t><tt>deactivated</tt> (<tt>active</tt> is false): the user has temporarily paused the account. Account data MUST NOT be redistributed but does not need to be deleted from infrastructure. Implied time-limited.</t>
          </li>
          <li>
            <t><tt>takendown</tt> (<tt>active</tt> is false): the host or service has taken down the account. Implied to be indefinite in duration, but MAY be reverted.</t>
          </li>
          <li>
            <t><tt>suspended</tt> (<tt>active</tt> is false): the host or service has temporarily paused the account. Implied time-limited.</t>
          </li>
        </ul>
        <t>Two additional status values are relevant to the synchronization process itself, and do not imply that the overall hosting status is inactive:</t>
        <ul spacing="normal">
          <li>
            <t><tt>desynchronized</tt> (<tt>active</tt> MAY be true): the service has detected a problem synchronizing the account's repository and may be missing content.</t>
          </li>
          <li>
            <t><tt>throttled</tt> (<tt>active</tt> MAY be true): the service has paused processing of new content for this account because a rate limit has been exceeded.</t>
          </li>
        </ul>
        <t>New status values may be defined in the future. Producers MAY emit <tt>status</tt> strings not listed above, and consumers MUST tolerate unrecognized values. Consumers MUST use the <tt>active</tt> boolean as the authoritative indicator of overall account visibility, treating the <tt>status</tt> string as clarification that may inform more specific behavior (for example, whether to delete cached data versus retain it pending reactivation).</t>
        <t>Producers expose an HTTPS request-response operation that, given an account identifier, returns the producer's current hosting status for that account. This allows consumers to query the present state of an account without subscribing to the message stream — for example, when establishing initial state for an account they have not seen before, or when reconciling diverging upstream reports.</t>
        <t>The details of the HTTPS request endpoint, the URL path, and the response media type are not specified by this document.</t>
      </section>
      <section anchor="account-status-propagation">
        <name>Status Propagation</name>
        <t>Account hosting status is not cryptographically authenticated. Status propagates hop-by-hop via streaming synchronization: each node emits an <tt>#account</tt> message (<xref target="msg-account"/>) to downstream consumers when the hosting status for an account changes. For intermediate synchronization nodes, this includes changes driven by an <tt>#account</tt> message received from an upstream.</t>
        <t>Intermediaries MAY override their upstream's status. For example, a relaying node may take down an account that an upstream still reports as active. Such overrides are propagated downstream as <tt>#account</tt> messages from the intermediary.</t>
        <t>When an upstream service is unreachable, downstream services SHOULD retain the previously reported status for some implementation-defined period rather than immediately changing the account to an inactive state. This preserves availability across short upstream outages, and increases resiliency of the network.</t>
        <t>When account status reported by different upstreams diverges (for example, due to differing moderation policies, or a transient network partition between an upstream and its own upstream), services apply their own policies to reconcile. Querying the account's current authoritative hosting service directly is one way to resolve such ambiguity.</t>
      </section>
    </section>
    <section anchor="full-sync">
      <name>Full Repository Sync</name>
      <t>Consumers can retrieve a full serialized snapshot of an account's current repository at any point in time. This can be used to initialize synchronization state for the account during a bootstrap or backfill phase, or to re-synchronize (<xref target="resync"/>) and reconcile after any discontinuity in the streaming synchronization mechanism. It is also an option for applications and use-cases which do not require continuous updates or synchronization over time.</t>
      <t>Producers expose an HTTP API endpoint which takes an account identifier as a parameter, and returns the serialized repository as the response body. If the account hosting status at the producer is not "active", this is indicated in an error response.</t>
      <t>A producer MAY redirect the request to another producer that holds the requested data — for example, a relaying service redirecting to the account's canonical host, or to a mirroring service with the content cached. Consumers SHOULD follow such HTTP redirects when re-synchronizing per <xref target="resync"/>.</t>
    </section>
    <section anchor="stream-sync">
      <name>Streaming Sync</name>
      <t>This section describes a low-latency streaming synchronization mechanism which allows consumers to receive repository updates with minimal latency through a pull-based WebSocket <xref target="RFC6455"/> connection. Streams can contain updates from many distinct account repositories, even aggregating all updates in the network. In addition to repository updates, they include updates to account hosting status and network identities. Whether encompassing the full network or any subset of it, a stream is often referred to as a "firehose".</t>
      <t>To ensure reliable delivery, each message on a given stream is given a monotonically-increasing sequence number. Consumers can track their progress on processing messages and reconnect to the stream using the last-processed sequence number as a cursor value as needed. Producers can maintain a "backfill window" of recently transmitted messages. All consumers receive the same messages in the same order with the same sequence numbers.</t>
      <t>The stream synchronization mechanism allows consumers to maintain complete indices of authenticated repository contents without needing to store complete copies of the repository MST structure. This significantly reduces storage overhead.</t>
      <section anchor="diffs">
        <name>Repository Diffs</name>
        <t>A repository diff carries the data that changed between two repository revisions: the new commit, any new MST nodes, and any created or updated record blocks. Applying a diff to a copy of the prior repository state results in the complete repository at the new revision. Repository diffs are used in the streaming synchronization mechanism.</t>
        <t>The commits within diffs are signed. Receiving parties can always verify those signatures, and the integrity of the blocks in the diff itself. But unless the receiving party has a full copy of the repository just prior to the diff, it can not verify the overall integrity of the diff or the final state of the repository. In particular, if record deletion operations were included in the diff, the receiving party can not enumerate or verify which records were impacted just from the diff.</t>
        <t>This section describes an "operation inversion" mechanism which allows receiving parties to verify the integrity of diffs when combined with metadata about the record-level operations encapsulated by the diff.</t>
        <section anchor="diff-format">
          <name>Diff Serialization Format</name>
          <t>Diffs use the same serialization format as complete repositories (described in <xref target="ATREPO"/>), with the commit block serving as the root. A diff MUST include:</t>
          <ul spacing="normal">
            <li>
              <t>The new commit block.</t>
            </li>
            <li>
              <t>All created and updated record blocks.</t>
            </li>
            <li>
              <t>All MST nodes in the current repository that did not exist in the prior revision.</t>
            </li>
          </ul>
          <t>Required blocks MUST be included in the diff regardless of their presence in earlier repository history. For example, if an MST node was previously present in the repository, then deleted, and subsequently reintroduced during the range that the diff represents, the diff MUST include that block.</t>
          <t>Deleted records and prior versions of updated records are excluded from diffs.</t>
          <t>With the exception of deleted record data, a diff MAY include additional blocks; receivers SHOULD ignore them.</t>
        </section>
        <section anchor="operation-inversion">
          <name>Operation Inversion</name>
          <t>A diff can be accompanied by an explicit operation list declaring the record-level creates, updates, and deletes it represents, along with a claimed previous repository tree root hash. Operation inversion verifies that this declared list is accurate and complete.</t>
          <t>To invert a diff against its declared operations:</t>
          <ol spacing="normal" type="1"><li>
              <t>Extract the diff's MST nodes into a partial tree structure</t>
            </li>
            <li>
              <t>For each entry in the operation list, apply the inverse operation to the partial MST: each "create" becomes a "delete", "delete" becomes "create", and "update" reverts the record value to the previous version</t>
            </li>
            <li>
              <t>Compute the root hash of the resulting MST</t>
            </li>
            <li>
              <t>Compare the computed root hash to the claimed previous root hash</t>
            </li>
          </ol>
          <t>If the hashes match, the operation list is accurate and exhaustive. If they differ, either the operation list is incomplete or the diff is internally inconsistent; in either case the diff MUST be rejected.</t>
          <t>Producers of diffs intended to support operation inversion MUST include, in addition to the blocks required by <xref target="diff-format"/>, the MST nodes for keys directly adjacent (in lexicographic order) to mutated keys. Without these adjacent nodes, the inverse operation cannot be correctly applied to the partial MST. Diffs carried in streaming synchronization messages (<xref target="msg-commit"/>) MUST satisfy this requirement, since stateless consumers rely on operation inversion for verification.</t>
          <t>Receivers can track repository root hash values for each account and verify the claimed root hashes provided with the diff. This fixed-size state is significantly smaller than maintaining full repository data.</t>
        </section>
      </section>
      <section anchor="websocket">
        <name>WebSocket Transport</name>
        <t>A consumer (client) establishes a WebSocket connection <xref target="RFC6455"/> to the producer's (server) stream endpoint. Secure WebSockets (using TLS) MUST be used for any internet-facing deployment.</t>
        <t>Once the connection is established, the producer sends a sequence of binary WebSocket frames to the consumer. Each frame carries a single message. Servers SHOULD ignore stream messages sent by the consumer: the protocol defined in this document is server-to-client only.</t>
        <t>Servers and clients SHOULD implement a keepalive system using Ping and Pong WebSocket messages.</t>
        <section anchor="frame-format">
          <name>Frame Format</name>
          <t>Each binary WebSocket frame contains two CBOR-encoded objects concatenated together: a header followed by a payload. Both objects MUST follow the deterministic CBOR encoding rules defined in <xref target="ATREPO"/>.</t>
          <t>The header contains:</t>
          <ul spacing="normal">
            <li>
              <t><tt>op</tt> (integer, REQUIRED): the frame operation. The value <tt>1</tt> indicates a normal message; the value <tt>-1</tt> indicates an error.</t>
            </li>
            <li>
              <t><tt>t</tt> (string, REQUIRED when <tt>op = 1</tt>): the message-type name, prefixed with <tt>#</tt>. For example, <tt>#commit</tt> for a commit message.</t>
            </li>
          </ul>
          <t>The payload is a CBOR object whose schema is determined by the message type indicated in the header. Payloads are always CBOR objects, never arrays or scalars.</t>
          <t>Producers MAY include additional fields beyond those defined for a given message type, and consumers MUST tolerate unknown fields. Strict schema validation is not performed on stream messages.</t>
          <t>A frame MUST NOT exceed 5 MB in total size, inclusive of the header, payload, and CBOR encoding overhead.</t>
        </section>
        <section anchor="error-frames">
          <name>Error Frames</name>
          <t>When <tt>op</tt> is <tt>-1</tt>, the frame is an error frame. The payload contains:</t>
          <ul spacing="normal">
            <li>
              <t><tt>error</tt> (string, REQUIRED): a short machine-readable error name.</t>
            </li>
            <li>
              <t><tt>message</tt> (string, OPTIONAL): a human-readable description of the error.</t>
            </li>
          </ul>
          <t>After sending an error frame, the producer MUST close the WebSocket connection.</t>
        </section>
        <section anchor="pre-upgrade-errors">
          <name>Pre-Upgrade HTTP Errors</name>
          <t>If the producer rejects the WebSocket upgrade request itself, it responds with a standard HTTP status code rather than an error frame. Response bodies SHOULD be JSON containing <tt>error</tt> and <tt>message</tt> fields matching the error-frame schema, but consumers MUST tolerate other body content.</t>
        </section>
      </section>
      <section anchor="cursors">
        <name>Cursors and Resumption</name>
        <t>Synchronization streams include per-message sequence numbers to improve transmission reliability. Sequence numbers are positive integers that increase monotonically across the stream. Sequence semantics are flexible, and they may contain arbitrary gaps between consecutive messages.</t>
        <t>Consumers track the last sequence number they successfully processed and can specify this as a cursor when reconnecting to receive any missed messages within the provider's backfill window. Consumers are responsible for managing and persisting cursor state themselves: producers do not maintain consumer-specific state across connections. The scope of a cursor is the (hostname, endpoint) pair: a cursor value is meaningful only when reconnecting to the same host and stream endpoint that issued it.</t>
        <t>Sequence numbers MUST NOT be repeated by producers on the same (hostname, endpoint) pair. If a producer must reset sequence numbers for any reason, it MUST start with a number higher than any previously broadcast.</t>
        <t>Sequence numbers are integers in the range <tt>[1, 2^53)</tt>. The upper bound is chosen so that cursors are exactly representable in 64-bit IEEE-754 floating point.</t>
        <t>Stream behavior depends on the cursor value specified during connection:</t>
        <ul spacing="normal">
          <li>
            <t><strong>No cursor specified</strong>: The provider begins transmitting from the current stream position, providing only new messages generated after the connection is established.</t>
          </li>
          <li>
            <t><strong>Future cursor</strong>: When the requested cursor exceeds the current stream sequence number, the provider sends an error message and closes the connection.</t>
          </li>
          <li>
            <t><strong>Cursor within backfill window</strong>: The provider transmits all persisted messages with sequence numbers greater than or equal to the requested cursor, in order, then continues with the stream once caught up.</t>
          </li>
          <li>
            <t><strong>Cursor older than backfill window</strong>: The provider sends an informational message indicating that the requested cursor is too old, then begins transmission at the oldest available message, sends the entire backfill window, and continues with the stream.</t>
          </li>
          <li>
            <t><strong>Cursor value of 0</strong>: The provider treats this as a request for the complete available history, starting at the oldest available message, transmitting the entire backfill window, then continuing with the stream.</t>
          </li>
        </ul>
      </section>
      <section anchor="msg-types">
        <name>Message Types</name>
        <t>The repository synchronization stream uses four message types: <tt>#commit</tt>, <tt>#sync</tt>, <tt>#account</tt>, and <tt>#identity</tt>. This section describes the schema and semantics of these messages. Some fields are common across all message types.</t>
        <section anchor="msg-common">
          <name>Common Message Fields</name>
          <t>The following fields are common to all message payloads:</t>
          <ul spacing="normal">
            <li>
              <t><tt>seq</tt> (integer, REQUIRED): the sequence number (cursor; see <xref target="cursors"/>) of this message.</t>
            </li>
            <li>
              <t><tt>did</tt> (string, REQUIRED): the account identifier of the repository this message concerns. For historical reasons the <tt>#commit</tt> message uses the field name <tt>repo</tt> rather than <tt>did</tt> for this purpose; the value has the same meaning.</t>
            </li>
            <li>
              <t><tt>time</tt> (string, REQUIRED): an ISO 8601 datetime string indicating when the message was emitted. This timestamp is informational and is not authoritative for any verification purpose.</t>
            </li>
          </ul>
        </section>
        <section anchor="msg-commit">
          <name><tt>#commit</tt> Message</name>
          <t>A <tt>#commit</tt> message represents a repository update, as an atomic set of record operations. The message contains a repository diff combined with supporting metadata.</t>
          <t>The payload contains:</t>
          <ul spacing="normal">
            <li>
              <t><tt>seq</tt> (integer, REQUIRED): see <xref target="msg-common"/>.</t>
            </li>
            <li>
              <t><tt>repo</tt> (string, REQUIRED): the account identifier of the repository (see <xref target="msg-common"/>; this is the historical name of the <tt>did</tt> field). MUST match the <tt>did</tt> field in the commit object enclosed in <tt>blocks</tt>.</t>
            </li>
            <li>
              <t><tt>time</tt> (string, REQUIRED): see <xref target="msg-common"/>.</t>
            </li>
            <li>
              <t><tt>rev</tt> (string, REQUIRED): the new revision identifier of the repository after these modifications. MUST match the <tt>rev</tt> field in the commit object enclosed in <tt>blocks</tt>.</t>
            </li>
            <li>
              <t><tt>since</tt> (string, REQUIRED, nullable): the revision identifier of the repository immediately prior to this commit. May be null only for the first commit of a repository.</t>
            </li>
            <li>
              <t><tt>commit</tt> (hash link, REQUIRED): reference to the new commit object. MUST match the hash of the commit object enclosed in <tt>blocks</tt>.</t>
            </li>
            <li>
              <t><tt>blocks</tt> (byte string, REQUIRED): the serialized diff (as defined in <xref target="diffs"/>) carrying all blocks required to invert and verify the operations in this message.</t>
            </li>
            <li>
              <t><tt>ops</tt> (array, REQUIRED): the set of record operations encapsulated by this message. Multiple operations on the same record (path) are not allowed within a commit. Each entry is an object containing:
              </t>
              <ul spacing="normal">
                <li>
                  <t><tt>action</tt> (string, REQUIRED): one of <tt>create</tt>, <tt>update</tt>, or <tt>delete</tt>.</t>
                </li>
                <li>
                  <t><tt>path</tt> (string, REQUIRED): the repository path of the record being mutated.</t>
                </li>
                <li>
                  <t><tt>cid</tt> (hash link, REQUIRED, nullable): the hash link of the new record at this path, or <tt>null</tt> for <tt>delete</tt> actions.</t>
                </li>
                <li>
                  <t><tt>prev</tt> (hash link, OPTIONAL): the hash link of the prior record at this path. Present for <tt>update</tt> and <tt>delete</tt> actions; absent for <tt>create</tt>.</t>
                </li>
              </ul>
            </li>
            <li>
              <t><tt>prevData</tt> (hash link, REQUIRED): the root hash of the repository's MST in the previous revision (the <tt>data</tt> field in the commit object). Used for operation-inversion validation as described in <xref target="streaming-validation"/>.</t>
            </li>
            <li>
              <t><tt>tooBig</tt> (boolean, REQUIRED): retained for compatibility with earlier versions of this protocol. Producers MUST emit this field with the value <tt>false</tt>. Consumers MUST ignore the field's value.</t>
            </li>
            <li>
              <t><tt>blobs</tt> (array, REQUIRED): retained for compatibility with earlier versions of this protocol. Producers MUST emit this field as an empty array. Consumers MUST ignore the field's contents.</t>
            </li>
          </ul>
          <t>A <tt>#commit</tt> message MUST contain no more than 200 entries in <tt>ops</tt>. The <tt>blocks</tt> field MUST NOT exceed 2 MB. Any single record block within <tt>blocks</tt> MUST NOT exceed 1 MB. Repository updates exceeding these limits MUST be communicated through <tt>#sync</tt> message instead.</t>
          <t>A <tt>#commit</tt> message with an empty <tt>ops</tt> array (e.g., a commit issued solely to advance <tt>rev</tt> after a key rotation) is valid.</t>
          <t>Note that the full message is <em>not</em> cryptographically authenticated end-to-end (from the origin account itself). Only the commit object contained within the <tt>blocks</tt> field is signed, with other blocks covered by proof chains. The <tt>ops</tt> array is <em>not</em> authenticated and must be verified via operation inversion.</t>
        </section>
        <section anchor="msg-sync">
          <name><tt>#sync</tt> Message</name>
          <t>A <tt>#sync</tt> message declares the current state of a repository, regardless of the previous state. Sync messages are emitted when commit-message continuity cannot be maintained: large mutations exceeding the limits in <xref target="msg-commit"/>, recovery from data loss or corruption, or account migration between hosting providers.</t>
          <t>The payload contains:</t>
          <ul spacing="normal">
            <li>
              <t><tt>seq</tt> (integer, REQUIRED): see <xref target="msg-common"/>.</t>
            </li>
            <li>
              <t><tt>did</tt> (string, REQUIRED): see <xref target="msg-common"/>. MUST match the <tt>did</tt> field in the commit object encapsulated in <tt>blocks</tt>.</t>
            </li>
            <li>
              <t><tt>time</tt> (string, REQUIRED): see <xref target="msg-common"/>.</t>
            </li>
            <li>
              <t><tt>rev</tt> (string, REQUIRED): the current revision identifier of the repository. MUST match the <tt>rev</tt> field in the commit object encapsulated in <tt>blocks</tt>.</t>
            </li>
            <li>
              <t><tt>blocks</tt> (byte string, REQUIRED): a serialized stream containing only the current commit object. Receivers reconstruct full repository state by fetching the complete repository as described in <xref target="resync"/>.</t>
            </li>
          </ul>
          <t>A <tt>#sync</tt> message provides a reset point that signals consumers to resynchronize against the current authoritative state without requiring knowledge of the intervening changes.</t>
          <t>A <tt>#sync</tt> message with a <tt>rev</tt> which is lower or equal to the previously tracked revision for an account would constitute a "rollback" and should be ignored. The commit object signature (within the <tt>blocks</tt> field) should also be verified, and the message rejected if validation fails.</t>
        </section>
        <section anchor="msg-account">
          <name><tt>#account</tt> Messages</name>
          <t>An <tt>#account</tt> message indicates a change in account hosting status for an indicated account. See <xref target="account-status"/> for details and semantics.</t>
          <t>The payload contains:</t>
          <ul spacing="normal">
            <li>
              <t><tt>seq</tt> (integer, REQUIRED): see <xref target="msg-common"/>.</t>
            </li>
            <li>
              <t><tt>did</tt> (string, REQUIRED): see <xref target="msg-common"/>.</t>
            </li>
            <li>
              <t><tt>time</tt> (string, REQUIRED): see <xref target="msg-common"/>.</t>
            </li>
            <li>
              <t><tt>active</tt> (boolean, REQUIRED): whether the account is currently active on the emitting service.</t>
            </li>
            <li>
              <t><tt>status</tt> (string, OPTIONAL): a short status code describing the account state.</t>
            </li>
          </ul>
          <t>Note that account messages are <em>not</em> cryptographically authenticated end-to-end, and that they have hop-by-hop semantics.</t>
        </section>
        <section anchor="msg-identity">
          <name><tt>#identity</tt> Message</name>
          <t>An <tt>#identity</tt> message indicates a possible change to the resolution result of an account identifier.</t>
          <t>Note that identity messages are <em>not</em> cryptographically authenticated end-to-end. Consumers SHOULD invalidate any cached identity metadata for the named account on receipt of this message, and then re-resolve the identifier.</t>
          <t>The payload contains:</t>
          <ul spacing="normal">
            <li>
              <t><tt>seq</tt> (integer, REQUIRED): see <xref target="msg-common"/>.</t>
            </li>
            <li>
              <t><tt>did</tt> (string, REQUIRED): see <xref target="msg-common"/>.</t>
            </li>
            <li>
              <t><tt>time</tt> (string, REQUIRED): see <xref target="msg-common"/>.</t>
            </li>
            <li>
              <t><tt>handle</tt> (string, OPTIONAL): included for historical reasons. Non-authoritative.</t>
            </li>
          </ul>
          <t><tt>#identity</tt> messages are best-effort: producers MAY emit them redundantly when no underlying change has occurred, and MAY fail to emit them when a change has occurred. Consumers SHOULD NOT rely on <tt>#identity</tt> messages as the sole signal of identity change.</t>
        </section>
      </section>
      <section anchor="streaming-validation">
        <name>Commit Validation</name>
        <t>Validating a <tt>#commit</tt> message establishes both that the message is internally consistent (its declared operations match the diff it carries) and that it matches the prior state of the account's repository from the perspective of the consumer.</t>
        <t>For each <tt>#commit</tt> message received, consumers MUST perform the following steps:</t>
        <ol spacing="normal" type="1"><li>
            <t>Verify wire-level fields: that the frame parses as deterministic CBOR, that the payload satisfies the schema in <xref target="msg-commit"/>, and that the size limits in <xref target="msg-commit"/> are not exceeded. Otherwise the message MUST be rejected.</t>
          </li>
          <li>
            <t>Parse the repository diff from <tt>blocks</tt>, verifying the deterministic CBOR encoding, schema, and syntax of all fields of the commit and MST nodes. All created and updated record blocks must be present, but the content and internal structure of records are not validated at this stage. If the repository diff is invalid, the message MUST be rejected.</t>
          </li>
          <li>
            <t>Apply operation inversion to the repository diff MST using the <tt>ops</tt> array, and match against the message's claimed <tt>prevData</tt>, as per <xref target="operation-inversion"/>. If inversion fails, the message MUST be rejected.</t>
          </li>
          <li>
            <t>Verify the commit signature using the signing key resolved from the account identifier. If the signature is invalid, the message MUST be rejected.</t>
          </li>
          <li>
            <t>Confirm that the message's <tt>rev</tt> is strictly greater than the previously observed <tt>rev</tt> for this account. Otherwise the message MUST be ignored.</t>
          </li>
          <li>
            <t>Cross-check the message's <tt>prevData</tt> field against the consumer's previously seen <tt>data</tt> for this account. If they differ, the consumer has become desynchronized for this account and MUST initiate re-synchronization as defined in <xref target="resync"/>.</t>
          </li>
        </ol>
        <t>A signature failure at step 4 might indicate a recent key rotation rather than a malicious commit. Consumers SHOULD refresh the cached identity for the account and retry verification before rejecting the message.</t>
      </section>
      <section anchor="resync">
        <name>Re-synchronization</name>
        <t>When a consumer detects desynchronization, either through a disjunction in commit history or a <tt>sync</tt> message that does not match their local state, they must perform a complete re-synchronization process to restore consistency with the current repository state.</t>
        <t>Re-synchronization requires fetching and processing the full repository structure, though the record contents themselves are optional depending on the consumer's needs. If the repository data is delivered in pre-order traversal, it can be validated incrementally as it is received.</t>
        <t>Parsing the repository structure produces a mapping of keys (repository paths) to record versions (hashes) that represents the complete repository state. This key-to-hash mapping can be compared against existing local state to identify discrepancies and re-establish synchronization. Once validated, this mapping establishes the new repository state against which future commit messages can be applied.</t>
        <t>Consumers SHOULD prefer requesting full repository data from their direct upstream rather than the resolved canonical host for the repository. Direct upstreams MAY coalesce and cache snapshot requests, or redirect consumers to alternative sources where appropriate. This reduces correlated load spikes on canonical hosts caused by re-synchronization message broadcast.</t>
        <t>During the re-synchronization process, any incoming commit messages for the repository should be buffered rather than processed immediately. Once re-synchronization completes successfully, these buffered commits can be validated and applied in sequence to bring the consumer fully up to date with the current repository state.</t>
      </section>
    </section>
    <section anchor="security">
      <name>Security Considerations</name>
      <t>Security considerations for the repository format itself, including CBOR processing limits and MST structural validation, are covered in <xref target="ATREPO"/>.</t>
      <section anchor="security-resources">
        <name>Resource Abuse</name>
        <t>A producer that routinely emits <tt>#sync</tt> messages could cause consumers to repeatedly fetch full repository snapshots, which is substantially more expensive than processing <tt>#commit</tt> messages. Similarly, a producer that rapidly updates the same key or issues many small commits can amplify message volume and bandwidth costs on downstream consumers. Consumers should apply rate limits and bandwidth budgets per repository, and may disconnect or deprioritize producers whose message patterns appear abusive.</t>
      </section>
      <section anchor="security-rewinds">
        <name>Repository Rewinds</name>
        <t>Intermediaries that relay firehose messages can present a consumer with an outdated view of a repository by replaying older commits or declining to forward newer ones. The <tt>rev</tt> field on each commit can help consumers detect this: a received commit whose <tt>rev</tt> is not greater than the most recently observed <tt>rev</tt> for that repository may indicate that the producer is serving a rewound view. In situations such as this, consumers can cross-check the latest observed <tt>rev</tt> against the canonical host for the repository.</t>
      </section>
      <section anchor="security-ssrf">
        <name>Server-Side Request Forgery</name>
        <t>Several aspects of synchronization involve following URLs or host endpoints derived from untrusted input: account-identifier resolution, retrieval of full repository data from a hosting service, and following redirects between hosts. Consumers MUST validate URLs derived from untrusted input before issuing requests, including any URLs reached via HTTP redirects. In particular, requests to internal-network addresses, loopback addresses, and link-local addresses MUST be rejected unless explicitly permitted by configuration.</t>
      </section>
      <section anchor="security-validation-responsibility">
        <name>Validation Responsibility</name>
        <t>Intermediaries that relay messages MAY apply some validation checks (for example, signature verification or size enforcement) before relaying. Consumers MUST NOT treat upstream relaying as evidence of validity: every consumer is ultimately responsible for performing the verification rules in <xref target="streaming-validation"/> on each message it processes.</t>
      </section>
    </section>
    <section anchor="iana-considerations">
      <name>IANA Considerations</name>
      <t>This document has no IANA actions.</t>
    </section>
  </middle>
  <back>
    <references anchor="sec-combined-references">
      <name>References</name>
      <references anchor="sec-normative-references">
        <name>Normative References</name>
        <reference anchor="RFC6455">
          <front>
            <title>The WebSocket Protocol</title>
            <author fullname="I. Fette" initials="I." surname="Fette"/>
            <author fullname="A. Melnikov" initials="A." surname="Melnikov"/>
            <date month="December" year="2011"/>
            <abstract>
              <t>The WebSocket Protocol enables two-way communication between a client running untrusted code in a controlled environment to a remote host that has opted-in to communications from that code. The security model used for this is the origin-based security model commonly used by web browsers. The protocol consists of an opening handshake followed by basic message framing, layered over TCP. The goal of this technology is to provide a mechanism for browser-based applications that need two-way communication with servers that does not rely on opening multiple HTTP connections (e.g., using XMLHttpRequest or s and long polling). [STANDARDS-TRACK]</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="6455"/>
          <seriesInfo name="DOI" value="10.17487/RFC6455"/>
        </reference>
        <reference anchor="ATREPO">
          <front>
            <title>Authenticated Transfer Repository</title>
            <author fullname="Daniel Holmgren">
              <organization>Bluesky Social</organization>
            </author>
            <author fullname="Bryan Newbold">
              <organization>Bluesky Social</organization>
            </author>
            <date year="2026" month="June"/>
          </front>
        </reference>
      </references>
      <references anchor="sec-informative-references">
        <name>Informative References</name>
        <reference anchor="AT-ARCH">
          <front>
            <title>Authenticated Transfer: Architecture Overview</title>
            <author fullname="Bryan Newbold">
              <organization>Bluesky Social</organization>
            </author>
            <author fullname="Daniel Holmgren">
              <organization>Bluesky Social</organization>
            </author>
            <date year="2026" month="June"/>
          </front>
        </reference>
      </references>
    </references>
    <?line 360?>

<section numbered="false" anchor="acknowledgments">
      <name>Acknowledgments</name>
      <t>TODO: acknowledge</t>
    </section>
  </back>
  <!-- ##markdown-source:
H4sIAPP2IWoAA9V9647cxpLm/3oKovXD3UZVre1jn120McC0LWmPFralkdpj
LBZYNIvMqqbFIjm8dKssCJiHmCfcJ9mILyIyk5eSdDwzWKx/WFIVmRkZGfdb
bTabVV/0pbtOLm6G/t5VfZGlvcuT2zatur1rr5M3pyq7b+uq+CPti7q6WKW7
Xese+I1bfHmx4lcOdXu6Tro+X63yOqvSI62Zt+m+39zX5fHQumqT9ptuvNjm
q69W3bA7Fl1H/+pPDb304tnt81U1HHe0+Wpoclq7u17xH9errK46V3UDfUAA
fLVKW5cyIE1TMty0RpekVZ68dmm5uS2OLrmhJy5Wj3X79tDWQ3P2nBert+5E
j+W0sqsG2itJPvVGkgjEF7/R8kV1SP47v8CfH9OipM/TvvnHwvX7bd0e+OND
0d8PO/qCP9w8HggjzX8BkrqL1SqlbWo6c7KhR5NkP5SloPFpWhWuTP6meMS3
tGJqWLxOfigH1709JW/qrEhLPOAEhhzv/uNOHnh0u+270x/zLX5oT2mV/OIe
d3WZ/10b7PjN6fqrqm6P9OoD8Pj6+Y9//fa77/ivN7evn716eY0FPk54dIdN
3RU9kdUFHgcFLJBU65/DYx6L+G+jf34KnZ914uXl5qj75GKrotrHCLq53dy8
/vFvn4OWa6Lo7L7oXdYPrUtePrj2oXCPcxRVAhBjKI3e+Ewc/YlD/QcjfLvd
rlabzSZJd13fplm/Wt3eF11CwmU4El6S3HVZW+xcl0yESnJ02T0t3B27hNCc
NMOOpEPi6aSgV9IuadK2T+p9QlhOzpDgq7bu66wuk8ub21dX2+RFn3SNy4o9
L7Gr+/skTcr6cVPSa1V2IulH0ubIkqCxN2u6oOQ3t6NTvXX9GtIpBW4iwk32
rs/uA9zy1t9ub18pDo5FnpdutXqSvKj6ts6HDAd9/6Tgf35g1HzmIRJXpbuS
wOdjZwQuFiI05C6jl9u0LP6gtyvXs8yMEeif7Fy532Su7Yv9ic9KVJduk5sq
KWLY+hpb8EnSsgwIiYkxofs8EA/wq8n798oGHz5s5UD+HfrLQ0H3nbj9vsgK
vv1P3XlbN+mBvuK7mNw/3xOhKOEXDkwLWVt3ghA99jrphqapW7yOe16+ZdVO
uNTdUL6dQdURTtO2qLvtVI0mGfFXn76lU5Zp5pId7ewIEWl1SggGUCdR2TrZ
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
1+Ll05fMuD6Rvfq/uYxKQYN6AAA=

-->

</rfc>
