Architecture
// ARCHITECTURE
Three execution layers — one per bug.
Layer 1 browser-native WebAssembly, Layer 2 containers, Layer 3 record-replay. The recipe declares which layer it runs on — you don't pick. The matrix below scans the trade-offs at a glance; the deep-dive sections follow.
In the browser, instantly.
Docker / microVM, for fidelity.
Trace bundled, replay anywhere.
rr replay.~4 GB, real fork/exec, data races, building the compiler itself.wasm32-wasip1 / sqlite-wasm.Dockerfile + ghcr.io/aletheia-works/vivarium-<slug> + Codespaces badge.rr trace baked in.// 01 · LAYER 1
WebAssembly, in the page.
Reproductions run directly inside your browser tab. No account, no install — open the page and it starts. Phases 0–2 built up Python / Ruby / PHP / Rust recipes, e.g. cpython#137205 and pandas#56679; this layer is the most "browser-only" surface Vivarium ships.
Bugs this layer fits
- Algorithmic bugs (sorting, parsing, text processing).
- Data-processing regressions (pandas / polars / numpy shape bugs).
- Database behavioural bugs (SQLite query anomalies, JSON path edge cases).
- Library-internal logic where the repro doesn't touch the filesystem, network, or process model.
Startup time
- Cold load (no cache): 1–10 seconds. Dominated by runtime download (Pyodide ≈ 10 MB compressed) and instantiation.
- Warm load (cached): under a second.
- Per-run execution: milliseconds to a few seconds.
What this layer can't reach
- Memory. A browser tab degrades past ~1 GB peak; ~4 GB is the practical ceiling. Production-scale data goes to Layer 2.
- System calls. No real
fork/execor real sockets. The WASI shim covers common cases, not all. - Concurrency bugs. Single-threaded by default — data races and heisenbugs go to Layer 3.
- Compiler builds. A Rust bug reproduces fine in-browser, but building the Rust compiler itself is Layer 2.
Runtimes and live examples
- Python: Pyodide — live: cpython#137205 and pandas#56679
- Rust:
wasm32-wasip1— live: regex#779 - Ruby: Ruby.wasm — live: ruby#21709
- PHP: php-wasm — live: php#12167
- SQLite: sqlite-wasm (via Pyodide) — recipes that hit the sqlite WASM build via Pyodide live under the Python listing above.
// 02 · LAYER 2
Docker / microVM, on your own machine.
For bugs that need a real filesystem, real processes, and real networking. Vivarium does not host execution; recipes are distributed as a catalogue that runs on your own Docker (or Codespaces).
Bugs this layer fits
- Whole-project reproductions — bugs that require dependency resolution against real package indexes.
- Syscall-dependent bugs — real
fork, real sockets, real file locks, real signals. - Toolchain-specific bugs — quirks of a specific GCC, glibc, or kernel ABI.
- Multi-process bugs where the interaction between processes is the bug.
How to use it
Each recipe page ships a pinned Dockerfile, a copy-pasteable docker run … command, and a link to a published image at ghcr.io/aletheia-works/vivarium-<slug>. The page also shows the latest CI verdict snapshot — your own docker run becomes the live confirmation. Where applicable an "Open in Codespaces" badge is provided.
What this layer can't reach
- No in-page execution. The repro runs locally or in Codespaces, not on the gallery page.
- Docker (or Codespaces) required. Without either, you can still browse recipes and verdict snapshots.
- Concurrency itself. Layer 2 runs on real threads, but reproducing heisenbugs reliably is Layer 3 territory.
// 03 · LAYER 3
Trace bundled, replay anywhere.
For heisenbugs — bugs that don't reliably reproduce on a fresh re-run. Vivarium pre-records the trace, bakes it into a GHCR image, and you only have to replay.
Bugs this layer fits
- Data races, memory ordering bugs, use-after-frees that resist a fresh re-run.
- Long-replay scenarios: rewind hours of captured execution in minutes.
- Distributed-system bugs that depend on a specific message interleaving.
- Post-mortem forensic analysis — stepping backwards through a recorded trace.
How to use it
Each Layer 3 recipe ships as a self-contained GHCR image with the trace baked in. rr replay doesn't need a PMU, so replay runs on commodity Linux hosts — both for visitors and for CI. The recording itself does need a PMU-equipped Linux/x86_64 host, but that is done offline by Vivarium when the recipe is added — not something you have to repeat.
What this layer can't reach
- Environment. Visitors need Linux/x86_64. ARM Mac or Windows users fall back to Codespaces or WSL2 + Docker.
- Coverage shape.
rrtargets single-process Linux x86_64; distributed-simulation tools target distributed systems — neither covers the other's territory. - Trace size. Tens of MB to single-digit GB per recipe.
Live examples
- pthread lost-update — a real pthread race captured deterministically; visitors only
rr replay. - New Layer 3 recipes need offline PMU recording, so the cadence is slower than L1 / L2.
Which layer a recipe runs on is declared by the recipe itself. You don't pick — opening the page runs it on the right layer automatically.