Skip to content

Normative · Conformance module

SOVM-SYNC-RT — realtime push mode

SSP/1 calls realtime mode optional in its own abstract and never says what optional means. There is no name for the omission, no obligation attached to it, and no way for a peer to tell a node that cannot hold a live subscription from one that can and has chosen not to. This document supplies the missing half.

It is deliberately the smallest module SOVM/1 will ever define, and that is why it was written first. SOVM-SYNC-RT requires no new mechanism at all: the declaration point, the mutual-establishment rule, the fail-closed refusal and the correctness backstop are all already in SSP/1, published and frozen. What was missing was a boundary, a name, and exactly one obligation — the obligation to answer the handshake honestly — which section 5 shows is the only place where the omission can hurt anyone.

If a module this cheap cannot be expressed without editing the layer it belongs to, none of the harder ones can either. That is the proof this document exists to carry.

The requirement keywords and the encoding rules are the specification’s conventions; shared vocabulary is terminology.

Every mechanism SOVM-SYNC-RT needs is already reserved in SSP/1, which is what makes it a module rather than a change.

What the module needs Where SSP/1 already provides it
A declaration point supports_realtime in the capability handshake
Mutual establishment §33: realtime operates only when both peers advertised it
A refusal path for a node that did not The fail-closed inventory: an unsolicited push without mutual supports_realtime is rejected, not dropped
A correctness backstop §33.1: realtime is a latency optimization, never a correctness mechanism, and a realtime node runs its batch cycle anyway
A conformance clause that does not require it Registry §55.1: eight items, none of which names realtime

The last row is the one worth pausing on. Realtime is absent from the core clause, so a node without it arguably conforms today. That is not the same as being permitted to omit it, and the difference between those two states is the whole content of this document. When this page was written the omission was merely unmentioned — nobody had written it down, so it carried no obligations because nobody had stated any. Registry §55.2 has since written it down, stating both halves of the module’s clause, and with GR1 closed the omission is now permitted on the terms that clause states.

SOVM-SYNC-RT comprises realtime mode — the behaviour of holding a live subscription and pushing sync bodies over it — specifically:

Three things that sit visually inside the module’s sections are not part of the module, and a node that omits SOVM-SYNC-RT implements all three. Stating the exclusions is more load-bearing than stating the inclusions, because each of these would otherwise be swept from tier 1 into tier 2 by the accident of where it is printed.

The refusal is not modular. Messages §33’s sentence that a receiver MUST reject an unsolicited body on a session where the capability was not mutually established is a row of the fail-closed inventory, and the inventory is tier 1 in its entirety. It is precisely the behaviour an omitting node needs most, so it belongs to SOVM-SYNC. Reject, not drop: the omitting node surfaces the protocol error rather than absorbing it.

The handshake member is not modular; the ability to answer it true is. Every node emits supports_realtime and every node parses a peer’s, in both directions, whatever it implements. What SOVM-SYNC-RT governs is whether a node is entitled to set it true. This distinction is not pedantry — a module defined as “the member” would license an omitting node to leave the member out, and the receiver’s fail-closed rule has nothing to act on when the member is absent.

The enumeration value is not modular either. realtime is a registered transport mode. A node that omits the module still knows the value, and must not treat it as unregistered — the fail-closed rule for unregistered values is for values SOVM/1 never defined, not for capabilities a peer has and this node does not.

This is the same cut SOVM-SEQ makes when it keeps the member-side obligation to route Commits through the sequencer in SOVM-OBJ while making only the capacity to serve the role optional. What is optional is the work; what protects everyone else from its absence never is.

The requirements below bind an implementation that states its module set. Registry §55.1 item 8 requires every implementation to state one; what section 6 still withholds is the entitlement to state one that leaves SOVM-SYNC-RT out.

  1. It MUST implement §33 in full, including §33.1’s periodic batch cycle. An implementation whose only delivery path is push MUST NOT claim SOVM-SYNC-RT; messages §33.1 is explicit that such an implementation has taken on an exactly-once obligation the transport cannot meet and will not converge.
  2. It MUST advertise supports_realtime: true only on a session whose binding can in fact carry unsolicited one-way bodies (transport §24). The claim is a property of the session, not a static property of the build: the same implementation reached over a binding that cannot hold a live connection, or over the mailbox — which §33.4 puts outside realtime mode entirely — advertises false there and is not in breach.
  3. It MUST apply a pushed body through the same apply chokepoint as a solicited one. §33 already requires this and it is restated here because it is what makes claim 2 safe to rely on.
  1. It MUST advertise supports_realtime: false in every capability handshake it sends. This is the module’s one new obligation and the reason the document exists; section 5 is the argument for it.
  2. It MUST NOT send an unsolicited sync body on any session. This is already required of it by §33 — a sender MUST NOT push to a peer that did not advertise — and it holds symmetrically here: having advertised false itself, mutual establishment is unreachable in either direction.
  3. It MUST still emit and parse the supports_realtime member, MUST still reject an unsolicited body per the fail-closed inventory, and MUST still recognise realtime as a registered transport mode. None of the three is relaxed by the omission (§2.1).
  4. Every session it takes part in therefore runs in batch mode, and that is the whole of the difference. No delivery semantics change: at-least-once delivery, idempotent apply, cursors, applied watermarks and convergence are identical. The cost is latency, and it falls on the two peers in the session.

An omitting node has declined one delivery path. It has not acquired a lighter version of anything else, and in particular it holds the fail-closed inventory whole, the COSE profile unchanged, and every scope obligation. It also gains no relief from the batch cycle: batch was never the fallback for realtime, it was always the mechanism, and §33.1 says as much from the other direction.

There is no degraded realtime. A node either holds live subscriptions or it does not; there is no third state in which it holds them unreliably and says so. That absence is deliberate — a partial claim is the shape a downgrade takes.

The tier test admits a capability to tier 2 only if omitting it cannot weaken a security or policy guarantee for a participant other than the node omitting it. Run SOVM-SYNC-RT through it.

Stripping supports_realtime on-path — which an attacker can do, because the handshake is unsigned and precedes authentication — degrades one session to batch. Delivery semantics, cursors, idempotent apply and convergence are unchanged, because §33.1 already requires the batch cycle to run underneath. The cost is latency, and it is borne by the two peers in that session and by nobody else. That is a legitimate local trade, and it is what the handshake is for.

SOVM-SYNC-RT is currently SOVM/1’s only tier-2 module. The tier exists for capabilities shaped like this one, and the profiles index is the record of how few of them there are.

5. The hazard is the false claim, not the omission

Section titled “5. The hazard is the false claim, not the omission”

The interesting failure in a negotiated capability is never the node that says false. It is the node that says true and cannot deliver, and SSP/1 as first published did not forbid it. Messages §33 now does; this section records why it must.

Read the handshake and the original text of messages §33 together. It constrained the sender — it MUST NOT push to a peer that did not advertise. The fail-closed inventory constrained the receiver — it MUST reject an unsolicited body where the capability was not mutually established. Neither constrained a node that advertises true without implementing the receiving side. supports_realtime is documented as whether the sender can hold a live subscription, which describes what the member means without, on its own, obliging the sender to answer truthfully.

The consequence is not cosmetic, because §33 ties the durable cursor to the push:

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.

A node that advertised true and cannot receive has two behaviours available and both are bad:

  • It rejects the body. The fail-closed rule’s stated ground — that the capability was not mutually established — is false here, since the node established it itself. The peer sees a protocol error it cannot attribute, on a session it negotiated correctly. The mesh converges, by batch, but with a permanent error signal pointing at the wrong cause.
  • It accepts and discards. The push succeeded as far as the sender can observe, so the sender advances its durable cursor. Messages §33.1’s backstop re-offers from that cursor, so the discarded events are not re-offered. Convergence fails, silently, and the batch path that was supposed to be the backstop is the thing carrying the loss.

The second is the whole reason §3.2’s first requirement is a MUST. It costs an implementation nothing — a node that omits the module hard-codes one boolean — and it converts the second behaviour from reachable to out of conformance.

Two things this argument does not claim. It is not a downgrade attack: an on-path attacker who flips the bit the other way, true to false, only slows the session, which is section 4’s point and the reason tier 2 is correct. And it does not make honesty enforceable — a handshake member cannot be made trustworthy by a rule, since the channel is unsigned. What the rule buys is that the failure becomes a conformance defect with a name, detectable by a corpus (GR3) rather than only in production by a mesh that has already lost events.

Three gates. GR1 is closed; GR2 and GR3 are open. They are not the same kind of gate as the blob extension’s, and the difference is worth naming rather than papering over: GB1–GB3 are empirical, because that extension defines a wire format that has to be measured. A conformance module defines no bytes, so its first gate is editorial and only the last two can be demonstrated.

GR1 normative adoption CLOSED
(a) CLOSED: SSP/1 states the conformance clause as core plus the
modules an implementation claims, naming SOVM-SYNC-RT
(b) CLOSED: SSP/1 carries section 3.2's honest-advertisement
requirement in the handshake section and the fail-closed
inventory
Both conjuncts hold: this document binds through SSP/1 itself,
which is what the gate existed to ensure.
GR2 interoperability, both directions
a claiming node and an omitting node converge over the same event
corpus; the omitting node's sessions carry no unsolicited body in
either direction; the claiming node's durable cursor never advances
past an event its peer did not apply
GR3 false-claim detection
a node advertising supports_realtime: true that discards pushed
bodies is caught by the corpus, and the divergence is attributed to
the false claim rather than to the batch path that surfaced it
Gate State Verdict
GR1 normative adoption closed verdict
GR2 interoperability, both directions open target
GR3 false-claim detection open target

GR1 is the load-bearing one. This document is not an amendment and cannot become one, so what GR1 asks for had to be stated elsewhere, and its two conjuncts landed in different places.

The first is closed. Registry §55 states conformance as core plus the modules an implementation claims, and §55.2 names SOVM-SYNC-RT with both halves of its clause. That is SSP/1 itself supplying exactly what the gate asks for.

The second is likewise carried by SSP/1 itself. §3.2’s honest-advertisement requirement does not live only on this page: messages §33 binds the sender’s advertisement in the handshake section, and the fail-closed inventory carries its two rows — a reader of SSP/1 meets the obligation where the capability is specified. Registry §55 is what lets an implementation act on §55.2’s clause.

GR3 depends on a conformance corpus. SSP/1’s now carries cases, but none of them are SOVM-SYNC-RT’s: they pin the change event’s bytes and the state a receiver materializes from them, neither of which realtime mode changes, and the fail-closed inventory including this module’s two rows — but those execute under SOVM-SYNC, because the inventory is tier 1 entire, so SOVM-SYNC-RT’s own partition remains empty. The harness that would run this module’s vectors is partitioned by module and treats a claimed module with zero executed vectors as an error rather than a pass (Registry §55.4). That is the machinery GR3 needs and not the evidence GR3 asks for: an empty partition that fails loudly is still empty. A module claim nothing can test is a label, and this document should not be read as claiming otherwise.

  • It does not amend SSP/1. Realtime mode’s normative text stays exactly where it is. This page points at sections; the sections keep their sentences.
  • It is not what makes realtime optional. Registry §55.2 is. With GR1 closed, omission is permitted on the terms that clause states — this page remains the boundary drawn around the capability, not the permission slip.
  • It does not define the tier-3 declaration. SOVM-SYNC-RT is tier 2 and is reachable over a channel that already exists, which is the only reason it could be written before that slot is filled. Every tier-3 module named in the profiles index still waits on it.
  • It does not define a second protocol. A realtime push is a sync-exchange body over a held connection. There is no realtime message, no realtime cursor and no realtime state.
  • It does not cover the object plane. Where SOP/1 shares the same held connection (§33.4), that traffic is SOP/1 control-plane messaging and is unaffected by whether this module is claimed.
  • It does not set a policy on timing exposure. §33.3 records that pushing at production time is a timestamp on the wire and recommends a fixed flush cadence where that matters. That trade stays a deployment policy, and omitting SOVM-SYNC-RT is not a supported way to buy it — a node wanting timing cover configures the cadence rather than declining the module.