Determinism as a Correctness Contract
Why Anvil treats bit-for-bit reproducibility as a testable property — and how an event-sourced core makes a backtest and a production run literally the same program.
By MorphIQ Labs Research Notes
Most trading systems are tested the way most software is tested: feed an input, assert an output, hope the parts you did not assert on behaved. That works until the part you did not assert on is wall-clock time, or iteration order over a hash map, or a thread that won the race yesterday and lost it today. In a trading system those non-determinisms are not cosmetic. They are the difference between a backtest you can trust and one you cannot.
Anvil takes a stricter line. Determinism is not an emergent nicety — it is a contract, declared at the type level and checked on every commit.
The contract
Anvil's core is a state machine. Given a strategy state and an input event , the transition function produces the next state and a list of emitted commands:
The contract is that is a pure function. No clock reads, no RNG without a seeded source, no filesystem, no allocation-order-dependent iteration. Given the same , it must produce the same — on any machine, in any year, under any compiler optimization level.
That single constraint buys an enormous amount. If is pure, then the entire run is a fold over the event log:
and the final state is a deterministic function of the seed state and the event sequence alone. Replay is not a feature bolted on afterwards. It is the definition of the system.
Why event sourcing falls out for free
Because state is reconstructed by folding events, the event log is the database. There is no separate mutable store to drift out of sync. This has a consequence that matters more than it first appears:
The class of bug where a strategy behaves differently in simulation than in production simply cannot be expressed. The two are the same object code reading two sources of the same event type.
Making it testable
A contract that is not checked is a comment. Anvil enforces determinism three ways.
Replay equality
Every recorded session can be replayed. The check is exact:
State is content-addressed — we hash the serialized state — so the assertion is a single 32-byte comparison, not a structural diff. A mismatch fails the build.
Cross-run divergence
The same log is folded twice in the same process and the intermediate states are compared step by step. The first index where
is reported directly. Because the two runs share a process, a divergence here points squarely at hidden global state or iteration-order dependence, not at a serialization round-trip.
Property-based fuzzing
A generator produces random-but-valid event sequences. For each, Anvil asserts
that folding the sequence, serializing, deserializing, and folding again yields
identical state. This catches the subtle cases — a HashMap iteration leaking
into a command's ordering, a f64 sum whose result depends on accumulation
order.
| Check | Catches | Cost |
|---|---|---|
| Replay equality | Drift between record and replay paths | O(events) |
| Cross-run | Global state, iteration-order dependence | O(events) |
| Property fuzzing | Serialization + accumulation-order bugs | O(cases) |
The cost, honestly
Determinism is not free. You give up the easy reach for SystemTime::now() —
time must arrive as an event. You give up unordered collections in any code
path that influences output. Floating-point reductions must fix an accumulation
order, which occasionally costs a few percent of throughput versus a
vectorized free-for-all.
We think the trade is obvious. A few percent of throughput is cheap. A backtest result you cannot reproduce six months later — after the bug it would have caught has already traded — is not.
Where this goes next
The current contract is enforced per-strategy. The next step is enforcing it across strategies sharing an event bus — proving that the interleaving of two strategies' command streams is itself a deterministic function of the merged log. That turns multi-strategy portfolios into the same replayable object the single strategy already is. More on that when the proof obligations are nailed down.
More from Anvil
July 6, 2026 · 2 min
Deterministic Replay for Trading Systems
The most expensive production bugs in trading systems are often not the ones that crash. They are the ones that cannot be reproduced. A signal changed, an order decision differed, a timeout fired in a different order,…