Transactions and time
Every update in Continuum happens inside a transaction — one atomic moment of logical time. e.fire(x) opens a moment; everything that follows from x settles inside it; the moment closes; only then do effects (listen, DOM patches) observe the result.
Glitch-freedom
If one event feeds two branches that later reconverge (a "diamond"), the join recomputes once per moment, seeing both branches updated:
const doubled = count.map((n) => n * 2);
const squared = count.map((n) => n * n);
const sum = combine(doubled, squared, (d, s) => d + s);
// count: 2 → 3 makes sum go 8 → 15 in one step. "6 + 4" never exists.Internally nodes are ranked by graph depth and processed in rank order, so a node never fires before its inputs settle. You don't manage this — it is what "transaction" means here.
Simultaneity is real
Two occurrences in the same moment are actually simultaneous, and the API forces you to say what that means:
Stream.merge(ea, eb, combine)— simultaneous occurrences are coalesced withcombine, not ordered arbitrarily;atsees States as of the start of the moment.
The hold delay
hold/accum update States at the moment's boundary. Inside the transaction that delivers the occurrence, the State still shows its previous value:
const count = clicks.accum(0, (_e, n) => n + 1);
const before = count.at(clicks);
// on the 3rd click, `before` is 2 — the value BEFORE this momentThis is what makes recursive definitions well-defined: "the new value depends on the old one" needs an "old one" that is stable within the moment. The past is available; the present is still forming.
Batching several fires
Each fire/set normally opens its own moment. When one user action updates several sources, wrap them in batch — everything inside joins one moment: joins recompute once, merges coalesce, observers run once at the end:
import { batch } from "@continuum-js/frp";
batch(() => {
query.set("");
page.set(1);
selection.set(null);
}); // one moment: one recompute per join, one DOM patch per bindingNested batch calls join the enclosing moment. You rarely need this — deriving state usually removes the need to set several sources at once — but when you do set several, batch keeps the in-between states from ever existing.
One rule: a stream carries at most one occurrence per moment, so firing the same stream twice inside one batch throws (silently folding the second occurrence over pre-moment state would corrupt accum). Setting the same state repeatedly is fine — the last write wins, and its updates delivers a single coalesced occurrence carrying the final value.
Effects run after
listen handlers run in the post phase, after the moment closes. If a handler fires a new event (a router redirect, a perform response), that opens a new moment — transactions never nest or interleave.
For the full operational story — the three phases, ranks, flatten, and how this maps to the Sodium book — see FRP-MODEL.
Unfamiliar term? Every piece of jargon in these docs is explained in the glossary.