db-20 — Execution Plan
Stage 1 — Single replica, no replication
Implement Replica and apply() for Op::{NoOp, Put, Del} in Rust.
Verify that a Cluster::new(1) (1-replica cluster — trivially has its
own quorum) can propose(Put("a", b"v")) and the state machine sees
a → b"v". Test cases 1 and 3 in the Rust suite.
Stage 2 — Five replicas, no failures
Add Cluster, propose, quorum = N/2 + 1. Verify that a single
propose on a 5-replica cluster applies to all five state
machines because all 5 follow the leader. Tests 2 and 6.
Stage 3 — Partitions
Add Cluster::partition(ids) and is_partitioned. Drop messages to
and from partitioned replicas. Test that:
- 3/5 reachable still commits (test 4),
- 2/5 reachable does not commit (test 3),
- partitioned followers have
commit_index == 0after one proposal (test 4).
Stage 4 — Heal + catchup
Implement Cluster::heal and Replica::truncate_and_replay. Verify
that after a sequence of mutations on healthy replicas, calling
heal() brings the partitioned ones back to byte-identical snapshots.
Tests 5 and 13.
Stage 5 — Canonical snapshot
Decide the wire format (see CONCEPTS.md), implement dump_state,
write the byte-format test that pins every field offset (test 8). The
test fails loudly if a future refactor changes endianness or field
order.
Stage 6 — Workload driver
Port splitmix64 (mix and stateful generator). Decode each r1
high-bit pair into Put/Del. Encode r3 % 10000 as a fixed 8-byte LE
value so the byte width is independent of host word size. Tests 9, 10.
Stage 7 — Cross-language exam
Build the Rust binary, capture the actual hash for scenarios A and B,
bake those hashes into src/go/dkv20_test.go,
src/cpp/tests/test_dkv20.cc, and scripts/cross_test.sh. Port Go.
Port C++. Run bash scripts/cross_test.sh and watch all three values
align.
Stage 8 — Verification + docs
scripts/verify.sh runs all three test suites. scripts/cross_test.sh
runs all three binaries on both scenarios. Doc trio (analysis,
execution, observation, verification, broader-ideas) plus three
steps/ study files.
Pitfalls to expect
| Symptom | Likely cause |
|---|---|
| Go scenario hash doesn't match Rust | unsorted map iteration in DumpState |
| C++ scenario hash doesn't match Rust | endian / size mismatch in put_u32_le / put_u64_le |
| C++ tests pass in Debug, fail in Release | assert(side_effect) — Release strips it |
| Wrong commit_index after partition heal | snapshot push not clearing state_machine |
Build error: duplicate package declaration | create_file leftover from a stub |
| Subagent left half-built ports | resume manually, hash will tell you if it works |