builds / raft / stage-4SHEET 4 / 6 · REV ASIGN IN
ASSEMBLY DIAGRAM — YOUR RAFT CLUSTERSCALE: LEARNING
clientthe outside worldTIMING CRYSTAL✓ builtELECTION CIRCUIT✓ builtREPLICATION BELT✓ builtCOMMIT INTERLOCK⚙ buildingBLACK BOXstage 5STORM ENCLOSUREstage 6
BUILTUNDER CONSTRUCTIONNOT YET IMAGINED INTO EXISTENCE
STAGE 4 · THE COMMIT INTERLOCK

The Commit Interlock

Replicated is not committed, and the gap between them is where Raft's safety actually lives.

What you're wiring up

An entry is committed once the leader has seen it stored on a majority. The promise attached to that word is enormous: a committed entry will be present in the log of every future leader, forever. Two rules are what make the promise true, and both get added on this sheet.

The first is the election restriction. A voter refuses any candidate whose log is less up-to-date than its own, comparing the last entry's term first and using length only as a tiebreak. Since a committed entry sits on a majority, and any winner needs a majority, the winner always already holds it.

The second is subtler and is the paper's Figure 8: a leader may only count replicas of entries from its own term toward commitment. Older entries ride along and commit as a side effect. Drop that guard and there is a specific crash-and-election sequence where the cluster acknowledges a write and then loses it. The harness replays exactly that sequence, a hundred times, with random seeds. This is the sheet where your Raft becomes correct rather than merely functional.

# voter asks: is your log at least as up-to-date as mine?
mine:      lastLogTerm 4, lastLogIndex 9
candidate: lastLogTerm 5, lastLogIndex 2  →  grant   (higher term wins)
candidate: lastLogTerm 4, lastLogIndex 9  →  grant   (tie, equal length)
candidate: lastLogTerm 4, lastLogIndex 8  →  refuse  (same term, shorter)

Assembly steps

[ 01 ]
Add commitIndex and lastApplied, plus an applier goroutine that pushes each newly committed entry onto the harness's applyCh, in order and exactly once.
hint

A condition variable signalled on "commitIndex changed", driving a loop over lastApplied+1 through commitIndex, is the clean shape.

hint

Never send on applyCh while holding the main mutex. That deadlock will find you.

[ 02 ]
Implement the leader commit rule: after every matchIndex advance, find the highest index replicated on a majority whose entry's term equals your current term, and ratchet commitIndex up to it.
hint

That term guard is the Figure 8 defense. When this sheet's nastiest test reports a lost committed write, go re-read section 5.4.2.

[ 03 ]
Propagate commitment downhill: put leaderCommit in every AppendEntries, and have followers set commitIndex to the smaller of leaderCommit and the index of the last entry they actually hold.
hint

That minimum is not a formality. A follower must never mark entries committed that it has not received yet.

[ 04 ]
Add the election restriction: carry lastLogIndex and lastLogTerm in RequestVote, and refuse candidates whose log is behind yours.
hint

Compare the last entry's term first, length only as a tiebreak. Comparing lengths first is the wrong-but-plausible reading the harness specifically traps.

Go deeper (after it passes)

This is the capstone practice for DDIA's Consistency and Consensus module — read it now that you have had to implement the guarantees instead of just naming them. The applier loop is also a textbook condition-variable pattern, worth revisiting the concurrency module's CV section for.