Message formats
Every message is a CBOR map. Deterministic encoding ([RFC 8949] section 4.2.1) is REQUIRED wherever bytes are hashed or signed; message envelopes themselves are neither, and need not be deterministic — though emitting them deterministically anyway is the simpler implementation.
1. Version negotiation
Section titled “1. Version negotiation”Every message carries an explicit ssp_version member, an integer. This revision
defines the value 1.
A receiver encountering an unknown ssp_version MUST fail closed — refuse the
exchange rather than attempt a best-effort parse.
This is a deliberate departure. A predecessor carried no in-band version member at all and delegated versioning entirely to a transport identifier, on the reasoning that the transport already distinguished versions. That couples protocol identity to transport choice: the same protocol over a second transport becomes unversioned, and a version bump requires a transport change. An in-band member costs a few bytes and makes the message self-describing.
2. Capability handshake
Section titled “2. Capability handshake”Exchanged before the first sync of a session.
| Member | Type | Description |
|---|---|---|
ssp_version |
unsigned | 1 |
site_id |
text | Sender’s site_id |
have_max_hlc |
map | Highest HLC the sender holds: {physical_ms, logical} |
supports_realtime |
bool | Whether the sender can hold a live subscription; see realtime mode |
secure_channel |
bool | Whether the binding authenticated the peer |
rtt_ms |
unsigned or null | Sender’s measured round-trip estimate, advisory |
A receiver MUST fail closed to batch mode on any unknown member value rather than guessing a capability.
secure_channel is advisory and MUST NOT be treated as a security input. A peer can
claim anything; the receiver knows what its own binding provided. It exists so a node
can warn when a peer believes the channel is authenticated and the local side
disagrees, which usually indicates a misconfigured binding.
3. Sync exchange
Section titled “3. Sync exchange”The same shape travels in both directions, which keeps a sync a single symmetric round trip rather than two asymmetric protocols.
| Member | Type | Description |
|---|---|---|
ssp_version |
unsigned | 1 |
from_site_id |
text | Sender’s site_id |
have_max_hlc |
map | Highest HLC the sender holds |
events |
array of byte strings | Zero or more encoded COSE_Sign1 change events, forwarded byte for byte |
records |
array of byte strings | Zero or more encoded COSE_Sign1 control records — vouches, role assignments, transport bindings, authorization records. MAY be empty; MUST be present |
applied_watermarks |
array | Zero or more watermark records |
Events travel as the exact bytes their producer signed — event identity depends on it — so the envelope carries them as opaque byte strings rather than re-encoding them.
records is the wire path for the durable control records the
registry defines. Each is
self-verifying, so a receiver processes them independently of the events in the same
exchange and in any order; a record that fails verification is dropped and surfaced
without affecting the rest of the body.
Selection: a responder returns events at or above the requester’s have_max_hlc,
bounded by an implementation-chosen batch limit.
The bound is inclusive — at or above — deliberately. An exclusive bound loses any event sharing the boundary HLC with one already delivered, and because apply is idempotent the cost of re-sending a boundary event is nil while the cost of skipping one is a permanent gap.
3.1. Self-echo suppression
Section titled “3.1. Self-echo suppression”A receiver MUST drop events whose protected kid equals its own site_id.
This is normative and unconditional. Without it, an event that a node authored and that returns via a peer is re-ingested, re-offered, and can circulate indefinitely — and the combination of an inclusive selection bound and at-least-once delivery makes that loop reachable in normal operation rather than only under attack.
A predecessor stated this rule only inside the description of one deployment epoch, so a reader implementing the other epoch would omit it. It belongs here, applying to every profile.
3.2. Liberal parsing bound
Section titled “3.2. Liberal parsing bound”A receiver MUST reject a sync body that is not a CBOR map with exactly the members above.
A predecessor instructed receivers to be liberal at this boundary — reading a bare array as an event list and anything else as empty. That converts a malformed or hostile body into a silent no-op, which is indistinguishable from a peer with nothing to send. SSP/1 rejects explicitly instead, so a protocol error surfaces as one.
4. Realtime mode
Section titled “4. Realtime mode”The registry registers two transport modes,
batch and realtime. Everything above this section describes batch mode:
cycle-driven request/response synchronization. Realtime mode is the second, and it
is deliberately not a second protocol: a realtime push is a sync-exchange body
— the same CBOR map, the same members, the same rules — sent unsolicited over a
held live connection as events are produced, with no response awaited.
Realtime mode operates only when both peers advertised supports_realtime in
the capability handshake. A sender MUST NOT push unsolicited bodies to a peer that
did not advertise it, and a receiver MUST reject an unsolicited body on a session
where the capability was not mutually established — reject, not drop, so a
protocol error surfaces as one.
Realtime mode changes when a body is sent — at production time rather than on the next cycle — and nothing else:
- Delivery semantics are unchanged. At-least-once delivery, idempotent apply, self-echo suppression and the watermark rules apply to a pushed body exactly as to a requested one.
- Cursors remain authoritative. A sender advances its durable cursor only on a successful push, solicited or not. A push that fails, or whose outcome the sender never observes, is re-offered by the batch path.
- Ordering is still not guaranteed. A pushed body may arrive before, after or interleaved with overlapping batch bodies. Idempotent apply absorbs every interleaving, and a receiver MUST NOT infer order from the mode a body arrived through.
4.1. Batch remains the correctness backstop
Section titled “4.1. Batch remains the correctness backstop”Realtime mode is a latency optimization, never a correctness mechanism — the same posture as applied watermarks. A node operating in realtime mode MUST continue running its periodic batch cycle.
That rule is what allows the push path to be cheap. A push may be lost to disconnection, backpressure or a crash without threatening convergence, because everything it failed to deliver is re-offered from the durable cursor on the next cycle. An implementation whose only delivery path is push has quietly taken on an exactly-once delivery obligation the transport cannot meet, and will not converge.
4.2. Coalescing
Section titled “4.2. Coalescing”A sender MAY coalesce events produced faster than the link drains into fewer, larger pushed bodies, and the sender-enforced events-per-response limit applies to a pushed body unchanged. A receiver MUST NOT assume one event per push, one push per event, or any particular pacing.
4.3. What realtime mode reveals
Section titled “4.3. What realtime mode reveals”A push at production time is a timestamp on the wire. Whoever can observe the channel — a relay operator, a network-path observer — learns the mesh’s activity rhythm even with payloads encrypted and padded, because padding hides sizes, not timing. Where that matters, a sender SHOULD flush on a fixed cadence rather than on production, which converts the timing channel into a constant signal at the cost of one cadence interval of latency. The trade is a deployment policy, not a protocol member.
4.4. Scope of the mode
Section titled “4.4. Scope of the mode”Realtime mode exists only on a live binding; the mailbox is store-and-forward by definition and nothing in this section applies to it. A binding claiming realtime mode MUST carry peer-initiated one-way bodies (see framing), and trust resumption applies to a held session exactly as to a fresh one.
Where SOP/1 is deployed, the same held connection typically also carries the object plane’s MLS-protected control messages (SOP/1 section 10) — which is how a freshly published object’s catalog entry reaches online peers with the same immediacy. That path is the object plane’s, not this one’s; realtime mode carries only SSP/1 bodies.
5. Applied watermark
Section titled “5. Applied watermark”| Member | Type |
|---|---|
site_id |
text |
table_schema |
text |
table_name |
text |
hlc_physical_ms |
unsigned |
hlc_logical |
unsigned |
Semantics, monotonicity and the fail-closed rule are in semantics.
Watermarks are not signed. They are an efficiency hint, not an authorization input, and a peer that lies about its watermark harms only its own convergence. A receiver MUST NOT grant anything on the basis of a watermark.