The Replication Belt
The leader's only job is to make every other log identical to its own.
What you're wiring up
Clients hand commands to the leader, the leader appends them to its log and ships them out. What keeps logs from quietly diverging is the log matching check: every AppendEntries says these entries go immediately after index i, which had term t. A follower that does not have exactly that entry in exactly that slot refuses the batch.
On refusal the leader steps its guess back one entry and tries again, walking backwards until it finds the last index where the two logs agree, then overwrites everything after it. It is induction carried out on the wire — if two logs agree on one entry, they provably agree on every entry before it.
One thing is deliberately missing: any notion of when an entry is safe. Entries flow and logs converge, but nothing is committed and nothing is applied yet. Keeping replication and commitment as separate ideas is why both of them stay clear.
# leader holds 1..5, guesses the follower holds 1..3 AppendEntries{prevLogIndex: 3, prevLogTerm: 2, entries: [e4, e5]} follower: my index 3 has term 1, not 2 → {success: false} # leader backs off one entry and retries AppendEntries{prevLogIndex: 2, prevLogTerm: 1, entries: [e3, e4, e5]} follower: match → {success: true} → nextIndex 6, matchIndex 5
Assembly steps
hint
Use 1-based indexing with a sentinel entry at index 0. It deletes every "is the log empty?" special case from your prevLogIndex handling.
hint
Never block in Start. Replication is asynchronous; the harness submits and then watches the logs converge on their own.
hint
Piggyback entries on the heartbeat ticker you already have rather than adding a second send path. One code path means far fewer interleavings to reason about.
hint
Truncate only when an incoming entry conflicts — same index, different term. Blind truncation lets one stale reordered RPC erase entries you already acknowledged.
hint
Correctness passes without this. Only the 100-entry catch-up test's time budget cares.
Go deeper (after it passes)
The backtracking loop here is the same shape as any anti-entropy protocol you will meet later. Pair it with DDIA's replication module, and with the key-value store track if you built it — that store is the state machine this log is about to drive.