Provable temporal logic

The correctness you can demonstrate, not just claim.

The hardest bug class to catch

Temporal bugs — wall-clock assumptions, stale closures, async races, missing cleanup — are exactly what AI code generation produces confidently and wrongly. A language model trained on React patterns has absorbed the idiom of useEffect + setTimeout + ref and will reproduce it fluently. It will not flag the race condition. It will not notice that the effect fires twice in Strict Mode. It will not realize that replayed events arrive out of order and the setTimeout measured the wrong interval.

React keeps shipping patches for exactly this class of bug: useEffectEvent (experimental, then revised), and the 19.x series of fixes for effects that run in an unexpected order under concurrent rendering. The pattern is not a React failure; it is a structural property of any model where logic, state, time, and side-effects are entangled in imperative code.

These bugs are also the hardest to catch in review. A correct-looking setTimeout in a useEffect is indistinguishable at a glance from a subtly broken one. The breakage only surfaces under specific timing conditions that code review does not reproduce.

tflo's two-front answer

(a) Less surface for slop. A declarative temporal rule replaces scattered effects, timers, and refs. There are no cleanup paths to forget, no stale-closure traps, no double-fire under Strict Mode. The rule reads like the requirement; the implementation is a single expression.

(b) The correctness is checkable. Because the engine is pure and the clock is injected, you feed a synthetic timestamped event log and assert exact output deterministically. The late-event case is a first-class test, not an untestable corner:

// Illustrative — the SHAPE of a deterministic event-time test, not a verbatim
// copy of any file. tflo-react's real suite (e.g. tests/reorder.test.tsx) asserts
// the same property through the React-hooks surface; the validation/ scenarios
// self-assert the same way. The point is the pattern: manual clock, timestamped
// events fed in arrival order, exact asserted output.
it("fires Abandoned when checkout_done arrives after the deadline — even late", () => {
  const clock = new ManualClock();
  const engine = buildCheckoutPattern({ clock });

  // Feed events in arrival order (out of event-time order)
  engine.push({ event: "checkout_begin",  ts: 1000 });
  engine.push({ event: "add_to_cart",     ts: 1200 });
  // checkout_done arrives late — after the 5-min deadline in event-time
  engine.push({ event: "checkout_done",   ts: 1000 + 6 * 60_000 });

  clock.advance(1000 + 6 * 60_000);
  expect(engine.signals()).toContainEqual({ kind: "Abandoned", ts: 1000 + 5 * 60_000 });
});

The snippet above is illustrative — it shows the pattern, not a verbatim file. tflo-react's actual tests (e.g. tests/reorder.test.tsx) assert the same late-arrival property through the React-hooks surface, and every scenario in the validation/ directory self-asserts; the late-arrival path is not a special case or a manual verification step — it is a normal assertion.

In the age of AI-written code, the temporal logic that ships is the temporal logic you can prove.

Testability by tool

Tool Expression Testability
React / effect Scattered useEffect + setTimeout + refs + reducer vi.useFakeTimers() tests wall-clock advance; stale-closure bugs slip through because the test and the production path share the same closure model
Signals (JS) Can't express temporal — collapses to effect + timer Nothing temporal to assert; you test a current value. The temporal logic lives outside the signal model and inherits React's testability limits
RxJS Operator chain; window / absence hand-coded TestScheduler marbles test processing-time advance only; the late-event case — where a payload ts is earlier than arrival — is the case you can't test with marbles
XState Machine + custom event-clock @xstate/test gives strong state-coverage; event-time testing requires a hand-built virtual clock injected into the machine; not impossible, but not built-in
tflo Reads like the requirement: A then B within T, unless C Feed timestamped events to a manual clock, assert exact output — deterministic and replayable. Late-arrival and out-of-order are ordinary test inputs, not special cases

The proof asset: the validation suite

The tflo-react/validation/ directory contains 16 reproductions across the three proven temporal scenarios: scenario-1-abandoned-flow (event-time negation within a window), scenario-2-temporal-join (event-time windowed join), and scenario-3-out-of-order-windows (late-event tolerance). Each scenario has implementations for React, Signals, RxJS, XState, and tflo.

The React, Signals, RxJS, and XState paths reach the correct output only by hand-writing the event-time logic themselves. Each implementation self-asserts — it runs its own check and either passes or prints the expected vs actual output — so the suite is runnable and verifiable without any additional test harness.

The point of the suite is not "look what the other tools can't do." Each tool is shown in its idiomatic form first (which produces a wrong answer on delayed events), then in its event-time-correct form. The suite documents the gap that exists and the work required to close it without tflo.

Next: Production superpowers — what purity enables beyond testing: crash recovery, regression replay, what-if backtesting, and operational portability. Or go back to event-time vs processing-time.