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.