A test runner that owns every source of nondeterminism — the microtask queue, timers, Date.now(), sockets — so a whole run becomes a pure function of one 64-bit seed.
And you never reproduce it. The failure depends on which of two tasks happened to wake first, and that ordering is decided by a clock you do not control. So the test gets marked flaky, retried, and eventually deleted — along with the bug it was catching.
V8's microtask queue is already deterministic. Two runs feeding the same values into the same awaits resolve in the same order every time, so that is not where flakiness comes from. It comes from the edges — when a timer fires, when a socket completes, what the clock said. So nondet takes the edges and leaves V8 alone, which means no compiler plugin and no rewriting of your awaits.
When several tasks are eligible at once, the seed decides who wakes first. That is the interleaving fuzzer.
The clock jumps to the earliest pending timer once nothing can run. An eight-hour retry backoff finishes in about three milliseconds.
Nothing eligible, no timers, tasks still alive — you get every task and what it is blocked on, instead of a hung CI job.
Every decision draws from one integer stream, so generic passes reduce schedules, network faults and generated data at once.
Latency, drops, duplicates and partitions, all seeded. A dropped packet is as reproducible as an off-by-one.
setTimeout, Date.now and Math.random are virtualised, so third-party code runs on virtual time unchanged.
From examples/race-condition.ts, which CI runs on every push:
Worker threads and real I/O are out of scope — anything that leaves the process is nondeterminism it cannot own. And it does not prove correctness: it explores interleavings you would never hit by hand, but a seed space is not a proof. This is fuzzing with a very good reproduction story.
The README goes deeper, and the tests are the honest documentation. Happy to walk through the trade-offs.