Skip to content

The Receive & Apply Path

An operation arrives — from a gossip broadcast or a sync stream; the path is identical. The receiver must establish three things before the operation can change any state: that it is authentic, that its author was authorized, and that it is causally ready. Only then does it fold. Two of the steps can pause the operation in a buffer rather than reject it — that resilience is the interesting part.

  1. Verify the signature. — Check the operation’s signature against its author key. This is the trust boundary established when an operation is signed: an operation that fails verification is dropped here and never reaches the fold. Everything downstream may assume authenticity.

  2. Authorize at the author’s cut. — Resolve the author’s membership and writer rights at the operation’s causal cut — the governance state they referenced — and check they were allowed to write it (per the projection and governance). Because the verdict is computed at the cut, it is the same on every node regardless of receive order: forward-only authority.

  3. Decrypt — or wait for the key. — Decrypt the payload with the scope key. The wait differs by plane. A governance op whose key hasn’t arrived is held undecodable and replayed the moment the wrapped key lands (apply_received_group_key). A state delta does not wait indefinitely: the node polls briefly (~3s) for the key, then drops the delta and relies on gossip rebroadcast plus the hash heartbeat to redeliver it once the key is in hand — there is no persistent per-delta key-pending buffer on the data plane.

  4. Insert into the DAG — or buffer for parents. — If all parents are applied, the operation is ready. If a parent hasn’t arrived (gossip delivered a child before its parent), it waits in the pending buffer keyed by the missing parent — the same buffer-and-cascade from the operations model.

  5. Fold and cascade. — Apply the operation into the projection, advancing state and heads, then re-check both buffers: a just-applied operation may be the missing parent of a pending child, or the key that unlocks a queued operation. Cascade until nothing new is ready.

  6. Run event handlers. — If the operation carried application events, dispatch their handlers and notify subscribed clients. This is a local side effect of applying — it never feeds back into consensus.

A worked example: the same message arriving

Section titled “A worked example: the same message arriving”

The send_message("hi") delta from the write path lands at a peer that already holds the parent 0x11aa…02 and the group key (SHA-256(group_key) == 0x4d90…7c). It clears all six steps in one pass:

1. verify — verify_delta_signature(context_id, delta_id=0x3c08…9d,
author_id=0x9f4b…21, governance_position, delta_signature)
→ author's key signed this exact delta_id ⇒ OK (bad sig ⇒ DROP)
2. authorize — resolve author 0x9f4b…21 at the delta's causal cut.
member of the scope ⇒ holds WRITE on the Public messages entity ⇒ OK
(not a writer at the cut ⇒ DROP)
3. decrypt — message key_id 0x4d90…7c matches a key in the keyring ⇒
SharedKey::from_sk(group_key).decrypt(artifact, nonce)
→ [ Put(entity=messages["m17"], value=borsh("hi")) ]
(no key yet ⇒ buffer briefly, not reject)
4. insert — parent 0x11aa…02 is already applied ⇒ ready (else hold in pending)
5. fold — apply the Put; messages["m17"] = "hi"; head advances to 0x3c08…9d
recompute scope_root → 0x6e72…ff == the message's root_hash ✓ converged
6. handlers — dispatch the plaintext "MessageSent" event to subscribed clients

The recomputed root in step 5 equals the root_hash the author put on the wire — the convergence assertion checks out, so the two peers now hold an identical scope root. Note the author’s root_hash was never trusted: the peer folds its own state and compares, so a tampered value would surface as a divergence to repair, never as granted authority.

A best-effort gossip mesh delivers operations out of order and sometimes before their prerequisites. The receive path is built to tolerate that rather than fight it. A missing parent or an undelivered key is a “not yet,” not a “no” — the operation is parked and revisited automatically. This is what lets a backfilled or reordered history snap into a correct state in a single cascade, and it is why convergence doesn’t require any particular delivery order.

Verified, authorized, ordered, applied: the operation has lived its full life on a receiving node, and if both peers hold the same set, their scope roots now match. We’ve now seen the full loop — written on one node, received and applied on another. Next we open up what’s inside a delta: Operations & the Causal DAG.