Skip to content

The protocol family

Sovereign Mesh is two specifications, not one.

Layer Specification Replicates
Upper SOP/1 — Sovereign Object Plane High-volume immutable data as encrypted objects
Lower SSP/1 — Sovereign Synchronization Protocol Small mutable state, plus identity, ordering and policy

Because the two kinds of data want opposite mechanisms, and forcing either into the other’s shape is expensive.

Immutable data — measurements, telemetry, logs — has no conflicts to resolve. Adding an object to a set is commutative and idempotent, so it needs no ordering, no merge algebra and no coordination. Paying per-row replication cost for a hundred million sensor readings is pure waste.

Mutable state — configuration, entity records, catalog metadata — genuinely can be edited on two machines at once, and must converge to the same value afterwards. Deterministic merge is unavoidable, and content-addressed immutable objects cannot express it.

So each layer uses the cheapest primitive that is actually correct for its data. That is the organising decision of the whole family.

flowchart TD
  accTitle: How the two Sovereign Mesh layers divide responsibility
  accDescr: Application queries reach a local engine that reads both the mutable state maintained by SSP/1 and the immutable object plane maintained by SOP/1. SOP/1 depends on SSP/1 for identity, admission, scope, hybrid logical clocks, mutable convergence and the mailbox. SSP/1 depends on SOP/1 for nothing.
  app["Application / query"] --> engine["Local query engine"]
  engine --> mutable["SSP/1<br/><small>mutable state, merge semantics</small>"]
  engine --> objects["SOP/1<br/><small>immutable encrypted objects</small>"]
  objects -->|"depends on"| host["SSP/1 host interface<br/><small>identity, admission, scope, HLC, mailbox</small>"]
  mutable --- host

SOP/1 depends on SSP/1 for six things. SSP/1 depends on SOP/1 for nothing — it is implementable and useful on its own.

SOP/1 needs Supplied by
Stable node identity and its signing key SSP/1 identity
Admission and removal decisions SSP/1 identity
Scope policy lookup SSP/1 scope
Hybrid logical clock values SSP/1 data model
Mutable-table convergence SSP/1 semantics
An asynchronous mailbox SSP/1 transport

That dependency list is written down as a contract in the host interface, which means SOP/1 can also run over a different host that satisfies it. The object plane’s data path — encryption, content addressing, manifests, placement, compaction — touches none of SSP/1’s wire format, canonical encoding, cursors or merge algebra.

Keeping that substitution possible is the reason these are two documents. A single merged specification would weld the layers together by accident, and the seam would be gone within one revision.

This is the other reason not to merge them, and the more practical one.

SSP/1 SOP/1
Status New specification Frozen architecture baseline
Gates outstanding Ten
Released implementation None None
Conformance corpus None yet None yet
Largest open gap No conformance corpus Encrypted-Parquet interoperability

Each carries its own honest status. A merged document would have to state one status for both, and either understate the settled parts or overstate the unsettled ones.

Two documents does not mean two stacks. Both layers share one substrate — deterministic CBOR ([RFC 8949]), COSE_Sign1 records under one profile, BLAKE3 over exact signed bytes as the single hash convention, one chained-record schema for policy-shaped state, and one transport family. An implementation of the whole family carries one codec and one signature container, and a structure defined in either layer verifies with the same machinery in the other.

The transport family is the concrete case. SOP/1 names iroh as its preferred live network substrate — endpoints addressed by public key over QUIC, direct paths attempted first, NAT traversal where possible, encrypted relay fallback where not — and SSP/1’s default live binding is mutually authenticated QUIC with raw public keys, chosen deliberately to be the same family. A mesh running both layers therefore carries one transport stack rather than two. Neither layer mandates a specific implementation: SSP/1 defines a binding profile, not a dependency.

A capability that changes neither layer’s semantics but adds a new registered value — an object kind, an encrypted-object format — ships as an extension specification: a separate hand-authored document layered on the extension points its host layer reserves, carrying its own status and its own decision gates. An implementation that does not know an extension fails closed on its identifiers, which both layers already require for unknown values.

One extension is currently specified:

Extension Host Adds
SOP/1 blob extension SOP/1 Unstructured objects (photos, video, audio) as chunked-AEAD blobs — object kind blob, format SOP-BLOB-1

If you want to understand the system, start with what sovm is and then how it works. Neither specification is a good introduction, and they are not written to be.

If you are implementing the object plane, read the host interface first — it is the contract you must satisfy or supply — then SOP/1.

If you are implementing synchronization, read SSP/1 in order. Read its limitations before writing code, not after.

If you are evaluating whether to build on this at all, read implementation status and the two limitations pages. They are short, and they are where the honest answer lives.