The Interleaving Explorer
Two agents. One database row. Six ways their operations can interleave, and one of them silently destroys committed work. This page lets you run every one of them.
My AI agents coordinate through a single SQLite file. One of the things
they share is a set of context sections: named rows of markdown that any agent
can read and update. An update is a full replace, so the row carries an
integer version, and a well-behaved writer does a compare-and-swap:
read the row, note its version, and submit the new content
conditioned on that version being unchanged.
The catch is the writer that doesn't pass the version. A blind write. For a long time the system accepted those for compatibility, in a configuration called warn mode. The simulator below is a faithful small model of the real test that measured what warn mode costs, and it is the reason the production default is now enforce.
Writer A ยท blind write
Writer B ยท CAS write
context_sections ยท one row
What you just ran
The schedule is the whole game. Each writer's own program order is
fixed (it must read before it writes), but which writer goes next at each step
is picked by a seeded random number generator, exactly like the deterministic
simulator in the real test suite. Same seed, same schedule, same outcome,
every time. Step through seed 6 in warn mode: both writers read version 1, writer B's
careful CAS write lands and commits, and then writer A's blind write replaces
it. Both writers were told ok: true. B's committed work is gone,
and B will never ask about it again, because as far as B knows, it succeeded.
That is a lost update.
Now flip the toggle to enforce and run the identical schedule. The blind write is rejected. Nothing is lost. The interesting part is what the rejection leaves behind.
The receipt
This system's design rule is that nothing loses quietly. Every refused write, and every accepted blind overwrite in warn mode, files a durable conflict receipt in the same transaction as the decision itself. The warn-mode receipt even records a hash of the content it displaced, so there is a forensic trail pointing at exactly whose work was destroyed. Receipts are shown in violet above. Cause a conflict and read one.
All six interleavings
With two writers and two operations each, there are only six possible schedules. Small enough to enumerate. Click one to load it, then flip the mode toggle and watch the same schedule land differently.
Notice the structure. In warn mode the danger is concentrated in the two schedules where both writers read the same version and the CAS writer commits first. In two other schedules warn mode survives by luck: the blind write happens to land first, so the CAS writer's version check fails and it gets an honest rejection instead. Luck is doing the work a guarantee should do. In enforce mode all six schedules are safe, because the blind write is refused no matter where it lands.
The sweep that flipped a default
One seed is an anecdote. The real test suite runs a sweep of seeds and asks how often the lost update is actually reachable. Here are thirty seeds through this model, in warn mode:
In the real system's sweep, seventeen of thirty seeds reached the lost update. That number is what moved the default from warn to enforce: not a hunch about race conditions, but a measured statement that under concurrent writers, warn mode destroys committed work more often than not. The evidence seed is pinned in the repository and replays forever, so the bug that motivated the change can always be reproduced bit-for-bit.
Honest small print
This page schedules writers at read/write granularity. The real simulator schedules at every SQL statement, injects crashes and busy errors, and drives the actual production tool code against the actual schema on a simulated clock. The lost-update shape you explored here is the same one it found. And you do not need a distributed system for any of this to matter: this is five agents and one SQLite file on one laptop, and the interleaving still bit.
Self-contained page, no dependencies. View source: the simulation is ~120 lines of plain JavaScript and it is the tutorial. Part of a series on bridge-db, a SQLite-backed coordination server for a small fleet of AI agents.