Determinism
Phony data is a pure function of (schema, seed, reference-time). Same inputs → byte-identical output, every run, every machine, every language runtime. There is no hidden randomness and no wall-clock dependency.
Why it matters
- Safe to commit. A test fixture that regenerates identically can live in your repo and CI — no flaky data.
- Reviewable. A change to the schema produces a reviewable diff in the data.
- Portable. The same schema in the CLI, an OSS library, or the Cloud yields the same rows — so you can develop against one and deploy against another.
How it works
The seed. Every value comes from a seed derived from (root_seed, field_path, row) — a fast, portable mix (FNV-1a + a SplitMix64 finalizer). Each cell has its own seed, so changing one field's definition doesn't shift everything else, and a PHP/JS/Python runtime can reproduce the exact same draws.
Row consistency. Within a row, references are memoized: email and full_name see the same first_name. The row holds together.
The frozen clock. "Now" never comes from the system clock — it comes from an injected reference instant. now(), today(), age(), and relative ranges like -1year or now+7days all resolve against it:
let registry = Registry::with_builtins()
.with_reference_time(1_704_067_200); // 2024-01-01T00:00:00ZSo a schema that says "created in the last year" produces the same dates tomorrow as it did today.
What changes the output
Only three things: the schema, the seed, and the reference time. Change any one and you get a different — but equally valid and equally reproducible — dataset. Change none and you get the same data forever.
This cross-runtime reproducibility is the core promise that lets a portable
.phonypackage behave identically everywhere. See the Execution Model for how the runtimes line up.