Skip to main content
Every world has a single clock that starts at t0. Time-consuming processes (a run settling, a transcription completing) have named durations, and events fire when “now” crosses their due time.

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

When you advance time explicitly, every due event fires in deterministic due-time order, each to completion, before the call returns. A 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 to 0. 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: