quorum
Distributed consensus, from scratch

Five machines.
One log.
No disagreement.

An implementation of the Raft consensus algorithm — no consensus library, the algorithm is the project — behind a linearizable key-value store, verified against injected partitions, crashes and clock skew.

A leader appends entries; once a majority holds an entry, it commits. Every node ends in the same state.

267,329
operations checked · 0 violations
147
tests, real consensus, ~25s
235ms
p50 leader re-election
0
consensus libraries used
The decision that makes it testable

The algorithm is a pure function.

The Raft core reads no clock, opens no socket, and writes no file. It takes a message and the current time and returns new state plus the messages to send. All the messy parts — the network, the disk, the wall clock — live in a thin impure driver around it. A test parses every module in the core and fails if it imports anything that does I/O.

src/raft · pure

The core

A deterministic state machine over messages. Because it has no I/O, an entire five-node cluster is five objects in one process — so the test suite runs thousands of randomized failure scenarios in seconds, and a seed reproduces any failure exactly.

  • Leader election with PreVote
  • Log replication + the Figure 8 commit rule
  • Snapshotting & log compaction
  • Single-server membership changes
  • ReadIndex linearizable reads
src/server · impure

The driver

Owns the clock, the disk, and the network, in that strict order: persist to a fsync'd write-ahead log before any message is sent. Swap the transport and the same core runs in a seeded simulator or a real gRPC cluster.

  • Write-ahead log + fsync + torn-tail recovery
  • gRPC transport, 3-node docker cluster
  • Client sessions for exactly-once commands
  • All four safety properties asserted every tick
Why the verifier is the point

The linearizability checker earned its keep.

A Jepsen-style checker records every client operation with real timestamps and searches for a valid sequential ordering (Wing & Gong, memoized, decomposed per key). Mandatory negative controls — deliberately broken variants — confirm it actually rejects bad histories. It caught two real bugs that the entire conformance suite missed, both outside the consensus core:

bug 01 · result routing

The wrong answer to the right client

Pending client requests were keyed by log index. A deposed leader could hand a client a different command's result after its slot was overwritten. Fixed: match the applied entry's (client_id, seq) before resolving, and fail pending requests on loss of leadership.

bug 02 · stale read

A fresh leader reading the past

A newly elected leader holds every committed entry but hasn't advanced its commit index over them until its own-term no-op commits. A ReadIndex read served before that could miss a committed write. Fixed: read at max(commitIndex, term-start index) and wait for the state machine to catch up.

In both cases the consensus core was correct. The bugs lived in read and result handling — and only checking real histories against real-time order surfaced them.

Evidence

Every claim has a command behind it.

Nothing here is asserted. Each number is reproducible from the repository.

make verify  ·  linearizability under chaos
Operations checked across chaos scenarios267,329
Linearizability violations0
Negative controls (deliberate bugs) caught4 / 4
Chaos injectedpartitions · kills · restarts · loss
make bench:election  ·  200 trials, 150–300ms timeout
p50 — kill leader → new leader elected and serving235 ms
p95430 ms
max560 ms
pytest  ·  entire cluster in-process
Tests exercising real consensus147
Wall-clock, full suite~25 s
Safety properties asserted continuously4
Built in order

Ten phases, one at a time.

Types and log → persistence → elections → replication → KV & sessions → gRPC → snapshotting → membership → linearizable reads → the checker → the benchmark.

01Entry, message types, replicated log
02Storage: WAL, fsync, crash recovery
03Elections, PreVote, simulator
04Log replication + conformance suite
05KV state machine + client sessions
06gRPC transport + docker cluster
07Snapshotting & log compaction
08Membership changes · ReadIndex reads
09Linearizability checker + controls
10Election-latency benchmark
$ docker compose up --build # real 3-node gRPC cluster
$ make test # 147 tests, whole cluster in-process
$ make verify # linearizability under chaos, 0 violations
$ make bench:election # re-election latency distribution