db-20 — Verification

Three layers of test

1. Per-language unit tests

FileTestsCovers
src/rust/src/lib.rs mod tests14splitmix64, sha256, single replica, quorum, sub-quorum, partition, heal, convergence, del, byte format, determinism, scenarios A/B, snapshot push, NoOp
src/go/dkv20_test.go15same set + an extra stdlib sha256 cross-check
src/cpp/tests/test_dkv20.cc13same set

Run with:

( cd src/rust && cargo test --release )
( cd src/go && go test ./... )
( cd src/cpp/build && cmake --build . && ctest --output-on-failure )

scripts/verify.sh is the one-shot wrapper for all three and ends with === OK ===.

2. Cross-language byte-identity exam

scripts/cross_test.sh builds three clusterctl binaries (Rust, Go, C++) and runs:

clusterctl workload --seed 42 --ops 500  --keys 32  --scenario default
clusterctl workload --seed 7  --ops 2000 --keys 128 --scenario partition

The script asserts: rust_hash == go_hash == cpp_hash == golden_hash for each scenario. Ends with === ALL OK ===. Failure on any line exits non-zero and prints the diverging hashes.

3. Frozen golden hashes baked into source

The golden values are duplicated in three places on purpose:

  • scripts/cross_test.sh
  • src/go/dkv20_test.go (hashA, hashB constants)
  • src/cpp/tests/test_dkv20.cc (string-literal in test_scenario_a_frozen and test_scenario_b_frozen)

A change to the wire format or workload spec must update all three to keep verify + cross_test green. The redundancy makes silent drift impossible.

Sanity-check invariants (asserted by the tests)

  • Sha256Hex(empty) and Sha256Hex("abc") match the canonical SHA-256 test vectors.
  • Splitmix64Mix(0) == 0x8b57dafca0cee644 in all three languages.
  • DumpState for one Put produces exactly 38 bytes whose layout is pinned byte-by-byte.
  • NoOp advances commit_index but leaves the state machine empty.

What this exam does NOT verify

  • Real persistence (no log file, no fsync).
  • Real elections (leader is fixed; current_term == 1).
  • Real RPC failure injection (we model partitions only).
  • Linearizable read paths (reads are direct map lookups).

Those are deliberate scope cuts — see analysis.md and broader-ideas.md.