# Determinism

> For the complete documentation index, see [llms.txt](https://docs.lertha.com/llms.txt).
> Any documentation page is available as raw Markdown by appending `.md` to its URL.

> The one rule a flow body must obey, and the replay mechanism that makes it necessary.

A flow body must be deterministic: given the same input and the same answers from the engine, it
makes the same calls in the same order.

## Why

The orchestrator does not checkpoint memory. It records **events**: task scheduled, task
completed with this result, timer started, timer fired, signal received. When a worker picks up
a run that another worker started, it runs the body from the top and, at each scope call, feeds
it the recorded answer instead of doing the work again. The body reaches the first call that has
no answer yet, and real execution continues from there.

That only works if the body asks the same questions in the same order every time.

## What breaks it

| Do not | Do instead |
| --- | --- |
| `System.currentTimeMillis()`, `Instant.now()` | `flow.now` |
| `Random`, `UUID.randomUUID()` in the body | generate in a task, or derive from the input |
| HTTP, database, file I/O in the body | a task |
| threads, coroutines, `suspend` in the body | `flow.startTask` for fan-out |
| branching on anything outside input, task results, signals and engine time | move the read into a task |

## Versioning

Two builds of the same flow type on one queue means a run can start on one build and continue on
the other. The orchestrator compares the **sequence of commands** during replay, not their
parameters: a changed timer duration goes unnoticed, a reordered task call does not. Keep one
build per queue, and drain runs before removing a step from a flow that has long-lived runs in
flight. A versioning guide for in-flight changes is on the way.

**Remember:** replay is the whole trick. Determinism is its price.
