blockworx_doc/protocol.rs
1//! The wire protocol. Commits are the only thing that crosses it: the
2//! server never sends a document, because a document is derived and
3//! sending one would put a second authority-shaped artifact on the wire.
4//! Rationale: `docs/collab-architecture.md` §7.
5
6use serde::{Deserialize, Serialize};
7
8use crate::{commit::CommitEnvelope, rev::Rev};
9
10/// Matches an answer to the submission that produced it. Session-minted;
11/// the server echoes it back and never persists it.
12#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
13pub struct Nonce(u64);
14
15impl Nonce {
16 pub(crate) const fn new(count: u64) -> Self {
17 Self(count)
18 }
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
22pub enum ClientMsg {
23 Submit {
24 nonce: Nonce,
25 commit: CommitEnvelope,
26 },
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
30pub enum ServerMsg {
31 /// On connect: the whole log, which the client folds. No snapshot —
32 /// cold start is fetch-and-fold, and snapshot-then-tail is a later
33 /// server-side optimization that must stay verifiable by replay.
34 ///
35 /// The commits carry no revs of their own, deviating from the spec's
36 /// `Vec<(Rev, CommitEnvelope)>` (2026-08-16): rev assignment is a
37 /// deterministic function of position, so the client's own fold mints
38 /// exactly the revs the server did. Sending them alongside would be
39 /// redundant data that could disagree with the fold, with no rule for
40 /// which to believe. `rev` is the head, and folding the log must
41 /// reproduce it — that equality is the integrity check.
42 Welcome {
43 rev: Rev,
44 commits: Vec<CommitEnvelope>,
45 },
46 /// To the submitter: sequenced as `rev`.
47 Committed { nonce: Nonce, rev: Rev },
48 /// To the submitter: refused at validation; nothing was sequenced, so
49 /// no rev was consumed.
50 Rejected { nonce: Nonce, reason: String },
51 /// To everyone else.
52 Apply { rev: Rev, commit: CommitEnvelope },
53}