Production superpowers
Purity is the product.
The spine: purity unlocks everything
tflo's engine is 100% functional. output = f(event_log, rule, clock)
is a pure function: same inputs, same output, always. The clock is an injected input, not
a runtime call to the wall. State is never mutated behind a reference.
What-if, roll-back, roll-forward, and simulation are not separate features. They are the same operation — re-running the function with one input changed. There is no special API to build, no forked code path to maintain. The capability is structural.
// The engine is a pure function. One operation, three levers.
output = f(event_log, rule, clock)
// What-if: swap rule
output_b = f(event_log, rule_b, clock)
// Roll back: truncate the log
state_as_of_t = f(event_log.up_to(t), rule, clock)
// Roll forward: extend the log (e.g. apply a correction event)
state_corrected = f([...event_log, correction_event], rule, clock)
// Simulation: swap the clock
simulated = f(event_log, rule, synthetic_clock) Capability status
| Superpower | Basis | Status |
|---|---|---|
| Crash recovery / checkpoint-resume | Checkpointer (async store, circuit breaker); topology fingerprint guards against loading mismatched state | SHIPS |
| Deterministic regression vs recorded sessions | Record an event log → replay() re-derives identical signals; the output is byte-for-byte reproducible | SHIPS |
| Audit / "why did it fire" | Provenance + rule_version stamped on every emit; every signal carries the evidence that produced it | SHIPS |
| State-as-of-T / roll back | Replay events where ts ≤ T via useRecorder().replayUntil(t); GraphSnapshot store-and-restore. Runnable proof in tflo-react/validation/primitive-recorder/ | SHIPS |
| What-if / backtest (vary the rule) | useBacktest(log, specs) — run a recorded log against multiple specs and diff the outputs. Runnable proof in tflo-react/validation/primitive-backtest/ | SHIPS |
| Shadow / canary rule rollout | useShadowSpec(active, candidate) — run a candidate rule alongside the current rule in production, diff output, promote when confident. Runnable proof in tflo-react/validation/primitive-shadow/ | SHIPS |
| Bitemporal corrections | Event-time + reorder buffer accept late corrections; full bitemporal versioning not yet formalized | PARTIAL |
| Operational portability (edge ↔ browser ↔ server) | One compiled engine; parity guaranteed by the cross-tier demo; cross-language portability is next | SHIPS; cross-language ROADMAP |
Honesty caveats
The table above uses "LATENT" to mean the primitive capability exists and is correct, but there is no convenience API built on top of it yet. Using it today requires assembling the pieces by hand. A few specifics worth being precise about:
- GraphSnapshot now covers
ScanandScan2nodes via opt-inscan_f64_checkpointed. The earlier "partial" caveat is resolved for serde-able accumulators. Graphs using custom non-serde accumulators still require manual snapshot support. - useRecorder replays from the start of the recorded log, not from an arbitrary seek point. "Roll back to T" today means replaying the prefix of the log, which is correct but not interactive-scrubber fast for large logs.
- "Time-travel" in the current implementation means deterministic re-derivation: feed the same events again and get the same signals. A scrubber UI that lets you drag to a point in time is roadmap, not shipped.
Roadmap
| Priority | Item | Status |
|---|---|---|
| P1 | useBacktest(log, specs) — run a log against multiple specs and diff; runnable proof in tflo-react/validation/primitive-backtest/ | DONE |
| P2 | useRecorder().replayUntil(t) — state-as-of-T via log prefix replay; runnable proof in tflo-react/validation/primitive-recorder/ | DONE |
| P3 | useShadowSpec(active, candidate) — run a candidate rule alongside the current rule, diff output, promote when confident; runnable proof in tflo-react/validation/primitive-shadow/ | DONE |
| P4 | Full bitemporal versioning — formalize the correction model; track both event-time and record-time for late-arriving corrections | ROADMAP |
| P5 | GraphSnapshot for Scan / Scan2 via opt-in scan_f64_checkpointed | DONE |
Why incumbents structurally can't
The capabilities above are not features that could be bolted onto an existing processing-time tool. They require that logic, state, time, and side-effects be separated at the architectural level. When time is entangled with the wall clock inside the operator, you cannot swap it. When state is mutated by a closure that captures the scheduler, you cannot replay without re-running the scheduler in exactly the same order.
React, RxJS, and most signal libraries entangle these concerns by design: the programming model is imperative mutation driven by events, and the wall clock is assumed. That model is excellent for its target use case (rendering the current UI state) and structurally unable to support deterministic replay or event-time correctness.
One fair credit: XState does support persisted-snapshot resume for a single actor. You can serialize a machine's current state and restore it later. This is genuine crash recovery at the state-machine level. It does not extend to event-time replay (the restored machine still uses the wall clock going forward), but it is real and useful.
Related: Provable temporal logic — how purity makes the late-event case a first-class test — and event-time vs processing-time for the foundation these capabilities are built on.