workshop private

← all creations

Precede

viz · created 2026-09-23

One message history read by three clocks at once, with the question they disagree about spelled out underneath — two clients write the same key a millisecond apart, the wall clock keeps one write, the Lamport clock keeps the other, and only the vector says the thing that is actually true, which is that it cannot choose.

algorithmsinterview-preparchitecturecanvas

Three processes on three lanes, events as dots, messages as arrows between them. Every event gets stamped by all three clocks at once, and the toggle decides which stamp you see: a wall-clock timestamp, a Lamport scalar, or the full vector.

The rules are the textbook ones, and they fit in four lines:

local / send : V[self] += 1
receive      : V[self] += 1, then V = componentwise max(V, message)

a → b  iff  V(a) ≤ V(b) componentwise and V(a) ≠ V(b)

That last line is an iff, in both directions, and everything here is built to make the second direction matter. A Lamport scalar keeps only the forward half — a → b still implies L(a) < L(b) — so it can order every pair and prove none of them. Switch to it on the crosstalk history and the readout says the quiet part: an opinion about all 78 pairs, and proof for 42.

The question at the bottom

Every history writes to one key, and the strip in the corner answers “what is cart?” three times, once per clock. It is the same question a replica answers on every read, and the three answers are not the same answer:

The struck-through value in each row is a write that existed, was acknowledged, and is gone. Last-write-wins is not a tie-break; it is a silent delete that looks like success.

What the controls are for

Hover any event and the picture splits into its light cone — what precedes it in teal, what follows in violet, and in amber the events that are neither, which is the set this process cannot know about and cannot be known by. Click two events for the verdict. When they are ordered, the witness is drawn: the actual chain of program steps and messages carrying one to the other, in white, because “before” is a path and not a number comparison. When they are concurrent, the two coordinates that prove it get named — A is ahead on P0, B is ahead on P1 — along with the orders the other two clocks invent anyway.

Wall mode is the one you should drag. Each lane can be pulled sideways, which skews that process’s clock and changes nothing else about the history. Pull it far enough and messages start arriving before they were sent, drawn in red and labelled as such, while the timestamps stay perfectly, uselessly ordered — and the cart winner flips, because on the default history the two writes are one millisecond apart and the survivor is decided by whose clock runs fast.

The readout carries the bill: 8 bytes per message for a scalar, 8×n for a vector. That linear term is the entire argument against vector clocks in production, and the reason real systems prune entries, cap them per replica, or move to dotted version vectors. The handoff history is the other side of it — a token relayed around the ring, zero concurrent pairs out of 120, all three clocks in agreement, and 40 bytes a message buying you nothing at all.

Reuse

src/precede.js is framework-free and has no canvas in it. simulate(scn) runs a history and stamps every event; relation(a, b), causalPath, cone and census ask questions of the result; registerVerdicts is the last-write-wins-versus-siblings comparison on its own. The four histories in SCENARIOS are generators of n, so any of them can be rebuilt at 3 to 5 processes.

node scripts/screenshot-demo.mjs [out] [--shot=wall] re-shoots the thumbnail and the wall-clock frame in media/.