open-standards/smart-byte/smart-byte-rs/crates/smart-byte-crdt/tests/convergence.rs
Transaction Science 3fe109d58f ingest batch 4: 9 crates · table-stakes completers across all three workspaces
OpenPay (3 crates, ~13k LOC, 175 tests)
  op-connect           sub-merchant onboarding + KYB + split-payments + payouts + 1099-K
  op-3ds2              3DS2.3 SCA processor (AReq/ARes/CReq/CRes/RReq/RRes + exemptions)
  op-tax               US/EU/UK/AU/CA/IN tax with Avalara/Stripe/CCH/Vertex/TaxJar adapters

Smart Byte (3 crates, ~7k LOC, 57 tests)
  smart-byte-libp2p    libp2p transport (kad/gossipsub/mdns/autonat/relay/dcutr/identify/ping/req_resp)
  smart-byte-crdt      LWW/GCounter/PnCounter/OrSet/LwwMap/RgaList/2P-Set + HLC + vector clock + Automerge/Yjs interop
  smart-byte-keri-witness  KERI key-rotation cycle + witness layer + watchers + recovery + delegation

EOC (3 crates, ~8k LOC, 108 tests)
  eoc-tools            function-calling across Anthropic/OpenAI/Google/Mistral/Cohere + parallel exec + sandbox
  eoc-multimodal       vision (CLIP/SigLIP/ColPali) + audio (Whisper/MMS) + video sampling + modality router
  eoc-spec-decode      vanilla + SpS-with-temp + lookahead speculative decoding + EAGLE/Medusa stubs

All three workspaces compile cleanly. Forbidden-unsafe, no unwrap outside tests.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-24 04:00:04 -04:00

230 lines
7.1 KiB
Rust

//! End-to-end convergence tests for the Smart Byte CRDT engine.
use proptest::prelude::*;
use smart_byte_crdt::{
apply,
document::{CrdtNode, DocumentId, Value},
hlc::{HlcClock, ReplicaId},
sync::{clock_of, diff},
types::{Crdt, CrdtId, GCounter, LwwRegister, OrSet, PnCounter, UniqueTag},
CrdtDocument,
};
fn rid(n: u128) -> ReplicaId {
ReplicaId::new(n)
}
#[test]
fn three_replicas_text_edit_converges() {
let id = DocumentId::from_bytes(b"doc");
let mut docs: Vec<(ReplicaId, CrdtDocument, HlcClock)> = (1u128..=3)
.map(|n| {
let r = rid(n);
(
r,
CrdtDocument::new(id, r),
HlcClock::with_manual_wall(r, n as u64),
)
})
.collect();
// Replica 1 inserts "AB" at /text.
let (r1, mut d1, mut c1) = docs.remove(0);
let (_o1, p_a) = d1.text_insert("/text", None, 'A', &mut c1, 1).unwrap();
let (_o2, p_b) = d1.text_insert("/text", Some(p_a), 'B', &mut c1, 2).unwrap();
// Replica 2 starts from R1's state, then inserts "X" after A.
let (r2, mut d2, mut c2) = docs.remove(0);
let ops_to_2 = diff(&d1, &clock_of(&d2));
apply(&mut d2, &ops_to_2).unwrap();
let (_o3, _p_x) = d2.text_insert("/text", Some(p_a), 'X', &mut c2, 1).unwrap();
// Replica 3 starts from R1's state, then inserts "Y" after B.
let (r3, mut d3, mut c3) = docs.remove(0);
let ops_to_3 = diff(&d1, &clock_of(&d3));
apply(&mut d3, &ops_to_3).unwrap();
let (_o4, _p_y) = d3.text_insert("/text", Some(p_b), 'Y', &mut c3, 1).unwrap();
// Cross-merge.
let ops_d2_to_d1 = diff(&d2, &clock_of(&d1));
let ops_d3_to_d1 = diff(&d3, &clock_of(&d1));
apply(&mut d1, &ops_d2_to_d1).unwrap();
apply(&mut d1, &ops_d3_to_d1).unwrap();
let ops_d1_to_d2 = diff(&d1, &clock_of(&d2));
apply(&mut d2, &ops_d1_to_d2).unwrap();
let ops_d1_to_d3 = diff(&d1, &clock_of(&d3));
apply(&mut d3, &ops_d1_to_d3).unwrap();
let s1 = collect_text(&d1, "/text");
let s2 = collect_text(&d2, "/text");
let s3 = collect_text(&d3, "/text");
assert_eq!(s1, s2);
assert_eq!(s2, s3);
assert!(s1.contains('A'));
assert!(s1.contains('B'));
assert!(s1.contains('X'));
assert!(s1.contains('Y'));
let _ = (r1, r2, r3);
}
fn collect_text(doc: &CrdtDocument, path: &str) -> String {
match doc.get_node(path) {
Some(CrdtNode::Text(t)) => t.iter().collect(),
_ => String::new(),
}
}
proptest! {
#![proptest_config(ProptestConfig::with_cases(40))]
#[test]
fn gcounter_arbitrary_ops_converge(
ops in proptest::collection::vec((0u8..3u8, 1u64..50u64), 1..50)
) {
// Each entry: (replica index 0..3, increment amount).
let id = CrdtId::new(7);
let mut a = GCounter::new(id);
let mut b = GCounter::new(id);
let mut c = GCounter::new(id);
for (which, amt) in &ops {
let r = ReplicaId::new(*which as u128 + 1);
match which {
0 => a.increment(r, *amt),
1 => b.increment(r, *amt),
_ => c.increment(r, *amt),
}
}
// Merge in two different orders; both must yield identical total.
let mut order1 = a.clone();
order1.merge(&b);
order1.merge(&c);
let mut order2 = c.clone();
order2.merge(&a);
order2.merge(&b);
prop_assert_eq!(order1.value(), order2.value());
// Idempotency.
let v = order1.value();
order1.merge(&b);
order1.merge(&c);
prop_assert_eq!(order1.value(), v);
}
#[test]
fn pncounter_arbitrary_ops_converge(
ops in proptest::collection::vec((0u8..3u8, -50i64..50i64), 1..50)
) {
let id = CrdtId::new(7);
let mut a = PnCounter::new(id);
let mut b = PnCounter::new(id);
let mut c = PnCounter::new(id);
for (which, delta) in &ops {
let r = ReplicaId::new(*which as u128 + 1);
let target = match which {
0 => &mut a,
1 => &mut b,
_ => &mut c,
};
if *delta >= 0 {
target.increment(r, *delta as u64);
} else {
target.decrement(r, delta.unsigned_abs());
}
}
let mut order1 = a.clone();
order1.merge(&b);
order1.merge(&c);
let mut order2 = c.clone();
order2.merge(&a);
order2.merge(&b);
prop_assert_eq!(order1.value(), order2.value());
}
#[test]
fn lww_register_converges_regardless_of_order(
writes in proptest::collection::vec((0u8..3u8, 0u64..100u64, 0i64..1_000i64), 2..20)
) {
// Each write: (replica, wall_ms, value)
let id = CrdtId::new(11);
let r0 = ReplicaId::new(1);
let mut a = LwwRegister::new(id, 0i64, smart_byte_crdt::HybridLogicalClock { wall: 0, logical: 0, node: r0 }, r0);
let mut b = a.clone();
for (which, wall, value) in &writes {
let r = ReplicaId::new(*which as u128 + 1);
let ts = smart_byte_crdt::HybridLogicalClock { wall: *wall, logical: 0, node: r };
match which {
0 => a.write(*value, ts, r),
_ => b.write(*value, ts, r),
}
}
let mut ab = a.clone();
ab.merge(&b);
let mut ba = b.clone();
ba.merge(&a);
prop_assert_eq!(*ab.get(), *ba.get());
}
#[test]
fn orset_observed_remove_converges(
sequence in proptest::collection::vec((0u8..3u8, 0u8..1u8, 0u8..5u8), 1..30)
) {
// Each entry: (replica, op (0=add, 1=remove), item id)
let id = CrdtId::new(13);
let mut a: OrSet<u8> = OrSet::new(id);
let mut b: OrSet<u8> = OrSet::new(id);
let mut c: OrSet<u8> = OrSet::new(id);
for (i, (which, op, item)) in sequence.iter().enumerate() {
let r = ReplicaId::new(*which as u128 + 1);
let target = match which {
0 => &mut a,
1 => &mut b,
_ => &mut c,
};
let nonce = (i as u64) + 1;
let tag = UniqueTag {
hlc: smart_byte_crdt::HybridLogicalClock { wall: nonce, logical: 0, node: r },
replica: r,
nonce,
};
match op {
0 => target.add(*item, tag),
_ => target.remove(item),
}
}
let mut order1 = a.clone();
order1.merge(&b);
order1.merge(&c);
let mut order2 = c.clone();
order2.merge(&a);
order2.merge(&b);
prop_assert_eq!(order1.snapshot(), order2.snapshot());
}
}
#[test]
fn document_set_via_path_round_trips_value() {
let id = DocumentId::from_bytes(b"d");
let r = rid(1);
let mut doc = CrdtDocument::new(id, r);
let mut clock = HlcClock::with_manual_wall(r, 5);
doc.write_at("/x/y/z", Value::Text("hello".into()), &mut clock)
.unwrap();
match doc.get_node("/x/y/z") {
Some(CrdtNode::Register(reg)) => assert_eq!(*reg.get(), Value::Text("hello".into())),
_ => panic!("expected register"),
}
}