All notable changes to this project are documented in this file.
The format follows Keep a Changelog, and this project adheres to Semantic Versioning.
0.2.0 — 2026-08-20
Added
TimeWarp.Model.commit/2may return{:ok, new_model_state}in addition to:ok. Fossil collection threads the returned state back into the logical process, which gives a model the only point at which it can release state that a commit has made unreachable.handle_event/3never observes GVT and so cannot determine what is safe to drop; a model that accumulates per-event state and always returns:okgrows for the length of the run. Events are committed in ascending virtual-time order and the state is threaded through that fold, so commit order is now observable in the resulting state.Pruning is bounded by GVT lag rather than immediate: a rollback restores a state snapshot from history, and snapshots at or above GVT were taken before the prune, so they still reference the released terms until the same fossil-collection pass drops them.
Returning
:okremains valid, so existing models are unaffected.:lp_call_timeout— timeout in milliseconds for the coordinator's own calls into logical processes, default5_000. These execute inside the coordinator process and a logical process may be remote, so exceeding the timeout fails the run rather than an individual call.:quiescence_timeout_ms— ceiling on the freeze-confirm quiescence poll, default1_000. The workable value scales with link latency, so a distributed run may require more than a local one.TimeWarp.stop_run/1cancels a run, tearing down its logical processes and returning the engine to idle. The function existed on the coordinator and the public documentation directed callers into that internal module; it is now part of the public surface.It waits without a timeout. Teardown reaches into every placement node's supervisor, which can exceed the default five-second call timeout on a multi-node run; a caller that timed out would exit while the teardown continued and completed, reporting a crash from a call that had in fact worked.
Changed
TimeWarp.start_run/1returns{:error, :run_active}when a run is already in progress, leaving the active run untouched.TimeWarp.Examples.KeyedWindowandTimeWarp.Examples.BufferedWindowrelease each window's accumulator and buffer on commit. Both previously retained every window for the length of the run.
Fixed
start_run/1against an active run matched no clause and raisedFunctionClauseErrorinside the coordinator. This terminated the coordinator and every caller awaiting the active run, so the run already in progress was lost and the failure surfaced as a crash in the second.Three coordinator calls into logical processes — the per-process dump behind
report/1, the GVT query, and the freeze-confirm poll — used the default five-second call timeout while executing inside the coordinator process. A remote or slow logical process therefore terminated the coordinator instead of failing a single call. These now honour:lp_call_timeout.The test suite aborted before ExUnit started when distribution was unavailable, reporting zero tests run. Tests requiring distribution are tagged
:distributedand excluded whenNode.start/2fails.
Documentation
:placement,:gvt_modeand:net_delayare documented in theTimeWarpmoduledoc. All three were read by the coordinator and absent from the option list.:net_delayis marked test-only.The one-run-per-BEAM constraint is stated explicitly. The coordinator is a global singleton, and
start_run/1tears down every logical process on the placement nodes without scoping the teardown to a single run, so concurrent runs destroy one another.:time_windowdocuments that it is the only bound on retained state. Fossil collection reclaims only below GVT, so a workload holding GVT near the floor grows retained state until the VM exhausts memory, and:noneplaces no limit on how far a logical process runs ahead.The
TimeWarpmoduledoc example referenced a model that does not exist and would not compile, and settime_window: :none— the value documented immediately below it as unbounded. It now usesTimeWarp.Examples.PHOLDwith a binding window.TimeWarp.Coordinator's moduledoc described the superseded stop-the-world computation as current and Mattern's algorithm as future work, though:gvt_modedefaults to:mattern. It now leads with Mattern's algorithm as the computation in use, and presents the stop-the-world variant as the test oracle and termination confirmation it actually is.References to an unpublished specification (
§N,Mitigation N,Phase-N) are resolved to their meaning throughout the published modules.
0.1.0 — 2026-08-04
Initial release. Jefferson's Time Warp with Mattern's distributed Global Virtual Time, mapped onto BEAM primitives: speculative execution with automatic rollback, anti-message annihilation, fossil collection on GVT advance, an optional deadlock-free time window, lazy cancellation, a purity divergence detector, and static multi-node LP placement.