Interactive course · about 8 hours

Distributed Consistency

One machine is simple. It works, or it is down, and when it is down nobody gets a wrong answer. Two machines is where this turns hard. Their clocks do not agree, so neither can say which of two things happened first. Cut the wire between them and each one carries on serving customers, certain that it is the one in charge. Both are behaving correctly. They now hold different answers, and somebody has to decide which answer the world gets.

How this works

One small network sits under every widget on these pages. Machines hold values, a message takes a whole number of ticks to cross, some messages are thrown away, and a switch stops messages crossing from one side to the other. A tick is one step of a clock this course controls, not a real second. When a widget says three machines ended up holding two different values, that run really happened and the values were really counted at the end of it. No number on these pages was typed in by hand.

What you need before you start

You should be comfortable with the idea that machines talk by sending each other messages, that a message can be lost or delayed without anybody being told, and that the two ends have to cope with that themselves. The course Reliable Data Transfer builds all of it from nothing. If you have not done it, Step 1 here re-explains the parts this course leans on. No programming is needed: two labs ask you to write a one-line rule and every piece of that line is explained first.

The steps

Step 1

The sale that goes missing

A server is a machine whose job is to answer other machines. The machines that ask it things are called clients, and one thing a client asks for is called a request. The answer coming back is a reply. Nothing in that arrangement is clever: a shop server that holds the number of jumpers left in stock is a machine with a number written down and a habit of answering questions about it.

The number it holds is its state. Looking at the state is a read, and changing it is a write. With one machine there is one copy of the state. With two or more machines, messages and failures can leave the copies at different versions.

What is a tick, and why not use real seconds

Every widget here counts time in ticks. A tick is one step of a clock we control, and nothing happens between two ticks. A message posted on tick 4 that takes two ticks to travel is delivered on tick 6, and until then it exists but has not arrived.

Real networks work in thousandths of a second, which is far too fast to watch and far too vague to reason about. Ticks let you press a button and see exactly one thing happen. Everything you learn about ticks is true of milliseconds; you are just able to see it.

Lab 1 · One machine, and nothing to disagree about
Try this firstPress Ana: add one, then press Tick three or four times. Watch the request sit in the wire list for a couple of ticks before the log says it arrived and the counter moved. Then press Ana: add one and Ben: add one one after the other and press Run until quiet.
Notice: the counter is right every single time, however you press the buttons. Now press Crash the server while a request is still on the wire. Requests are thrown away and nobody gets a reply, which is annoying, but no client is told a wrong number and there is no second copy to argue with. One machine gives you exactly two states of the world: working, or not working.
Why does a single sale need two trips

Selling one jumper is not one action. The client has to find out how many there are, work out the new number, and send that new number back. That is a read, some arithmetic, and a write: two trips across the network with a gap in the middle.

The gap is where everything goes wrong for the rest of this page. While one client is thinking, the number it read is already out of date, and it does not know. Nothing in the network can tell it, because nothing in the network is watching.

If one machine is so much simpler, why have two

Because one machine is one power cut away from a shop that cannot sell anything, and one broken disk away from a shop that has lost its records. A second machine holding a copy means the shop survives losing either one. That is the reason people put up with everything in this course.

The second reason is size. One machine can only answer so many requests a second, and one machine in London answers a customer in Sydney slowly no matter how fast it is. Copies close to the customer are the only fix and a copy is a second machine with its own opinion.

Lab 2 · Make a sale disappear
Try this firstThe four steps are already placed in a safe order, so press Run this schedule and read the stock at the end. It says 8, which is ten jumpers minus two sales. Now press Clear and place the four steps in an order where the stock ends up wrong, then press Check my schedule.
Notice: the order that loses a sale has both people reading before either writes. Nothing broke to make that happen. No message was lost, no machine crashed, and both copies end up holding the same number. They agree perfectly, and they are both wrong by one. This is called a lost update, and the cause is the gap in the middle of every read-then-write: time for somebody else to read the same old number. If you get stuck, Show me one that loses a sale places one for you, and it is not the only one that works.
Two shop assistants each sell a jumper in the same second, each using a different machine. Afterwards both machines say the stock is 9, and two jumpers have left the shop. What went wrong?
The second write covered the first. Both assistants read 10, both worked out 9, and both wrote 9, so the second write landed on a number that was already 9 and changed nothing visible. The third option is the tempting one, and it is worth seeing why it is wrong: the machines do not disagree at all here. They hold exactly the same number, and it is exactly one too many. A system can be perfectly consistent and perfectly wrong at the same time.
Step 2

Clocks lie

There is an obvious fix for the lost sale, and almost everybody reaches for it first. Make every write carry the time it happened. When two writes turn up for the same thing, keep the one with the later time and throw the other away. The time carried on a write is called a timestamp, or a stamp for short, and the rule is called last write wins.

It works, as long as the two machines agree what time it is. They do not. Each machine has its own clock, and a clock is a small crystal wobbling a few million times a second with something counting the wobbles. No two crystals wobble at the same rate, so two clocks set together this morning are apart by the afternoon. The gap between two clocks has a name: the skew.

The widgets from here on label their machines node A, node B, or n1 to n5. A node is one machine considered as part of a group, and that is the whole of what the word means. This course says machine when there is one and node when it is one of several.

How can a clock be wrong when it is just counting

The counting is exact. The wobbling is not. A quartz crystal is cut to shiver at a chosen rate, and the rate it actually manages depends on how it was cut, how warm it is now, and how old it is. A typical one is out by a few seconds a month and a warm one in a badly cooled machine is worse.

Nothing about that is a fault, and no amount of money fixes it, because a clock that is out by one part in ten million is still out. Atomic clocks in laboratories are out by less, and they still drift. The lesson is not that clocks are bad. It is that two of them are never quite the same and a rule that compares readings from two different clocks is resting on a difference that nobody measured.

Lab 3 · Two clocks pulling apart
Try this firstPress Set both clocks together now, then press Let an hour pass a few times and watch the gap between them grow. Then press Let a day pass. The last card is the skew, in seconds, and the bar underneath shows how big that gap has become.
Notice: the slider marked Node B gains, seconds per hour is set to 12, which is a perfectly ordinary clock. A day later the two machines are almost five minutes apart. Drag the slider to a negative number and node B falls behind instead. Nothing here is broken or unusual: this is what two working clocks do when nobody makes them agree.
Why not just ask a time server and be done with it

Machines do exactly that. There are servers whose only job is to say what time it is, and your machine quietly asks one every few minutes. It helps a great deal: instead of drifting for a day, a machine drifts for a few minutes and is then pulled back.

What it cannot do is make two clocks equal. The answer arrives by message, and a message takes time. Your machine knows the round trip took 40 thousandths of a second, but not whether that was 20 out and 20 back or 35 out and 5 back, so the time it sets itself to is a good guess with a margin around it. In practice machines on the same network land within a few thousandths of a second of each other, which sounds close until you remember that two writes to the same value can easily be less than a thousandth of a second apart.

What "later" is actually being asked to mean

When you say one write is later than another, you mean something about the real world: this one happened after that one, so it should win. When a machine compares stamps, it is doing arithmetic on two numbers that came from two different clocks. Those are not the same question, and the second one is only a useful stand-in for the first while the skew is smaller than the gap between the writes.

That is the whole trap. The rule looks like it is asking "which happened later" and is really asking "which clock was reading higher", and nobody notices the difference until two writes land close together.

Lab 4 · Predict which write survives
Try this firstPress I predict blue survives, because blue really was written ten seconds after red, then press Merge and reveal. The log shows both machines comparing stamps and deciding. Then press Try another skew and predict again, and drag the slider down to 0 to see when the rule starts telling the truth.
Notice: with the slider at 15, blue is written later in real time and loses anyway, because the machine that wrote it had a slow clock and stamped it 5 while the earlier write was stamped 10. The customer who chose blue was told the change had been made, and it was, and then it quietly went away. Nobody is told. There is no error message anywhere in this system, because as far as the machines can see, the rule worked exactly as written.
Node A writes "red" ten seconds past the minute and stamps it 10. Node B writes "blue" twenty seconds past the minute, but B's clock is fifteen seconds behind, so B stamps it 5. Both machines then send each other what they hold, and each keeps the later stamp. What survives?
Red survives. Each machine holds two numbers, 10 and 5, and keeps the value attached to the bigger one. Nothing in the message says what B's clock was doing, so nothing can correct for it. The third option is the comfortable one, and there is nobody to ask: the merge happens inside two machines with no person watching, and a rule that always picks a winner never reports a problem. Step 5 builds a rule that can say "I cannot choose", and that turns out to be worth a lot.
Step 3

Did this happen before that

If a clock reading cannot be trusted, what is left? Something surprising: the messages themselves. An event is one thing happening on one machine at one moment. Writing a value is an event. Sending a message is an event. A message arriving is an event on the machine it arrives at.

Two facts hold no matter what any clock says. A machine does its own events in its own order, because it did them one after the other and it remembers. And a message is always sent before it arrives, because nothing arrives before it leaves. That is all. Chain those two facts together and you get the only ordering a group of machines can actually be sure of.

Chaining them gives a test you can run with a finger. Event X happened before event Y if you can get from X to Y moving only forwards along one machine's own line, or forwards along a message. If you cannot get from either one to the other, then neither of them could have known anything about the other, and the two events are concurrent. That word is the one to watch: it does not mean the two events happened at the same moment, it means nothing in the system can put them in an order. The relation itself is called happens-before. It is the backbone of every step after this one.

What counts as one event

Whatever you decide to write down. In the picture below, each machine does three things, and each of those is one event with a name like a1 or c2. The letter says which machine, the number says which of that machine's own events came first.

The choice of what to record does not change the answers. If you split one event into two, both halves happen on the same machine in a known order, so every chain that ran through the old event runs through both halves. The reasoning survives being more or less detailed, which is the sign that it is about the messages rather than about the bookkeeping.

Lab 5 · Follow the arrows
Try this firstPress Show me an ordered pair, then press Show me a concurrent pair, and read what changes in the picture. Then pick any two of the nine event buttons yourself, such as b1 and c3, and the line underneath says whether one had to come first.
Notice: the ordered pair lights up a path along the flat lines and the slanted ones, and every step of that path is one of the two facts above. The concurrent pair lights up nothing, because there is no path. Look at the seconds printed for those two events: one of them is earlier on the wall clock, and the system still has no way to know it and no reason to care. Nothing that happened at either event could possibly have depended on the other.
Why this test can be trusted when a clock cannot

Look at what it is made of: no clocks, no assumption about how fast anything runs, nothing that can drift or be set wrongly. Walking the arrows uses two facts and no others, and both are things a machine would report about itself. I did these two things in this order. This message left here before it got there.

So the answer it gives is exactly what the machines could have known, and nothing more. That is also why it stays silent so often. A pair of events with no chain between them is a pair the system holds no evidence about. Putting them in an order anyway is not a measurement. It is a guess wearing the clothes of one.

Concurrent does not mean at the same time

Two concurrent events can be an hour apart. Concurrent here means "no chain of arrows connects them", which is a statement about who knew what, not about when. An event on a machine in Tokyo on Monday and an event on a machine in Peru on Friday are concurrent if no message passed between those machines in between.

The useful way to read it is: neither one could have influenced the other. That is why the ordering does not matter, and why claiming an order anyway is the mistake. A pair that nothing could distinguish is a pair you are free to put in either order, and any two machines are free to make opposite choices without either being wrong.

Lab 6 · Put all nine in one order
Try this firstThe nine events are already placed, sorted by machine, so press Check this order and read which arrow that breaks. Then press Clear and place all nine yourself in an order that respects every arrow, pressing Check this order whenever you want to test it.
Notice: when you find a working order, the checker builds one of its own by always taking the latest event that is ready, and shows you that too whenever it differs from yours. Both are correct. The arrows fix part of the order and leave the rest of it open, and this is what any group of machines can agree on: not the one true order of events, but a list of orders that are all equally defensible. If your system needs everybody to pick the same one, the machines have to agree on a tie-break, and agreeing is Step 8.
Machine one does event p. Machine two does event q. No message has passed between the two machines all day. Machine one's clock says p was at 3 seconds past; machine two's says q was at 5 seconds past. What is true?
They are concurrent. With no message between the two machines, there is no chain of arrows either way, so no machine holds any evidence about the order. The first option treats two readings from two different clocks as if they were readings from one clock, which is exactly the mistake Step 2 was about. The second invents a fact about the clocks that nobody measured. The events are unordered under the available evidence; a system that reports an order is adding an assumption.
Step 4

Counting instead of timing

Arrows in a picture are fine for us, but a machine cannot see the picture. It needs the ordering written down in something it can carry on a message and compare with arithmetic. The trick is to stop measuring time and start counting events.

Give every machine a counter that starts at zero. Every event on that machine adds one to it. When a machine sends a message, the message carries the counter's value. When a message arrives, the receiving machine first jumps its counter up to the number the message carried if that number is higher, and then adds one. Three rules, no clocks and the counters are called logical clocks because they order events without measuring anything.

Why jump up on a receive instead of just adding one

Because the arriving message is proof that something already happened somewhere else. If a message says "I was at 7 when I sent this", then everything the sender had done was numbered 7 or less, and the receiving of it comes after all of that. A counter that answered 3 would be claiming this event came before things it demonstrably came after.

Jumping up is how one machine's history gets folded into another's. It is also why the counters do not stay near each other: a machine that talks to a busy machine inherits its high numbers, and a machine nobody talks to stays low.

Lab 7 · Count the nine events
Try this firstPress Next event nine times, reading the line at the bottom each time. The number under each dot is that event's stamp, and the three cards show what each machine's own counter holds. Watch what happens at b2, c2 and a3, which are the three arrivals, and use ◀ Back to go over them again.
Notice: the widget's own closing line is the point of the whole step, so read it after pressing Count all nine. The promise runs one way only. If one event really did happen before another, its number is smaller. The reverse is not true: a smaller number does not prove anything, because two concurrent events get numbers too and one of them has to be smaller. The slider under the picture drags through the count if you would rather scrub than press.

One number per event is not enough, then, because one number always sorts and can never say "I do not know". The repair is to give every machine a whole row of counters instead: one for itself and one for each other machine it knows about. Three machines means three numbers, written [2, 1, 0], and a row of numbers kept in a fixed order like that is called a vector. The position says which machine the number is about. So [2, 1, 0] reads "I have done 2 things, I know of 1 thing the second machine did. Nothing at all about the third".

An event still adds one, but only to its own machine's number. A message carries the whole row, and on arrival the receiver takes the larger of the two numbers in each position before adding one to its own. Now a comparison can say something a single counter cannot. Suppose every number in X's row is at least as big as Y's, and at least one is bigger. Then everything Y knew, X knew, so Y happened before X. And if each row is ahead in one position and behind in another, each machine knew something the other did not, so the two events are concurrent, proved rather than guessed. Rows used this way are called vector clocks, and Step 5 leans on them entirely.

Who decides which position belongs to which machine

They agree on it in advance, from a shared list of names. Position one is n1 because everybody was handed the same list, and a row of numbers means nothing to a machine that does not have that list. In real systems the row is usually stored as pairs, a name and a number together, which costs more room and saves the argument.

Adding a machine later makes every row longer. Every older row then has to be read as though it carried a zero in the new position, which is exactly what it means: nobody had heard of that machine yet. Taking a machine away is the harder direction. Its number holds real evidence about what it did before it left, and dropping the position throws that evidence away.

If vectors are exact, why does anybody keep the single counter

Because of size. One number per machine means a stamp on every message that grows with the number of machines, which is fine for five and awkward for five thousand. A single counter is one number whatever the size of the system, and it never needs a shared list of names to be understood.

It also does one thing vectors cannot. Vectors leave concurrent events unordered, honestly, and sometimes a system needs to pick one anyway so that every machine picks the same one. A single counter always yields an order, and the machine's own name breaks the ties, so everybody agrees on a winner even though nobody is claiming it really happened first. Knowing that a cheap answer is approximate is more useful than pretending it is not.

Lab 8 · Find the pair that catches the single counter out
Try this firstTwo events, a1 and b2, are picked already, so press Check my pair and read why that pair is no use for this hunt. The table gives every event both kinds of stamp side by side. Then press Clear and hunt for a pair on two machines that had not heard from each other yet.
Notice: for every ordered pair, both kinds of stamp agree, so the single counter is not wrong so much as unable to say "I do not know". The pair you are hunting for is one where the two numbers differ and the vectors cover each other in neither direction. That is a pair where one number quietly invented an order that does not exist, and a machine using it to pick a winner would throw away a value for no reason at all.
You are handed two events. One has a single-counter stamp of 4, the other 7. What can you conclude about the order they happened in?
Nothing yet. The promise only runs from the world to the numbers, not back. Every ordered pair gets numbers in the right order, and so does every concurrent pair, because the counters have to produce some number and any two numbers are either equal or one is bigger. The third option gets the machinery backwards: two events on the same machine never share a number, because each one adds one. To tell an order from a coincidence you need the vectors from Lab 8.
Step 5

Both halves are right

Now break the network instead of a machine. A cable is cut, or a switch fails, or somebody unplugs the wrong thing, and the group of machines is left in two pieces that can each talk among themselves and not across. That is a partition. This page calls it a cut.

The machines cannot see the cut. A machine on the left sends a message to a machine on the right and gets no reply. That is exactly what it would see if the other machine had crashed, and exactly what it would see if the other machine were fine but slow. Three different worlds, one identical view, and no way to tell them apart from inside.

Why can a machine not tell a crash from a cut

Because the only evidence either way is a message arriving, and all three situations produce the same thing: no message. There is no signal for "the machine you want is gone" and no signal for "your messages are not getting through", because whatever sent that signal would have to reach you, and reaching you is the thing that is broken.

You could add a second, separate wire to check on the first, and people do. Now there are two things that can break, and a machine that hears nothing on either one is in exactly the position it started in, with a bit more equipment. The uncertainty is not a gap in the design. It is a fact about being at one end of a connection.

Lab 9 · Cut the network and watch both halves work
Try this firstPress Cut the network, then press n1 writes "north" and n3 writes "south", then press Run until quiet. The four cards show what each machine holds. Now press that first button again, which by then reads Network is cut, to mend the network, and press Gossip everything, which makes every machine tell every machine it can reach what it is holding.
Notice: while the cut is there, n1 and n2 hold north and n3 and n4 hold south, and every machine believes it has told everyone. Neither write was a mistake, and neither half did anything a working system should not do. When the cut heals and they compare vectors, the answer that comes back is not a value: it is I cannot choose. Neither vector covers the other, which is the proof from Step 4 that these two writes are concurrent. Two machines each thinking they are in charge of the same value is called split brain.
What gossip means here

Telling every machine you can reach what you now hold, and letting them pass it on. There is no leader in that arrangement and no list of who has heard what: each machine repeats what it knows and the information spreads like a rumour, which is where the name comes from.

It has one good property that matters for the rest of this course. If the machines keep gossiping and the network eventually works, everybody eventually hears everything, without anybody having to know who is up. This provides eventual convergence, but it does not promise when convergence occurs or what a read may return before then. Step 11 tests whether that guarantee fits the application.

What a conflict is, and what a merge rule is

A conflict is two writes to the same thing where neither happened before the other. Not two writes that arrive in a funny order, and not two writes that disagree. Concurrent writes, proved concurrent by their vectors, with nothing in the data saying which should win.

Something has to happen next, and whatever you choose is a merge rule. Keep the later stamp. Keep the bigger value. Keep both and hand them to a person. Add them together. Every one of those is a real rule that real systems use, and Lab 10 makes you look at what each one destroys.

Lab 10 · Three merge rules, and what each one costs
Try this firstPress each of the three rule buttons in turn and read the three cost lines under the table. The table shows the same three clashes under whichever rule you picked, with the value each one held before the cut next to what the two halves wrote, and the lines below say what that rule threw away in each case.
Notice: the counter and the shopping basket have right answers that no winner-takes-all rule can reach. Two people each added one to 10, so the answer is 12, and no rule that keeps one side's 11 will ever say 12. Keep both and ask later is the only rule here that destroys nothing, and its price is real: something further along has to know what to do with two answers, and for the signpost there is no sensible answer at all. A person has to choose.
While the network was cut, the left half sold a jumper and the right half sold the same jumper, each answering a customer standing in front of it. When the cut healed, the two halves found they held different numbers. Which machine made a mistake?
Neither made a mistake. There was no "checking with the others" available: that is what being cut off means, and a machine cannot tell a cut from a crash anyway. The third option is not silly, though, and it is the subject of the next step. Refusing to write while cut off is a rule you can choose in advance, and it has a price of its own that somebody pays. What you cannot do is have both halves keep serving customers and also keep agreeing.
Step 6

You cannot have everything

The cut leaves a machine with two options and no third. It can answer the customer from whatever it happens to hold, which may be out of date, and accept writes that may later be thrown away. Or it can refuse to answer at all until it can reach enough of the others to be sure. Answering is called being available. Never giving an answer that is out of step with the others is called being consistent.

While the network is cut you may have either one. Not because nobody has been clever enough yet, but because the machine has no information: a cut-off machine that answers is guessing, and a cut-off machine that refuses is admitting it cannot know. This step makes you pick one and then shows you the bill.

Where "answer only with a majority" comes from

A cut divides five machines into two groups, and only one of those groups can hold three or more of them. So "answer only if you can reach more than half of the machines" has a property no other rule has: at most one group can ever satisfy it, whatever the shape of the cut. A group of more than half is called a majority, and this is why the rule is majority rather than "at least two".

Two out of five would let both sides carry on, which is the split brain from Step 5 with extra steps. More than half is the smallest rule that makes two halves unable to both feel in charge.

Lab 11 · Choose a rule, then live with it
Try this firstLeave the rule on Answer anyway and press Run the twelve operations. Read the five cards, then press Only answer if you can reach a majority and run the same twelve again. Every number on those cards comes from what the twelve customers were actually told.
Notice: answering anyway serves all twelve customers and hands out answers that were already out of date, and accepts writes that get thrown away when the halves meet. The majority rule hands out nothing wrong and turns customers away. Read the log at the bottom under each rule: the refusals are not failures of the machine, they are the machine saying "I can reach two of five, so I might be the half that is out of date".
What an out-of-date answer costs, in real money

It depends entirely on the question, which is why this is a decision and not a rule. An out-of-date count of likes on a video costs nothing: it is a number nobody checks twice. An out-of-date bank balance means an overdraft the bank did not agree to. An out-of-date seat map means two people with the same seat, and a very long conversation at the gate.

So real systems make the choice per question rather than once for the whole company. The same shop will happily show you a stale count of how many people are viewing this item, and will not sell the last one twice. Both live in the same building, and the interesting engineering is deciding which values sit on which side of that line.

The name this choice goes by

People call it the CAP theorem, from consistency, availability and partition tolerance. It is often quoted as "pick two of three", which is a poor way to say it, because a partition is not a thing you pick. Networks get cut whether you approve or not.

The experiment gives the precise choice: when the network is cut, a machine can answer without knowing the other side's state or refuse to answer. When the network is fine, you can have both, and a great deal of practical work goes into keeping the periods of being cut short and rare so that the choice hardly ever has to be made.

Lab 12 · Both rules, side by side
Try this firstPress Run both rules and read the six bars in pairs. Each pair is the same measurement under the two rules: how many customers got an answer, how many answers were wrong, and how many accepted writes were later discarded.
Notice: neither rule gets a clean sheet. Answering anyway serves everybody and pays in wrong answers and discarded writes; the majority rule pays in half the customers being turned away. No rule you could invent empties both columns, because the information needed to do better is on the other side of the cut. What a real design does is move the pain to where it hurts least. That is a decision about your shop, your customers and your lawyers, and it cannot be made by anybody who has not looked at these numbers.
Your bookshop has machines in two buildings and wants to keep taking orders even while the link between the buildings is cut. What must you accept as part of that decision?
Out-of-date answers and discarded writes. That is the price of the first column in Lab 12, and choosing it deliberately is a perfectly good decision for a bookshop. Speed does not help with the second option: while the cut is there, no amount of speed carries information across it. The third option describes the other choice, the one you did not make, and it has its own bill: every customer in the smaller building turned away for as long as the cut lasts.
Step 7

Overlapping on purpose

The majority rule from Step 6 is one setting of a more general idea, and the general idea is worth having, because it lets you buy exactly as much certainty as you want to pay for.

Keep the value on N machines. A write is not accepted until it has reached W of them. A read asks R of them and keeps the newest answer it gets back. A set of machines big enough to act on its own like that is called a quorum. So W is the size of a write quorum, and R the size of a read quorum. Now the question is: when is that read guaranteed to see the newest write? Nobody has to guess, because the widget below runs two hundred rounds and counts.

How a read knows which of several answers is newest

Every write is given a number that goes up, and each machine stores that number next to the value. So a read that asks three machines gets back three pairs, and the newest is simply the one with the biggest number. That is all the vector clock machinery from Step 4 collapsed into one counter. It is allowed here because the writes all go through the same counting.

The read does not need a majority to work out which answer is newest. It only needs to have asked at least one machine that saw the newest write. That is the entire subject of this step: not counting for the sake of counting, but making sure two sets of machines cannot avoid each other.

Lab 13 · Two hundred rounds, counted
Try this firstRead the card marked out of date as the widget starts, with N at 5 and both R and W at 2. Seventy of the two hundred reads missed the newest write. Now drag the R slider up one notch at a time and watch that number: 3 is still not enough, and at 4 it reaches zero. Then press Kill copy 1 and Kill copy 2.
Notice: the line that matters is R plus W against N. With five copies, a write reaching 2 and a read asking 2 can miss each other completely, because 2 and 2 fit inside 5 with room to spare. Even 2 and 3 can miss, because 2 and 3 is exactly 5. A write reaching 2 and a read asking 4 cannot, because 2 and 4 is 6 and there are only 5 machines to put them on, so at least one machine has to be in both sets. That one shared machine is what makes the promise. Killing copies shows the other half of the deal: the bigger you make R and W, the more machines have to be alive, and with R at 4 and two copies dead every single read is refused.
Why the two sets have to overlap, said with a shelf

Put five books on a shelf. Somebody puts a bookmark in two of them. Somebody else, who cannot see the bookmarks, opens four of the five. Can they miss both bookmarks? No: only one book is left unopened, and there are two bookmarks, so at least one bookmarked book was opened.

Two plus four is six, and six does not fit in five without something being in both groups. That is the whole proof, and it is why the rule needs R plus W to be strictly bigger than N. Two bookmarks and two books opened, out of four books, is exactly enough room for the two groups to keep apart. It is the case that catches almost everybody.

New to code: what a function is, and what "return" means

The next lab has you edit one line of a program. A function is a named piece of a program that takes some values in and hands one value back. function safe(n, r, w) { starts a function called safe that expects three numbers, and inside it those three numbers are called n, r and w. Anything after // on a line is a note to the reader and is ignored by the machine.

return is how the function hands its answer back and stops. return false; means "the answer is no". The two answers a yes-or-no question can have are written true and false. So return r + w > n; hands back true when r plus w is bigger than n, and false when it is not, and > is the ordinary greater-than sign. The lab checks your line by calling it with ten different sets of numbers and comparing the answers, so it is grading what your rule does rather than how you wrote it.

Lab 14 · Write the rule yourself
Try this firstPress Run before changing anything, so you can see that both printed lines say false. Then change return false; to your own rule, press Run again to read the two lines, and press Check my rule when they look right. Start over puts the original line back.
Notice: the ten cases include n=4, r=2, w=2, which is the one that catches people, and n=5, r=5, w=1, where the read asks everybody. If your rule answers those two correctly it is the real rule and not a near miss. When you have passed, Show me one that works shows the same idea written with a comment explaining it.
A value is kept on five machines. A write is accepted once it has reached 2 of them, and a read asks 3 of them. Is that read guaranteed to see the newest write?
No, and by one. The write went to machines 1 and 2; the read can ask 3, 4 and 5 and see nothing of it. R plus W has to be strictly bigger than N, and here it is exactly equal. The first option is the trap: the read being a majority is not the point, because the write was not. Both sets have to be big enough that they cannot avoid each other, and that is a statement about the two of them together, never about either one alone.
Step 8

The two generals

Everything so far has been about coping. This step is about something you cannot cope with, and it is worth meeting on purpose, because a great deal of engineering time has been spent trying to build it anyway.

Two commanders are camped on two hills with a town in the valley between them. They win only if they attack at the same time, and lose badly if either attacks alone. The only way to talk is to send a messenger through the valley, where the messenger may be caught. Neither commander can see the other. What do they agree on, and how many messengers does it take?

Why two generals and not two servers

They are two servers. The hills are two machines, the valley is a network that loses messages, and attacking together is any decision two machines have to take identically: both charge the card, or neither does. The story is from 1975 and it stuck because the picture is easier to hold in your head than the machines are.

Everything in the story maps onto something in Step 5. A messenger caught in the valley is a lost message. A commander waiting and hearing nothing is a machine that cannot tell a cut from a crash. The answer the story gives applies to the machines exactly, and it is not a comforting answer.

Lab 15 · Send messages until you are sure
Try this firstPress Send the next message four or five times and read the last line of the list each time. Then press Send five more and read that last line again. It says the same thing with different names in it.
Notice: every message moves the doubt to the other side and never removes it. The card that says either side certain stays on no. Press Send the next one, but lose it and compare what the sender sees with what it saw a moment ago: nothing on that side is different. The sender cannot tell a lost message from a delivered one whose reply has not come yet, and the last message sent always has that problem, whichever message is last.
Why a hundred confirmations do not help

Suppose somebody hands you a plan that always works and uses exactly six messages. Look at the sixth one. Whoever sent it never finds out whether it arrived, so that sender must behave the same way in both cases, so the plan works just as well if the sixth message is never sent at all. You now have a plan that uses five.

Run that argument again on the fifth, and the fourth, until you have a plan that uses no messages, where one commander attacks with no idea what the other will do. That plainly loses, so the six-message plan cannot have worked either. Nothing in the argument mentioned six, which is why the answer is not "use more messages".

Lab 16 · Take the last message away, and again
Try this firstPress Remove the last message six times, reading the line it adds each time. Each line is the same argument applied to one fewer message. Then set the slider to a bigger number and press Remove them all.
Notice: the number in the slider does not matter. Set it to 10 and the argument runs ten times instead of six and ends in the same place. That is the difference between a hard problem and an impossibility: a hard problem gets easier with more effort, and here more effort is more messages, and the argument does not care how many you send.
What this does not mean, because real shops do take payments

What is impossible is certainty: no plan makes both sides sure, in every possible run, using finitely many messages. What is entirely possible is being confident enough. Send the confirmation three times and the chance that all three are lost is small, and you can make it as small as you can afford.

The other move real systems make is to stop needing both sides to decide at the same instant. Write down what you intend to do first, agree afterwards, and make the action safe to repeat so that doing it twice by accident has the same effect as doing it once. Almost every payment system you have used works that way, and it works because it stopped asking for the thing that cannot be had.

A colleague proposes adding a hundred confirmation messages to the plan, on the grounds that losing all hundred is vanishingly unlikely. What is wrong with calling that a solution?
The last message always has the problem. The argument in Lab 16 never mentions how many messages there are, so it applies to a hundred exactly as it applies to six. That said, the colleague is not being foolish, and the first option is only wrong in one word. The chance gets small, it never gets to zero, and knowing the difference is what stops you promising a customer something you cannot deliver. Speed is not the objection: a hundred small messages is cheap.
Step 9

How far behind the copies are

Most systems do not let every machine take writes, because Step 5 showed what that costs. Instead one machine is the leader, the only one allowed to accept a write, and the others are followers that keep copies. The leader writes down each accepted value in order. That ordered list of values is called a log. One value in the log is an entry, and adding one to the end is called appending.

Every time the leader appends an entry, it sends a copy of that entry to each follower. The copy takes time to arrive. So there is always a moment when the leader has an entry that a follower does not, and a customer reading that follower is told the old value. How long that lasts is the replication lag.

Why followers exist at all if they are behind

Three reasons, and they are the reasons from Step 1 again. A follower can take over if the leader dies, which turns a disaster into a pause. A follower can answer reads, so a hundred readers do not all queue behind one machine. And a follower close to the customer answers quickly, which no amount of leader is going to fix for a customer on the other side of the world.

Being a little behind is a small price for those three, and often the value being read has not changed for hours anyway. The trouble is not lag by itself. It is lag that nobody accounted for in a place where a stale answer causes harm, and lag that grows without limit while nobody is watching.

Lab 17 · Watch the copies fall behind
Try this firstPress Write five, one per tick, then press Customer reads follower two. Five values are written and that customer is told nothing yet, because follower two is eight ticks away and not one copy has landed. Then press Run until quiet and read the same follower again.
Notice: follower two is set eight ticks away and falls further behind while writes keep coming, then catches up completely the moment they stop. Lag is not damage: nothing was lost and nothing needs repairing. What matters is that the customer reading a follower gets an old answer with nothing on it to say so. Drag the slider for follower two out to 12 and watch how far behind a single slow link can put a copy that is working perfectly.
What an acknowledgement is, and why waiting for one is a choice

When a follower has written an entry into its own copy, it sends a small message back to the leader saying so. That message is an acknowledgement, usually shortened to ack. It is the only way the leader ever learns that a copy landed.

So the leader has a decision on every write. Tell the customer it is done immediately, and be fast but hand out stale reads. Or wait for the acks first, and be slower but never have a copy behind. There is no third option, and the next lab races the two.

Reading your own writes, and why it feels like a bug

The version of lag that customers actually complain about is this one. You change your name, the leader accepts it, the page reloads, the reload happens to be answered by a follower that has not heard yet, and your old name comes back. Nothing is broken and no data was lost, and every person this happens to is certain the site lost their change.

The usual fix is small and worth knowing: for a short while after somebody writes, send that person's reads to the leader, or to a follower that has caught up past their write. It costs almost nothing, and it turns an alarming bug report into a promise you can write down. Step 11 asks you to check exactly this promise against a running system.

Lab 18 · Wait for the copies, or do not
Try this firstPress Race them again and read the four bars. The top two are how long the twenty customers waited, the bottom two are how many reads were out of date. Then drag Ticks to the further follower out to 12 and press Race them again: of the two waiting bars, watch which one grows and which does not move at all.
Notice: waiting for both copies hands out no out-of-date reads and takes far longer, and every extra tick of distance to the slowest follower goes straight into the time every customer waits. When you wait for everybody, your speed is the speed of your worst machine, and adding a machine can make the system slower. Waiting for a majority instead of for everybody is the compromise almost everybody picks, and it is Step 7 turned into a rule about writes.
A leader accepts a write and tells the customer it is done. The customer immediately reads from a follower eight ticks away and is shown the old value. What happened?
The copy is still travelling. Nothing was lost, and eight ticks later that follower holds the new value with no repair needed. The third option is a definition rather than a fact: you may define "done" as "every copy has it", and Lab 18 shows what that costs. What the customer is entitled to complain about is being shown their own change disappearing, which is why systems send a fresh writer's reads to the leader for a while.
Step 10

Dead, or just slow

If the leader dies, a follower has to take over, and quickly, because until it does nobody can write anything. So something has to notice the death. The usual arrangement is a heartbeat: the leader sends a short "I am here" message every few ticks, and a watcher declares it dead when the messages stop for longer than some agreed budget. That budget is called the timeout.

The watcher sees exactly one thing, and it is not death. It sees silence. Silence from a machine that has died and silence from a machine that is briefly overloaded are the same silence and the timeout is a guess about which one this is.

Why a healthy machine goes quiet for a while

All sorts of ordinary reasons. Its disk is busy, so the write it was doing took twenty times as long as usual. The machine it shares a building with started a backup and the network between them filled up. Its own memory needed tidying, and the tidying stopped everything else for a moment.

None of that means the machine is unwell in any way that matters, and all of it produces a gap in the heartbeats. This is why the timeout cannot simply be set low: a low timeout does not detect more deaths, it invents them.

Lab 19 · Pick a timeout, and pay for it
Try this firstPress Try 5 ticks, then Try 40 ticks, and compare the false alarms card with the real death spotted card. The watched machine is healthy until tick 700 and then really does die, and every number here comes from one nine hundred tick run.
Notice: the impatient setting buries a healthy machine several times, and each time it does, two machines are acting as leader at once and both are taking writes. The patient setting never makes that mistake and leaves a real death unnoticed for much longer, during which nobody can write anything at all. Drag the slider through the middle and watch the two bars trade places. There is no setting where both are zero.
What two leaders at once actually does

It is the split brain from Step 5, arrived at by a different route. Both leaders accept writes, neither knows about the other, and the two lists of entries diverge. When somebody notices, one of the two lists has to be thrown away and the customers whose writes were in it were told those writes had succeeded.

Real systems defend against this by making the old leader unable to do damage rather than by trying harder to detect it. Every leader carries a number that goes up each time a new one is chosen, and followers refuse anything carrying an old number. The demoted leader can shout as much as it likes and nobody is listening. The next course in this stream builds that machinery.

What a good timeout looks like in practice

Nobody good picks one number and leaves it. The machine watches how long the gaps between heartbeats usually are for this particular machine, and suspects it when the current silence is far outside its own usual range. A machine that is normally slow gets more rope than one that is normally instant, which is the rule you are about to write.

The other half of the answer is to stop treating suspicion as a verdict. Instead of "dead" or "alive", keep a number saying how suspicious things look, and let whatever depends on it decide how much suspicion is enough. A leader takeover can demand a lot of evidence, and a load balancer sending a request elsewhere can act on very little, and both read the same number.

Lab 20 · Write the detector yourself
Try this firstPress Run without changing anything and read the two printed lines. The starting rule says a machine is dead after 10 ticks of silence, which calls a 70 tick silence dead even for a machine that has taken 40 ticks before and been fine. Change that line so it uses worstSeen, then press Check my rule.
Notice: two of the ten cases sit exactly on the line, where the silence is exactly twice the worst ever seen. A rule that uses a fixed number can never get all ten, because the same silence has to mean different things on a machine that is usually instant and one that is usually slow. That is the whole idea: the evidence is not the length of the silence, it is how unusual this silence is for this machine.
A watcher currently waits 40 ticks of silence before declaring a machine dead. A colleague suggests 5 ticks, to spot failures faster. What does that change?
Faster, and wrong more often. Lab 19 counts both: the impatient setting notices the real death quickly and buries a healthy machine several times on the way. The first option treats a false alarm as free, and it is not free at all. The healthy machine is still running and still thinks it is the leader, so two machines are accepting writes at once, and one of those two sets of writes is going to be thrown away.
Step 11

What a system can promise

These failures do not make distributed systems unusable. They show why each design needs a precise contract. State whether reads may be stale, what a successful write guarantees, which failures are tolerated, and how long recovery may take. Then test those claims with the corresponding fault.

So this step has no new mechanism in it. The first lab is a cluster of five machines with every switch from the whole course on it and nothing to get right. The second gives you five promises and one running system, and asks you which of them that system can honestly make.

The names these five promises go by

"Every request gets an answer" is availability."A second read never shows something older than the first" is monotonic reads."You always see your own last write" is read your own writes."Once the network is mended, every copy ends up the same" is eventual consistency. And a write that is accepted and never quietly discarded is durability of the accepted write.

Learning the names is worth ten minutes because they are how the promise is written in a manual, and a manual that promises eventual consistency is telling you, in two words, that it does not promise the other four. Reading that sentence properly is most of what this course was for.

Lab 21 · The whole cluster, nothing to get right
Try this firstPress n4 to choose that machine, then Write a new value here, then Run until quiet. Everyone agrees. Now press Cut the network, write on n1 and on n5, run until quiet again, and press Read from here on a few different machines.
Notice: nothing here is marked and there is nothing to get right. Three things are worth causing on purpose. Drag Messages lost, per 100 up to 40 and see how many machines never hear a write. Crash a machine, write on another, then bring the first one back: it holds an old value and nobody corrects it. Heal the cut and watch nothing catch up until somebody writes again. Every one of those is a real failure that a real cluster has, and you can now name all of them.
Why "eventually the same" is worth having at all

It sounds like the weakest promise on the list, and it is. It is still the difference between a system that heals itself and one that needs a person. It says that if the machines can talk again and somebody keeps gossiping, the copies stop disagreeing without anybody being told who is up or what broke. A system that does not promise it has to be repaired by hand after every cut.

What it does not tell you is when, and it does not tell you what happens to conflicting writes on the way. Those are separate questions with separate answers and a system can promise this one and still throw away your write. Reading the promise for exactly what it says, and no more, is the habit worth keeping.

How a promise is tested, rather than argued about

The way Lab 22 does it. Write down what the customers did and what they were told, in order, then check the list of promises against that record. Nobody's opinion is involved: either a customer was shown a value older than one they had already seen, or no customer was.

This is a real technique with real tools behind it. People test databases by running a pile of clients against a cluster while cutting its network at random, recording every answer, and then checking whether any promise in the manual was broken by that record. The number of well-known databases caught breaking their own manuals this way is larger than you would hope.

Lab 22 · Which promises does this system keep
Try this firstLeave the rule on Answer anyway, press Run the customers, and read the log of what the three customers were told. Then tick the promises you think this setup keeps and press Check my answer. It names the first one you have wrong and quotes the evidence from the run.
Notice: when you have all five right under one rule, switch to Only answer with a majority and work the other one out from scratch. A different set of promises survives, and neither set is all five. That list, honestly filled in, is what a system is allowed to claim, and being able to produce it for something you built is the difference between engineering and hoping.
A supplier tells you their database always answers every request, always shows the newest value, and keeps working through a network cut. What should you conclude?
At least one of the three is not true. Lab 12 counted this: while a cut is there, a machine either answers without knowing or refuses, and no mechanism removes that choice. Vector clocks do not help, because they are a way of describing what happened, not a way of moving information across a cut. The productive next question is which one bends, and under what conditions, because a supplier who can answer that precisely is one who has thought about it.
What you can do now

Take any claim about a group of machines and work out which of it survives a cut, a crash and a slow machine. That is a skill with a market rate, and you now have it.

What you built up to

  • Cause a lost update, and say exactly why the gap between a read and a write is where it comes from.
  • Explain why two clocks disagree, and why "keep the later write" throws away the later write.
  • Order events without a clock, using only what machines could have known, and say when no order exists.
  • Read a vector stamp and tell "before" from "concurrent".
  • Recognise split brain, and pick a merge rule knowing what it destroys.
  • Choose between answering and being right during a cut, with the counts in front of you.
  • Set N, R and W so a read cannot miss the newest write, and know why the rule is strict.
  • Explain why no number of messages makes two machines certain, without hand-waving.
  • Tell replication lag from data loss, and price the cost of waiting for every copy.
  • Pick a failure timeout knowing which two things you are trading.
  • Audit a system against a written list of promises, using a record of what customers were told.

Where this goes

  • Raft and Consensus. This course was about what goes wrong. That one is the machinery that copes: elect one leader properly, replicate a log so no accepted write is ever lost, then kill the leader mid-write and watch the rest heal without a person.
  • Inside a Database. One machine, taken seriously: how a write survives the power being pulled out halfway through, which is the promise every copy in this course was quietly assuming.
  • Reliable Data Transfer. If you came here without it, the layer underneath: making a message arrive at all, across a network that loses, delays, duplicates and reorders.
Step 12 · Advanced path

Read a history against a model

A consistency model is a set of allowed histories. A history records when each operation started, when it finished, its input and its result. Linearizability requires every completed operation to appear at one instant between its call and return, while preserving real-time order. Sequential consistency preserves each client's program order but may choose a different order for operations that did not overlap in real time.

Causal consistency preserves cause before effect and may leave concurrent operations unordered. Eventual consistency only promises convergence after updates stop and all updates arrive. “Strong” and “eventual” are not complete specifications; name the operations, model, failure assumptions and any bounded-staleness limit.

Lab 23 · Classify one operation history
Try this firstMove a read before and after a completed write. Check the same history against linearizable, sequential and causal rules.
Use call and return intervals, not machine wall-clock timestamps. A valid explanation must produce one legal ordering or identify the first impossible observation.
One object or a transaction?

Linearizability is normally stated per object. Strict serializability combines serializable multi-object transactions with real-time order. Do not claim the second after testing only the first.

Read the original linearizability paper and the Jepsen model map.

A write finishes before a later read starts, but that read returns the old value. Which property is violated?
Real-time order matters to linearizability.
Step 13

Keep one user's session sane

A system may choose weaker global consistency and still protect one user's path. Read your writes keeps a user from saving a change and immediately seeing an older copy. Monotonic reads prevent a session from moving backward, monotonic writes preserve its update order, and writes-follow-reads keep an update after the version it used.

Sticky routing is one implementation, not the promise itself. A session token carrying a version can move with the client and make another replica wait or forward the read. Decide what happens when the required version is unavailable: wait, fail, or explicitly return weaker data.

Lab 24 · Move a user between replicas
Try this firstWrite on replica A, move the next read to lagging replica B, then add a session version token.
Test session expiry, two devices, logout and a failed preferred replica. “Usually sticky” is not a guarantee.
Why a session token is evidence

The token names the minimum version this client has already observed. A replica can compare that requirement with its local version instead of guessing from elapsed time.

A user saves profile version 8 and replica B has version 7. What can B do while preserving read-your-writes?
The promise constrains the answer.
Step 14

Merge by construction

A conflict-free replicated data type gives concurrent updates a merge rule that is associative, commutative and idempotent, so delivery order and duplicates do not change the converged answer. A grow-only counter keeps one component per replica and merges each component by maximum. Its value is the sum.

The data type decides semantics. A grow-only set cannot remove. An observed-remove set tracks which additions a removal observed, so a concurrent unseen add can survive. CRDT convergence does not automatically preserve a bank balance, uniqueness constraint or inventory floor; application invariants may still require coordination.

Lab 25 · Merge counters and an observed-remove set
Try this firstIncrement both offline replicas, deliver states twice and in opposite orders. Then remove a tag concurrently with a new add.
Check convergence and meaning separately. Two replicas can converge perfectly on an answer the business rule forbids.
State-based and operation-based forms

State-based replicas merge whole or delta states with a join. Operation-based replicas deliver operations under stated ordering and delivery assumptions. The proof obligations differ.

See the CRDT overview.

A replicated counter converges after offline updates. Does that prove an account never went negative?
A merge rule cannot invent coordination for a cross-replica limit.
Step 15

Repair replicas in the background

Read repair fixes replicas encountered by a read. Anti-entropy compares replicas in the background, often using hashes over ranges so equal regions are skipped. Hinted handoff temporarily stores an update for an unavailable owner. None of these makes an acknowledged write durable unless the acknowledgement rule already placed enough copies.

Tombstones represent deletion long enough for every replica to learn it. Remove them too early and an old value can return during repair. Keep them forever and metadata grows without bound. Garbage collection therefore needs evidence about replica membership, repair completion and the maximum time an old replica may rejoin.

Lab 26 · Compare trees and stop deleted data returning
Try this firstCorrupt one range, compare hashes, repair only the differing branch, then bring back a replica that missed a deletion.
Record bytes compared, bytes transferred, versions repaired and the oldest tombstone still required. A green “repair finished” light needs those counts behind it.
Why repair and consistency are separate

Repair changes how long replicas disagree. The read and write rules decide which disagreement a client may observe before repair finishes.

Why can deleting a tombstone too early resurrect old data?
The deletion itself is replicated state.
Step 16

Coordinate a multi-service change

Two-phase commit asks participants to prepare durably, then tells all of them to commit or abort. It can make the decision atomic, but a prepared participant may block while the coordinator is unavailable. Consensus can replicate the coordinator decision; it does not remove every application and availability trade-off.

A saga commits local transactions and runs compensating actions after a later failure. Compensation is a new business action, not time travel. The transactional outbox stores a state change and an event in one local transaction; a relay may publish the event more than once, so consumers use stable IDs and idempotent effects. “Exactly once” must name the boundary being measured.

Lab 27 · Crash between database change and event publish
Try this firstCrash the direct publisher in each gap. Then use an outbox and duplicate one relay delivery.
Test every crash point, including after an external effect but before recording completion. Store the idempotency decision durably with the effect it protects.
Why compensation can fail

The world may have changed since the original action. A refund can fail, a seat may have been resold, and an email cannot be unsent. Design retries, escalation and a visible incomplete state.

An outbox relay publishes the same event twice. What makes the consumer effect safe?
Delivery can repeat. Make the effect recognise that repetition.
Step 17

Use time with an error bound

Step 2 showed that bare wall clocks lie. A clock service can instead return an interval: the true time is no earlier than this bound and no later than that one. If a transaction must be ordered after everything that definitely finished before it, the system can wait until the uncertainty interval has passed its commit timestamp.

Hybrid logical clocks combine a physical-time estimate with a logical counter. They remain close to wall time while preserving causal order when clocks move backward or messages arrive from the future. Neither method excuses an unmeasured clock error. Monitor uncertainty, reject implausible jumps and specify behaviour when the bound grows.

Lab 28 · Wait out clock uncertainty
Try this firstIncrease the clock error bound and watch commit wait grow. Then move a physical clock backward and compare a raw timestamp with a hybrid logical timestamp.
The uncertainty bound is a measured input and an operational dependency. Alert when it grows before it silently becomes latency or loss of the promised ordering.
What TrueTime contributes

Google Spanner uses a bounded time interval plus waiting and replicated transaction machinery to provide external consistency. The clock interval is one component, not a replacement for consensus or concurrency control.

See Google Cloud's explanation of TrueTime and external consistency.

The uncertainty interval widens. What changes?
The error bound is part of the contract.
Step 18 · 2026 practice

Try to falsify the promise

A happy-path load test does not validate consistency. Generate overlapping operations from independent clients, record invocation and completion, inject process pauses, crashes, partitions and clock changes, then ask a checker whether any legal history explains the results. Preserve incomplete operations rather than quietly deleting them.

Random testing finds some schedules. Deterministic simulation and model checking explore chosen state transitions repeatedly and shrink a failure to a small counterexample. AI tools can propose fault schedules or summarise a long trace, but the model, raw history and executable checker remain the evidence.

Lab 29 · Find the smallest impossible history
Try this firstSelect a claimed model, inject a partition and run the history checker. Remove operations until the violation would disappear.
A passing finite test is evidence, not proof. State the operations, model, generator, faults, run count, checker version and uncovered assumptions.
Why client observations matter

Internal logs can agree while clients receive an impossible result. Build the checked history from request and response boundaries, then use internal traces to explain a violation.

A checker finds a four-operation history with no legal linearization. What is the useful next artifact?
A small reproducible counterexample is actionable evidence.

Continue the distributed systems path