Skip to main content
Rafflesia is built so that an answer can be re-derived later, by someone else, byte for byte. Three mechanisms do the work.

Immutable releases

Data is never queried “as it currently is”. A corpus is compiled into an immutable release — a fixed set of content-addressed objects, each referenced by URI and SHA-256. A release can never change underneath a query. Mutable aliases (like stable) point at a release. Publishing swaps the pointer atomically; the release the pointer used to name still exists and is still queryable.
Pass the exact release you intend to read, and the answer is pinned:

Digests

Beyond the data, the semantics are versioned. The ontology — every declared identifier namespace, coordinate system, relation, and join — is one file whose SHA-256 digest is folded into query identity. A query cannot silently acquire different semantic validation, because a different ontology is a different digest.
Passing --ontology-digest turns “I expect these semantics” into an enforced precondition: if the deployment moved on, the query fails instead of quietly answering under new rules. The same idea appears throughout: relation digests, release digests, index build ids, engine versions, and canonical input_hash / parameters_hash on every response.

Explicit sources, refused guesses

Determinism is not only about pinning versions — it is about refusing to invent the parts the caller left out.
  • Every FROM/JOIN in a query must be declared with --source. There is no implicit catalog resolution.
  • A join is allowed only along a registered, type-checked relationship. An unregistered pair is refused, not guessed. See Joins & join safety.
  • Network access for fetch primitives is opt-in per call (--allow-network), so a run that was supposed to be offline cannot silently reach the internet.
  • Nothing is resolved from ambient state. There is no session, no “current database”, and no remembered defaults that would make the same command mean two different things.

What is not promised

  • Wall-clock time is not part of the contract. The same query may be faster on a warm cache; provenance.cache_hit tells you which happened. Caches are optimizations, never correctness requirements.
  • Floating-point measurement values are reproducible for a fixed engine version, which is why the engine version is in provenance rather than implied.
  • An alias is not a pin. If you record stable instead of the database_release_id it resolved to, you have recorded a moving target. Every response echoes the exact release it read — keep that value.