Mental model
tflo vs React state, Signals, RxJS, XState
Where does authority over time live?
Every reactive tool has an implicit answer to this question. The answer shapes what questions you can ask, what bugs you can prevent, and what you can prove after the fact.
RxJS: time = when a value arrived at the scheduler.
The debounceTime, bufferTime, windowTime, and
throttleTime operators all read the wall clock at call time. The scheduler owns time.
XState: time = how long you have been in a state,
measured from the machine's own wall clock. The after transitions use
setTimeout under the hood. The machine owns time.
tflo: time = what the record itself says happened, in what order, at what instant — and that clock is an injected input, not a runtime assumption. The data owns time. The engine is a function of the event log, the rule, and a pluggable clock; given the same three inputs you get the same output, always.
Side by side
| Tool | Mental model | Best at | Models time? | History & time-travel |
|---|---|---|---|---|
| React state | Current snapshot, manual propagation | Rendering now | No — only "now" | None |
| Signals (JS reactivity) | Current snapshot, automatic fine-grained propagation | Reactivity / derived values | No — still only "now" | None |
| RxJS | Values over processing-time streams | Async composition, transport | Time = arrival | Ephemeral, no replay |
| XState | Finite states + events | Lifecycle / orchestration | Time = wall-clock delay | Per-entity snapshot, no event-time replay |
| tflo | Timestamped events + temporal rules | What happened, in what order, within what time, and what did not | Time = first-class axis of the data | Event-sourced: replay, what-if, roll back/forward |
Disambiguation: two things called "signal"
Important: "Signals" in this page means
JS reactivity signals — the Preact, Angular, Solid,
and TC39 proposal model for fine-grained reactive current values. It does
not mean tflo's typed Signal<Mode, Payload> output
type, which is a timestamped, typed verdict emitted by a tflo detector. They share a word
and nothing else.
JS Signals are reinforcement, not competition
The TC39 Signals proposal explicitly defers async and time: the proposal text notes that "async is omitted for now." This is a deliberate scope decision, not an oversight. Signals standardize the current-value layer and leave the temporal layer to be composed on top.
tflo and JS signals compose cleanly: tflo runs its temporal rule over a timestamped event log and emits a verdict; a JS signal holds the latest verdict for rendering. Each does what it is good at. Neither is a replacement for the other.
Ergonomics boundaries
Pick the tool that matches the question you are actually asking:
- tflo "When X, followed by Y, unless Z within T" — or the negative: "X without Y within T"
- RxJS Transform, combine, or cancel async streams; pipeline composition over arrival-ordered values
- XState The UI is in one of these states; these events transition between them; orchestrate lifecycle
- React state / Signals Render the current value; derive a new value from the current value; propagate a change
Next: Event-time vs processing-time — why the assumption "time = now" is invisible until it isn't — or Provable temporal logic for the testability story. See also Positioning for the broader project framing.