Two modes
Wall-clock ticking
“Now” advances with real time, like a staging environment — events fire on their own as time
passes. The right default for a long-lived raw sandbox. (Ships first.)
Freeze-in-place
“Now” moves only when you advance it. Every time-derived field is reproducible by
construction, and due timers drain inside your
advance() call. The eventual default for
CI. (Roadmap.)Advancing time
POST finishes its own state change first, then its cascade
fires through the ordered queue. There’s no “halfway” state you can accidentally observe.
Making CI deterministic today: collapse the durations
Until freeze-in-place ships, you get deterministic sequencing by setting named durations to0.
The timer queue then drains in order on the triggering call — no waiting on real time, no flake:
Durations→0 gives you deterministic ordering and “did the cascade fire?” assertions today.
Absolute timestamps still track wall-clock until freeze lands — so if you need to assert an exact
created_at, that’s what freeze mode (and a pinned t0) are for. See
Deterministic CI.Reset rewinds to t0
reset() empties state and rewinds the clock to t0. Because t0 is a fixed constant by default,
every fresh world is byte-identical. Override it per world to test date boundaries: