Skip to content

Normative · Part

Constants, COSE profile and extension policy

Field Value
ssp_version (message envelopes) 1

Signed records do not carry ssp_version; they are versioned by their protected content type, which the signature covers.

Every durable signed structure in SSP/1 is a COSE_Sign1 under the substrate signature profile. This page restates none of it — a restatement is exactly the copy that can drift, and the substrate part is the single home both layers bind to. A standalone SSP/1 implementer reads one substrate page and acquires no obligation to implement any part of the object plane.

What belongs here is only SSP/1’s instantiation of the profile:

  • SSP/1 signs COSE_Sign1 records only. It defines no encryption records, because it seals nothing: confidentiality is the transport binding’s responsibility.
  • external_aad on every SSP/1 record is the verifier’s own 16-byte mesh_id — mesh binding without transmission, the narrowest instance of the context principle. The object plane binds richer per-record context; SSP/1 records need only the mesh.

Where this page or any SSP/1 page appears to state a rule about signatures, it is stating a consequence for an SSP/1 structure, never an independent rule. Where the two appear to conflict, the substrate governs.

Durable records are distinguished by protected content type. One content type, one payload schema, one purpose.

Content type Record Defined in
sovm/ssp-event-v1 Change event data model
sovm/ssp-vouch-v1 Vouch certificate identity
sovm/ssp-role-v1 Role assignment (chained) scope
sovm/ssp-custodian-v1 Custodian designation (chained) scope
sovm/ssp-capability-v1 Capability requirement (chained) scope
sovm/ssp-modules-v1 Per-node module set (chained) scope
sovm/ssp-binding-v1 Transport binding transport
sovm/ssp-eventkey-v1 Event-signing subkey data model
sovm/ssp-succession-v1 Identity succession identity

Admission and removal authorization records use the chained-record schema shared with the object plane; where SOP/1 is deployed the definition of sovm/sop-authorization-v1 (SOP/1 section 5.7) applies unchanged. The record takes this profile, and the sop prefix names the layer its normative home sits in, not the profile it is signed under.

The dividing principle: durable records use COSE content types; transient in-ceremony transcript signatures use raw labels. A transcript signature never outlives its ceremony and is never stored or forwarded, so wrapping it in a COSE envelope would add structure with nothing to protect.

Label Used in
sovm-mesh-id-v1 mesh_id derivation
sovm-mesh-pair-v1 Pairing transcript

HKDF info strings, scoped by their input key rather than globally:

info Used in
pair-session Pairing session key
pair-sas SAS derivation
Space Values Reserved
operation upsert, delete purge
Pairing method qr, sas, vouch —
Policy layer system, role, user —
Policy effect allow, deny —
Transport mode batch, realtime —

There are no encoding, hash or signature tag enumerations: those axes are versioned by content type, and the hash convention is fixed – BLAKE3 over exact signed bytes, SOVM/1’s single hash namespace.

A new record or a changed payload schema ships as a new content type version (sovm/ssp-event-v2). Because the content type is a protected header, a receiver that does not know it fails closed on the signature path, never by guessing.

Adding a member to a message envelope requires a new ssp_version. There is no ignore-unknown-members rule.

Adding a value to an enumeration requires a new revision of this document. A receiver encountering an unknown value MUST fail closed for that item.

New raw labels MUST be registered here before use. An unregistered label is a latent cross-protocol signature-confusion risk that no automated check can find, since nothing knows to look for it.

Changing any value in this registry is a wire change. It is never a revision of an existing version.

Conformance is core, plus the modules you claim. An implementation states a set of conformance modules and is held to the core clause below plus one clause per module in that set. It is not held to the clauses of modules it did not claim, and it does not get to be silent about them: a module is claimed or it is not, and both are statements.

Every implementation claiming SSP/1 conformance, whatever else it claims, MUST:

  1. implement every fail-closed behaviour in the inventory;
  2. implement the substrate signature profile with no extensions;
  3. document its floor partition;
  4. document its implementation-chosen limits;
  5. document its key custody posture per platform;
  6. state which transport binding it uses and what that binding provides;
  7. state which limitations it has closed locally, if any, and how;
  8. state its module set — every module it claims, from the profiles index, by identifier.

The floor of every module set is SOVM-BASE — the substrate, root identity and the host-interface obligations — and it is tier 1: no revision may reclassify any part of it. On top of the floor an implementation MUST claim at least one whole layer: SOVM-SYNC, whose clause is the SSP/1 pages, or SOVM-OBJ, whose clause is the SOP/1 pages, or both. Claiming SOVM-OBJ without SOVM-SYNC is the host-only profile: the implementation supplies the host interface from elsewhere and is a conforming object-plane host — the substitutability the specification index defends, stated as a claim a harness can execute rather than as a document boundary.

Item 8 is deliberately an obligation on every implementation rather than only on the ones that omit something: a module set nobody states is a module set nobody can check, and the hazard is the false claim, not the omission.

One clause per module, and each says both halves: what claiming it obliges and what omitting it obliges. A module with only the first half would be a feature list; the second half is what makes a narrower implementation checkable rather than merely smaller.

An implementation MUST NOT claim a module it does not implement. A claim is the only thing a reader has, so a false one is worse than a narrower set honestly stated: the narrower set is checkable and the false claim is not. Section 55.4 is where that obligation becomes testable rather than merely asserted.

Module Claiming it means Omitting it means
SOVM-SYNC Implement the SSP/1 pages in full Supply the host interface from elsewhere and claim SOVM-OBJ — the host-only profile of section 55.1
SOVM-OBJ Implement the SOP/1 pages in full, including the base fail-closed rules Run without an object plane; fail closed on every object-plane content type, object kind and format identifier
SOVM-SYNC-RT Implement realtime mode in full, and answer supports_realtime in the handshake true only where that is true Answer supports_realtime: false — answered, not withheld — and run every session in batch mode
SOVM-BLOB Implement the blob extension in full, including its decision gates’ obligations Fail closed on the blob object kind and the SOP-BLOB-1 object format, per the fail-closed rule in section 54
SOVM-IROH Implement the iroh binding in full — every row of transport §24 met as that page states Run another live binding satisfying transport §24, or run mailbox-only; transport §23 requires at least one transport role either way

Each omittable module here has a mechanism that carries the omission. They differ in whether the omission is permitted yet, and that difference is not a technicality.

SOVM-BLOB is omittable today. An extension is not a capability inside a specification, so the nothing-lands-in-place rule does not reach it: omission was always the default state and adoption is the act. Its carrying mechanism is the existing unknown-value rule, which an implementation that never adopted the extension already satisfies.

SOVM-SYNC-RT is omittable on exactly the terms its row states. Both conjuncts of gate GR1 are discharged: the row above names the module and says what claiming and omitting it oblige, and §3.2’s honest-advertisement obligation is carried where a reader who never opens the module page still finds it — in the handshake section and in the fail-closed inventory. Its carrying mechanism is not in question: the capability handshake, which SSP/1 already requires a receiver to enforce.

SOVM-IROH is omittable today, on transport’s own terms. A specific binding was never mandatory: transport §23 requires a mesh to run at least one transport role, not this one. Its carrying mechanism is the core clause’s item 6 — every implementation states which binding it uses and what that binding provides — so an omission is visible as a different statement rather than as silence.

SOVM-SEQ, SOVM-DEL and SOVM-HIST are tier 3: the mesh states which of them its members must implement, and the statement is enforced. An implementation MAY omit any of the three and still conform. What it cannot do is join a mesh — or, where the requirement is per-domain, a domain — that requires one it omits: it is refused at admission, not admitted degraded.

Module Omitting it means
SOVM-DEL Fail closed on the delete object kind; MUST NOT accept an APPEND_DELETE table; refused admission to any APPEND_DELETE domain
SOVM-SEQ Cannot hold the sequencer role; no participation in sequenced domains
SOVM-HIST Current-epoch domain keys only; every admission it performs is FORWARD_ONLY

Two carriers hold that statement, and which one a mesh uses follows from whether it has an MLS control group to put it in. The tier is defined by the four properties a carrier must have, not by either mechanism.

Carrier Where the requirement lives Checked
Capability declaration Authenticated MLS group state, where SOP/1 is deployed At admission and at every membership-security transition that touches the leaf, by the same library that enforces membership
Capability requirement chain A per-mesh chained record, needing no group state At admission, at sender-side policy, and per event at the apply chokepoint

A mesh carrying both is subject to both, and a member must cover the union. The second carrier is enforced by each peer independently rather than by the membership library, which is a real weakening relative to the first — bounded to a partition around a misbehaving peer rather than a mesh-wide downgrade, and stated in full where the mechanism is. A mesh that has an MLS control group should use the first.

Under the second carrier a member’s own claim is not documentation but a signed module-set record, which is what section 55.1 item 8 states as an obligation and what section 55.2’s false-claim rule governs.

The append-only mesh is therefore a real, conformant profile — and so is a mesh that requires deletion of every member. Two honest limits travel with that sentence. The first: neither carrier attests behaviour. A declaration is re-checked at every membership-security transition that touches the leaf and a requirement chain at every record delivery, so on both carriers a degraded node’s claim is attributable — but on neither is the degradation detected, since what is re-checked is the claim and not the conduct behind it. The open gate on the profiles index says what that costs. The second: within an APPEND_DELETE domain the §14.4 tombstone obligation remains invariant for every admitted node regardless.

SOVM-SYNC-RT does not belong on this list: it is tier 2, per-session, and section 55.2 states the terms on which it may be omitted. A tier-2 capability MUST NOT appear in a mesh’s requirement, on either carrier.

The conformance corpus is partitioned by the same module identifiers, so an implementation runs the cases of the modules it claimed. Two properties of that harness are load-bearing for this clause, and they point in opposite directions:

  • a case whose module was not claimed is reported as skipped, never silently dropped, so a narrower claim visibly tests less rather than invisibly testing less;
  • claiming a module the corpus executes zero cases for is an error, not a pass, so a claim nothing checked cannot be mistaken for a claim that held.

Neither property depends on which modules are omittable today. The harness implements the partition; section 55.2 and section 55.3 decide what may be put through it.

SSP/1’s own coverage reaches the wire format, the fail-closed refusals, and the state a receiver materializes from the event sets the corpus names, and stops there. See limitations.

55.5. An unregistered identifier is not a claim

Section titled “55.5. An unregistered identifier is not a claim”

A module identifier that the registry does not register is not a conformance claim. A verifier presented with one MUST reject the claim, rather than ignore the identifier and evaluate the remainder of the set. Ignoring it is precisely the failure the registry exists to prevent: an unregistered module and a module the verifier happens not to check are otherwise the same thing.

Section 55.1 obliges an implementation to state its module set and to be honest about it; this clause is what the reader of such a set does with an identifier it does not recognise. That is a verifier obligation rather than an implementation one, which is why it stands apart.