What a domain model implements (spec §7). The engine handles all Time Warp mechanics — rollback, anti-messages, GVT, fossil collection.
The purity contract (hard requirement, §7/§8)
handle_event/3 MUST be pure: no side effects, no wall-clock reads, no
randomness outside a seeded PRNG carried inside model_state. A model that
violates this produces non-reproducible, silently-wrong results.
Two engine features defend the contract (Mitigation 3):
TimeWarp.Rand— a seeded PRNG carried inmodel_state, so rollback restores the PRNG position for free with the state snapshot.- The Divergence Detector (
check_purity: true) — exploits the fact that rollback re-executes events, and asserts a re-execution emits the identical events it did the first time. Impurity surfaces immediately instead of corrupting results.
PRNG discipline and lazy cancellation (§5.5)
Lazy cancellation collapses the rollback storm by suppressing an anti-message
when re-execution re-emits a byte-identical event. Whether it pays is a
property of the model, and the deciding factor is precise: does the event
that a straggler interleaves consume a PRNG draw? If it does, every
subsequently re-executed event draws different numbers, so its emission changes
in timestamp/payload and the match fails — even when the logical decision is
identical (same routing choice, different drawn travel time is enough to kill
it). A purely random model (see TimeWarp.Examples.PHOLD) therefore gets a zero
match rate and lazy cannot help it.
This makes PRNG placement a design lever: keep bookkeeping events (occupancy
updates, state transitions with no stochastic duration) PRNG-free, and
concentrate draws in as few event types as possible. Stragglers landing on
PRNG-free events re-emit identically and lazy pays; the lazy_matched stat
measures whether that discipline held.
Summary
Types
An event to schedule: to target, firing at virtual time at, carrying payload.
Callbacks
Called ONLY by fossil collection, once GVT has passed this event's timestamp. The single sanctioned place for externally-visible effects. Optional.
Process one event. MUST be pure. Returns the new model state and any events to
schedule at strictly future virtual times (at > at_of_current_event);
target may be the LP itself.
Build the initial model state for one LP from its config args.
Types
An event to schedule: to target, firing at virtual time at, carrying payload.
@type lp_id() :: TimeWarp.Event.lp_id()
@type vtime() :: TimeWarp.Event.vtime()
Callbacks
@callback commit(event :: TimeWarp.Event.t(), model_state :: term()) :: :ok
Called ONLY by fossil collection, once GVT has passed this event's timestamp. The single sanctioned place for externally-visible effects. Optional.
@callback handle_event(payload :: term(), at :: vtime(), model_state :: term()) :: {new_model_state :: term(), [emission()]}
Process one event. MUST be pure. Returns the new model state and any events to
schedule at strictly future virtual times (at > at_of_current_event);
target may be the LP itself.
Build the initial model state for one LP from its config args.