Deep Dive · supplement to Part 1, Lesson 8 · visual edition

Consensus — the floor beneath FLP, Raft & BFT

~30 min · 6 levels · the proofs & the safety bug you'd otherwise ship · interactive recall

Published

ConsensusPaxosRaftFLPIdempotency keys

Your bar: from a blank page, redraw why FLP is true (bivalence), exactly what makes Raft safe (the election restriction), the one commitment rule everyone states wrong (Figure 8), and why lying nodes force 3f+1. Five sentences from Lesson 8 each hide a subtlety that separates “I read the Raft paper” 3 from “I could implement it without a safety bug.”

One sentence holds the whole supplement. Each level unpacks one chip of it:

Async consensus can’t be guaranteed (FLP)

so real protocols buy liveness with partial synchrony

Raft moves safety into the election

and lying nodes raise the wall to 3f+1

THE CONSENSUS CONTRACT — three properties one protocol must keep AGREEMENT no two correct nodes decide differently VALIDITY a decided value was actually proposed TERMINATION every correct node eventually decides FLP (1985): you cannot guarantee all three — deterministically, in a purely asynchronous system, if even one node may crash. Safety (the two green ones) is always kept. Termination is the one that gives way. ↑ this is the casualty
Memorise this banner. Every level below either proves why termination must yield, or shows how a real protocol keeps the two safety properties anyway.
1

FLP, actually proved — the bivalence argument

“An adversary delays the deciding message forever” is the shape. The real proof says precisely where the impossibility lives.

The bivalence argument. Configurations are 0-valent, 1-valent, or bivalent. A bivalent start exists; from any bivalent configuration the adversary can always step to another bivalent one, so it never reaches a decision.

The bivalence argument. Configurations are 0-valent, 1-valent, or bivalent. A bivalent start exists; from any bivalent configuration the adversary can always step to another bivalent one, so it never reaches a decision.

Model the system as a configuration = every node’s state + every in-flight message. Its valence is which decisions are still reachable:

0-valent every run from here decides 0 — sealed, even if nobody knows 1-valent symmetrically sealed on 1 bivalent both 0 and 1 still reachable — the future is undecided "univalent" = the outcome is already fixed; "bivalent" = it isn't
The proof is two lemmas: a bivalent start exists, and from any bivalent config the adversary can stay bivalent forever.

Lemma 1 — a bivalent start exists Order all initial input vectors so neighbours differ in one node’s input. All-0 is 0-valent, all-1 is 1-valent; somewhere two neighbours flip valence. Crash that one differing node and the runs are indistinguishable → must decide alike → one neighbour is bivalent.

Lemma 2 — bivalence is inescapable From a bivalent config, delivering a pending message e can always be arranged to land in another bivalent one. A “critical step” where e vs e’ forces opposite valences can’t exist: they either commute (different nodes) or one node can crash right after (same node) — indistinguishable.

✗ “FLP says consensus is impossible in practice”

✓ It says no deterministic protocol can guarantee termination in a purely asynchronous model

The dagger: the adversary may not drop messages or crash more than one node — it only chooses message order, and every message is still eventually delivered. Impossibility comes from asynchrony alone. Relax any one assumption and consensus is solvable:

pure async FLP wall ✗ relax one + randomisation Ben-Or — terminates w.p. 1 + partial synchrony Dwork–Lynch–Stockmeyer 1988 + full synchrony bounded delays → trivial safety ALWAYS liveness once calm
Every real protocol below takes the partial-synchrony escape: keep safety always, get liveness once the network calms down.2

🔒 Memory rule: FLP kills guaranteed termination in pure async with one crash — order alone is enough; real systems trade liveness for partial synchrony and never give up safety.

Memory check
  • What is a "configuration"? → all node states + all in-flight messages
  • Which property does FLP make impossible to guarantee? → termination (safety always holds)
  • The adversary's only power? → choosing message order; it can't drop or extra-crash
2

Raft is safe via five properties — one is subtle

Raft (Ongaro & Ousterhout, 2014) 3 guarantees correctness through five always-true invariants. Four are mechanical; one carries the whole proof.

#PropertyPlain meaning
1Election Safetyat most one leader per term
2Leader Append-Onlya leader never overwrites/deletes its own log, only appends
3Log Matching

same index and term in two logs ⇒ all prior entries identical

4Leader Completenessa committed entry is present in the log of every later-term leader
5State Machine Safety

no two servers apply a different command at the same index

Leader Completeness (4) is the one that makes the whole thing work — and it’s not obvious. A brand-new leader is never told what was committed, so why must it already hold every committed entry? The answer is the election restriction + the quorum-overlap trick:

WHY A NEW LEADER CAN'T BE MISSING A COMMITTED ENTRY S1✓ S2✓ S3✓ S4 S5 committed entry sits on a MAJORITY (S1,S2,S3) candidate needs a MAJORITY of votes (S3,S4,S5) two majorities OVERLAP in ≥ 1 node (S3) S3 holds the committed entry & only votes for an at-least-as-up-to-date candidate → winner has the entry too
On RequestVote, a follower refuses unless the candidate's log is at least as up-to-date (compare last-entry term, then index). A candidate missing a committed entry can never assemble a majority.
✗ “The previous leader hands its log to the new one”

✓ Nobody hands anything over — the up-to-date check at vote time guarantees it

🗳️ Memory rule: Raft moves the hard safety work into the election, not the replication — the up-to-date vote check is what makes a leader complete.

Memory check
  • Which property does the real work? → Leader Completeness (#4)
  • What enforces it? → the election restriction + majority overlap
  • "Up-to-date" compares what, in order? → last-entry term, then index
3

The commitment gotcha — Raft’s Figure 8

The single most important subtlety in Raft, and the rule almost everyone states wrong on a first reading.

✗ “An entry is committed once stored on a majority of nodes”

✓ True only for a current-term entry; a previous-term entry on a majority can still be overwritten

The Figure-8 commitment trap. An entry from an old term, replicated to a majority, can still be overwritten by a later leader. A leader must only count an entry committed once it has replicated an entry from its own term on a majority.

The Figure-8 commitment trap. An entry from an old term, replicated to a majority, can still be overwritten by a later leader. A leader must only count an entry committed once it has replicated an entry from its own term on a majority.

Walk the canonical five-node scenario (S1–S5). At step (c) the old entry is on a majority — and committing it there is the disaster:

StepWhat happensDanger
(a)

S1 is leader in term 2, replicates idx2(t2) to S1,S2

(b)

S1 crashes. S5 wins term 3 (S3,S4,S5 — short logs pass the check), accepts a different idx2(t3) on S5 only

(c)

S5 crashes. S1 restarts, wins term 4, re-replicates old idx2(t2) to S1,S2,S3 — now a majority

⚠ tempting to call it committed
(d)

If it did: S1 crashes, S5 wins term 5 (S5’s idx2(t3) is a higher term → “more up-to-date”), forces idx2(t3) onto everyone

✗ overwrites a “committed” entry — agreement violated

📌 The fix (one sentence in the paper): A leader counts an entry committed only once it has stored an entry from its own current term on a majority; earlier-term entries are then committed indirectly, carried by Log Matching.

So at (c), S1 must not commit idx2(t2) by replica count. It waits to replicate a fresh idx3(t4) on a majority — the instant that commits, S5 (lacking idx3) can never win again, so idx2 is safe too.

Commitment is only ever decided through a current-term entry; the past rides along.

Miss this and you ship an implementation that loses committed data under one specific crash interleaving — and it passes every test that doesn’t reproduce exactly that order.

Memory check
  • When is replica-count commitment safe? → only for a current-term entry
  • How do old-term entries get committed? → indirectly, once a current-term entry above them commits
  • Why won't normal tests catch the bug? → it needs one exact crash interleaving
4

Membership change without splitting in two

Cluster membership isn’t fixed. Switch nodes from C_old to C_new at slightly different moments and each set can form a majority independently — two leaders, divergence. Changing membership is itself a consensus problem.

NAIVE SWITCH — split brain C_old majority elects leader A C_new majority elects leader B two independent majorities → two leaders → diverge ✗ JOINT CONSENSUS — safe 1 · commit C_old,new every decision needs maj(C_old) AND maj(C_new) 2 · commit C_new old-only nodes retire because each decision needs BOTH majorities, two disjoint majorities can never form during the transition → Election Safety preserved ✓
The cluster transitions through an intermediate C_old,new where elections and commits each need a majority of both sets, separately and simultaneously.
✗ “Just point every node at the new config and restart”
✓ A naive cutover breaks Election Safety; you need joint (overlapping) consensus

🔀 Memory rule: Joint consensus forces every decision to clear a majority of both old and new sets at once, so two independent majorities can never coexist. (Single-server-at-a-time changes came later; joint consensus is the idea to hold.)

Memory check
  • Why is a naive membership switch dangerous? → C_old and C_new can each form a majority
  • What does C_old,new require for any decision? → a majority of both sets, simultaneously
  • The two-step sequence? → commit C_old,new, then commit C_new
5

The landscape — you don’t have to use Raft

Raft is one point in a space dominated for decades by Paxos. Same safety; different trade-offs.

Paxos (single-decree) prepare/promise → accept/accepted · minimal, hard Multi-Paxos stable leader runs a log · what most "Paxos" means Raft strong leader · easy to implement · leader = throughput ceiling EPaxos / leaderless commuting cmds need no order · low latency · complex
All provide the same safety. Raft & Multi-Paxos are crash-fault-tolerant (CFT): they assume nodes fail by stopping, not by lying — which is the last, biggest step.
ProtocolIdeaTrade-off
Paxos (single-decree)agree on one value via prepare/promise then accept/accepted, around a quorumproven minimal; famously hard to understand & productionise
Multi-Paxosa stable leader runs a sequence of Paxos instances — a replicated logthe practical form; what most “Paxos” systems mean
Raft

same guarantees, redesigned for understandability: strong leader, terms, election restriction

easier to get right; strong-leader bottleneck caps throughput
EPaxos / leaderlessno fixed leader; exploit that commuting commands need no agreed orderlower latency, no leader hotspot, at real complexity cost

🗺️ Memory rule: Paxos → Multi-Paxos → Raft are the same CFT family; EPaxos drops the leader. Pick by who you trust to bottleneck (the leader) vs how much complexity you’ll pay.

Memory check
  • Multi-Paxos in one line? → a stable leader running a sequence of Paxos = a replicated log
  • Raft's main cost? → strong-leader throughput ceiling
  • What do CFT protocols assume about failures? → nodes stop, never lie
6

When nodes lie — Byzantine consensus & the 3f+1 wall

Drop the crash-fault assumption. A Byzantine node (Lamport, Shostak & Pease, 1982) 5 can do anything — send conflicting messages, forge values, collude. The model for systems crossing trust boundaries: blockchains, compromised participants.

Crash vs Byzantine quorums. Tolerating f crashes needs 2f+1 nodes; tolerating f liars needs 3f+1, because quorums must overlap in enough nodes to guarantee at least one honest one in common.

Crash vs Byzantine quorums. Tolerating f crashes needs 2f+1 nodes; tolerating f liars needs 3f+1, because quorums must overlap in enough nodes to guarantee at least one honest one in common.

CRASH · 2f+1 · quorum f+1 overlap = 1 node, and it's correct (crash nodes don't lie) BYZANTINE · 3f+1 · quorum 2f+1 overlap ≥ f+1, so ≥ 1 of it is HONEST even if the liar is in the intersection
Under crash faults a one-node overlap suffices — that node is trustworthy. Under Byzantine faults the shared node might be the liar, so the overlap must contain more honest than faulty nodes → 2f+1 quorums out of 3f+1, intersecting in f+1.
Fault modelNodesQuorumWhy
Crash (CFT — Raft, Paxos)2f + 1f + 1any two majorities overlap in ≥ 1 node, which is correct (didn’t lie)
Byzantine (BFT — PBFT)3f + 12f + 1any two quorums overlap in ≥ f + 1 nodes, so ≥ 1 of the overlap is honest
✗ “BFT is the safer choice, use it everywhere”

✓ Inside one datacenter, crash faults are the honest model — 2f+1 Raft is right; reach for 3f+1 only across trust boundaries

🛡️ Memory rule: Crash needs a quorum overlap of one trustworthy node; Byzantine needs the overlap to out-number the liars → 2f+1 of 3f+1, intersecting in f+1 with ≥ 1 honest.

PBFT (Castro & Liskov, 1999) 5 made this practical with three phases (pre-prepare, prepare, commit). Nakamoto/Bitcoin reaches probabilistic Byzantine agreement via proof-of-work instead of fixed quorums; Tendermint and HotStuff are PBFT descendants.

Memory check
  • Why 3f+1 not 2f+1? → overlap must contain an honest node even if the liar is in it
  • Byzantine quorum size? → 2f+1, intersecting in f+1
  • PBFT's three phases? → pre-prepare, prepare, commit

Where each idea shows up — real systems

Grounding for the theory: the concept, a concrete place it bites, and the lesson it teaches.

ConceptReal systemWhat it teaches
FLP / partial synchronyAny Raft/Paxos cluster wedging during a network blip, then recoveringsafety holds; liveness waits for the network to calm
Election restrictionetcd / Consul leader elections refusing stale candidatescommitted history can’t be lost across a leader change
Figure-8 commitmentThe classic Raft implementation bug: committing prior-term entries by replica countonly current-term entries commit by majority
Joint consensusResizing an etcd / CockroachDB raft group safelymembership change is itself consensus
Multi-Paxos vs RaftGoogle Chubby/Spanner (Paxos) vs etcd/TiKV (Raft)same safety, different ergonomics & bottlenecks
BFT / 3f+1Tendermint, HotStuff, Bitcoin’s probabilistic agreementcrossing trust boundaries triples the honest-overlap requirement

Pattern to notice: inside one company’s datacenter, 2f+1 crash-fault tolerance is almost always the right model. The 3f+1 machinery is for when participants genuinely can’t trust each other.

Retrieval practice — mix the levels

Reading builds fluency (feels familiar). Recall builds storage (lasts). Answer from memory — instant feedback.

Q1. FLP proves consensus can't be guaranteed specifically when the system is…

Q2. Which consensus property does FLP make impossible to guarantee?

Q3. A brand-new Raft leader is guaranteed to hold every committed entry because…

Q4. A Raft leader may treat an entry as committed only once it has…

Q5. Joint consensus prevents split-brain during membership change by…

Q6. Byzantine consensus needs 3f+1 rather than 2f+1 because…

Reconstruct the deep dive from a blank page

Write the six levels in order, one line each, with nothing on screen. Then reveal and compare — gaps are your next drill.


1 FLP: bivalence — order alone kills guaranteed termination; partial synchrony is the escape · 2 Raft safety lives in the election: up-to-date check + majority overlap ⇒ Leader Completeness · 3 Figure 8: commit by replica count only for current-term entries; old ones ride along · 4 Membership: joint consensus needs a majority of both sets ⇒ no split brain · 5 Landscape: Paxos→Multi-Paxos→Raft (CFT); EPaxos drops the leader · 6 Byzantine: liars force 3f+1, quorum 2f+1, overlap f+1 with ≥1 honest.

I’m your teacher — ask me anything. Say “grill me on consensus” for mixed no-clue questions, or hand me a real system and I’ll place it on CFT↔BFT and leader↔leaderless with you. Want to whiteboard a Raft commit walkthrough or the Figure-8 trace live? Just ask.

Interview — pick your bar

Answer out loud in ~60s, then reveal. Core = recall · Senior = trade-offs & failure modes · Staff = synthesis under ambiguity · System Design = open design round (a different axis, not a harder level).

What problem does consensus solve, and what are its three required properties?
Hit these points: consensus = a set of nodes agree on a single value (or a single ordering of commands) despite crashes and message delays → the three properties: Agreement (no two correct nodes decide different values), Validity (the decided value was proposed), Termination (every correct node eventually decides) → agreement + validity are safety, termination is liveness → consensus is equivalent to total-order broadcast, which is exactly what a replicated state machine / replicated log needs → so "build a replicated log" and "solve consensus" are the same problem.
Why does crash tolerance need 2f+1 nodes but Byzantine tolerance need 3f+1?
Hit these points: it's all quorum-overlap reasoning → crash (CFT): with 2f+1 nodes a majority is f+1, and any two majorities overlap in ≥1 node — that shared node is honest (crashed nodes just stop), so it carries the agreed value forward → Byzantine (BFT): the overlapping node could be the liar, so a single shared node isn't enough; you need quorums of 2f+1 out of 3f+1 so any two intersect in f+1 nodes, guaranteeing ≥1 honest node in the overlap → mnemonic: CFT survives nodes that stop, BFT survives nodes that lie → PBFT does this in three phases; Nakamoto/PoW gives only probabilistic finality.
What does FLP state precisely, and what's the standard escape hatch?
Hit these points: FLP: no deterministic protocol can guarantee termination in a purely asynchronous model that tolerates even one crash → it does not say consensus is impossible — safety is fine; it says you can't guarantee both safety and liveness with no timing assumptions → the escape is partial synchrony (DLS 1988): assume the network is eventually timely, use timeouts for liveness, and never let timeouts compromise safety → randomization is the other escape (terminate with probability 1) → that's why every real protocol (Paxos, Raft) keeps safety unconditional and makes liveness depend on the network calming down.
How does Raft elect a leader and guarantee at most one per term?
Hit these points: time is divided into terms; a follower whose election timeout fires becomes a candidate, increments the term, votes for itself, and requests votes → each node grants at most one vote per term → a candidate wins only with a majority; since two majorities always overlap and the overlap node already voted, two leaders in one term is impossible (Election Safety) → split votes are resolved by randomized election timeouts so candidates rarely time out together → the leader sends periodic heartbeats; a higher term seen anywhere makes a node step down.
State FLP precisely, then explain why the bivalence argument is sharper than "the adversary delays a message."
Hit these points: no deterministic protocol can guarantee termination in a purely asynchronous model tolerating one crash → bivalence is the engine: Lemma 1 shows a bivalent (outcome-undecided) initial configuration must exist, and Lemma 2 shows from any bivalent state the adversary can always reach another bivalent state → so the protocol can be kept perpetually undecided → the key subtlety: the adversary only reorders messages, it never drops them or crashes more than one node — far weaker than "messages get lost," which is why the result is so strong → bonus: names the partial-synchrony escape (DLS) and that randomized protocols sidestep it too.
A new Raft leader is never told what was committed. Why is it guaranteed to already hold every committed entry?
Hit these points: the election restriction — a voter grants its vote only to a candidate whose log is at least as up-to-date (compare last-entry term, then index) → a committed entry lives on a majority; a winning candidate also needs a majority; those two majorities overlap in ≥1 voter → that overlapping voter holds the committed entry and would refuse to vote for a candidate missing it → therefore the winner already has every committed entry — this is Leader Completeness → red flag answer: "the old leader hands its log over" — there is no handover; safety comes from the vote-time check, not from the predecessor.
Walk me through Raft's Figure 8 and state the commitment rule that prevents it.
Hit these points: an entry from a previous term can be replicated to a majority and still be overwritten — a later leader (S5) can win with a higher last-term entry and clobber it → so "replicated on a majority" is not sufficient to call a prior-term entry committed → the rule: a leader may only mark an entry committed once it has replicated an entry from its current term on a majority; earlier entries then commit indirectly via Log Matching → the trap is committing by replica count alone → bonus: this bug hides because it needs a specific crash/election interleaving, so naive tests pass — you need a model checker (TLA+) or targeted fault injection to force it.
How does Raft change cluster membership without risking two leaders?
Hit these points: a naive single-step cutover from C_old to C_new lets each configuration independently form a majority during the overlap → split brain, two leaders → joint consensus routes through a combined C_old,new in which every election and every commit requires a majority of both the old and new sets simultaneously → sequence: commit C_old,new, then commit C_new; once C_new is committed the old config can retire → because both majorities are required during transition, two disjoint majorities can never form → bonus: single-server add/remove (changing membership one node at a time) is the later, simpler optimization that avoids full joint consensus.
Your team's homegrown Raft loses a committed write under one rare crash sequence. What's your first hypothesis and how do you confirm it?
Hit these points: first hypothesis: the Figure-8 commitment bug — committing a prior-term entry by replica count instead of waiting to replicate a current-term entry on a majority → second candidates: missing fsync-before-ack (durability lost on crash), or a broken election restriction letting a less-up-to-date candidate win → confirm not by adding logs and hoping the race reappears, but by writing a TLA+/model-checked spec or a deterministic-scheduler test that forces the exact crash-then-elect interleaving → reproduce → fix the commit rule → keep the model check in CI as a regression → the staff move is treating safety bugs as specification problems, not log-spelunking problems, because the failing interleaving is too rare to catch by chance.
When would you choose Multi-Paxos, Raft, EPaxos, or PBFT — and when none of them?
Hit these points: all crash-fault options give identical safety, so choose on operational and performance axes → Raft for implementability and a strong leader's simple mental model (most teams); Multi-Paxos as the battle-tested incumbent where it already exists; EPaxos to remove the single-leader throughput/latency bottleneck for commuting commands, accepting a sharp jump in complexity; PBFT only when you must tolerate lying nodes across a trust boundary (3f+1, 3 phases) → none when you don't actually need linearizable agreement — if eventual consistency / CRDTs / a single-writer design satisfy correctness, consensus is needless coordination cost → the principal framing: consensus is the most expensive coordination primitive; justify the need before picking a flavor.
Distinguish safety from liveness in a replicated log, and which one you're allowed to sacrifice.
Hit these points: safety = nothing bad happens: never two leaders in a term, never lose or reorder an acknowledged committed entry, never let two correct nodes diverge → liveness = something good eventually happens: a request eventually commits, a new leader is eventually elected → FLP says you cannot guarantee both under pure asynchrony, so the universal design choice is: safety is unconditional, liveness is best-effort under partial synchrony → concretely, during a partition a CP log refuses progress (sacrifices liveness/availability) rather than risk two leaders (sacrificing safety) → the staff point: any protocol that "stays available" through a partition by relaxing majority is silently trading away safety — make that trade explicit and intentional, never accidental.
Design-round framework — drive any consensus/replicated-log prompt through these, out loud:
  1. Clarify the contract: linearizable commits, durability (fsync), RPO = 0?, throughput & latency targets.
  2. Fault model: crash-only (2f+1) or Byzantine/trust boundary (3f+1)? — pick the cluster size from f.
  3. Commit path: majority replication, commit only via a current-term entry, fsync-before-ack.
  4. Leadership: election restriction on votes, randomized timeouts, leader leases to bound stale reads.
  5. Membership changes via joint consensus; client dedup/idempotency so retried proposals don't duplicate.
  6. Liveness vs safety: what happens under partition (block the minority); how reads stay linearizable.
  7. Verification & ops: TLA+/model check the safety properties; fault-injection for rare interleavings.
Whiteboard the commit path for a replicated log that must never lose an acknowledged write.
A strong answer covers: replicate to a majority before acking the client, and on each replica fsync the entry to durable storage before counting its vote — an in-memory ack that a power loss erases is not a commit → mark an entry committed only after a current-term entry reaches a majority (Figure-8 rule), so a later leader can't overwrite a "committed" prior-term entry → enforce the election restriction so any new leader already holds every committed entry (Leader Completeness) — no log handover → bound stale reads with a leader lease or read-index so a deposed leader can't serve a linearizable read → make client requests idempotent (request IDs / dedup) so a retried proposal after a timeout commits at most once → change membership via joint consensus to preserve Election Safety → verify the safety properties with a model checker and force the rare crash/election interleavings with fault injection → name the trade-off: fsync-before-ack and majority replication add tail latency, which you accept as the price of RPO = 0.
Design a consensus-backed configuration / coordination store (think etcd / ZooKeeper).
A strong answer covers: a small odd-sized cluster (3 or 5) running a single replicated log via Raft/Multi-Paxos — crash-fault model, 2f+1, since it's inside one trust domain → all writes go through the leader and the log, giving linearizable, totally-ordered updates; expose compare-and-swap / leases / watches on top of the log → serve reads via the leader with a read-index or lease so they're linearizable without a full log round-trip, or offer explicitly-stale follower reads as a separate, labeled API → durability: fsync-before-ack, periodic snapshots + log compaction so the log doesn't grow unbounded → under partition, the minority side stops serving writes (CP) — correctness over availability, which is right for locks/config → clients use sessions + fencing tokens so a client that loses its lease (GC pause, partition) can't act on a stale lock → membership changes via joint consensus; keep the cluster small because write latency = majority round-trip and grows with size → name the trade-off: this store is deliberately low-throughput and strongly consistent — it coordinates other systems, it is not your data plane.

★ Cheat sheet — the numbers & the gotchas

Mental models: FLP = order alone defeats guaranteed termination · safety always, liveness waits · Raft safety lives in the election · commit only via a current-term entry · joint consensus for membership · CFT = 2f+1, BFT = 3f+1.

The numbers

QuantityValue
Crash-fault nodes for f failures2f + 1 (quorum f+1, overlap ≥1 correct)
Byzantine nodes for f liars3f + 1 (quorum 2f+1, overlap f+1 ⊇ honest)
Consensus propertiesAgreement · Validity · Termination
FLP casualtyTermination (in pure async, 1 crash, deterministic)
Raft safety properties

Election Safety · Append-Only · Log Matching · Leader Completeness · State-Machine Safety

The gotchas that bite

① “Majority = committed” is true only for current-term entries (Figure 8). ② A new leader is complete because of the vote-time up-to-date check, not a handover. ③ Naive membership cutover breaks Election Safety — use joint consensus. ④ Don’t reach for BFT inside one datacenter; crash faults are the honest model.

Sources
1. Fischer, Lynch & Paterson — Impossibility of Distributed Consensus with One Faulty Process (JACM 1985). The bivalence proof.
2. Dwork, Lynch & Stockmeyer — Consensus in the Presence of Partial Synchrony (1988). The escape hatch every real protocol uses.
3. Ongaro & Ousterhout — In Search of an Understandable Consensus Algorithm (Raft) (USENIX ATC 2014). §5.4 = Leader Completeness & Figure 8.
4. Lamport — The Part-Time Parliament (1998) / Paxos Made Simple (2001).
5. Lamport, Shostak & Pease — The Byzantine Generals Problem (1982); Castro & Liskov — Practical Byzantine Fault Tolerance (1999).
6. Kleppmann — DDIA, Chapter 9 — ties consensus to total-order broadcast and linearizability.
Was this lesson helpful? Thanks — noted.

These notes reflect my current understanding and are updated as I learn, build, and discover better explanations.