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 |
Why two
Section titled “Why two”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.
How they divide
Section titled “How they divide”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.
They are at different maturities
Section titled “They are at different maturities”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.
One substrate
Section titled “One substrate”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.
Extensions
Section titled “Extensions”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 |
Which to read
Section titled “Which to read”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.