Transactions and proofs

Every commit in Hyphae — SQL, structure, or search — passes through one commit scheduler and lands at one commit sequence number (CSN) across every engine. This page covers how to stage a transaction that spans engines, what each durability class actually guarantees, and how a result can carry a proof someone else verifies without trusting the machine that produced it.

Explicit all-engine transactions

An explicit transaction mixes SQL, structure, search, and vector stages and commits them all under one CSN, or none of them. The step sequence is status, any of stage_sql, stage_structure, stage_search, stage_vector (repeatable, in any order), then a terminal commit or rollback. Each stage returns its own provisional result inside the transaction, before the commit:

hyphae transaction --data-dir "$D" execute --steps-json '[
  {"operation":"stage_sql","statement":"INSERT INTO notes (id, body, stars) VALUES (?, ?, ?)",
   "parameters":[3,"transactional note",5]},
  {"operation":"stage_structure","mutation":{"operation":"counter_add","keyspace":20,"key":"visits","delta":1}},
  {"operation":"commit"}
]'

If the process dies or a commit acknowledgement is lost, durable evidence on disk resolves the outcome — never guess or blindly replay a commit whose acknowledgement you never saw:

hyphae transaction --data-dir "$D" status --id <transaction_id>

In the SDKs, a cancelled or transport-failed commit becomes a terminal outcome_unknown — resolved the same way, through transaction status, never by re-sending the commit.

One delta batch, not a full-state reload

Underneath, a local all-engine transaction is built from one detached native delta batch captured off a single immutable snapshot: a bounded catalog cache, a relational overlay, a scalar-structure overlay, and a lexical overlay, rather than a reload of the whole directory's state on every stage. The batch stays bound to the exact live database handle that created it — staging or committing through a different handle, a reopened handle, or another directory fails closed. Work scales with the keys, index entries, and WAL bytes actually touched, not with the total row, structure, or document count already in the directory. Full contract: delta all-engine transaction v1.

Three durability classes

Every mutating command accepts --durability strict|group|memory. None of them carry a universal sub-millisecond promise — fsync, cold I/O, and unbounded queries are measured and reported separately, never folded into one latency claim:

  • Strict — acknowledged after this transaction's own WAL fsync. The strongest guarantee; the most fsync latency.
  • Group — acknowledged after a shared cohort fsync. Multiple commits share one fsync, trading a small acknowledgement delay for throughput.
  • Memory — acknowledged with no fsync at all. An acknowledged Memory commit can be lost on crash — but never torn: recovery drops whole commits from the volatile WAL suffix only, never a partial one.

A commit receipt's durability field names which class actually acknowledged that write (see Getting started). The cross-engine commit protocol — atomicity across crash and recovery, strict-durability acknowledgement, first-committer-wins, and contiguous visibility — has a machine-checked TLA+ model (docs/formal/HyphaeCommit.tla). The model checks the protocol as specified; it is evidence about the design, not a proof of the Rust implementation, whose fidelity is carried separately by physical crash-matrix tests.

Checkpoints, backups, vacuum

A checkpoint publishes one synchronized all-engine recovery boundary — run it before a backup, and after any bulk load. The verified full backup/restore cycle validates at every step before promising anything:

hyphae checkpoint --data-dir "$D"
hyphae backup create --data-dir "$D" --out ./backup      # → created (verified at creation)
hyphae backup verify --backup ./backup                   # → verified (without opening live state)
hyphae restore --backup ./backup --data-dir ./restored   # → restored (staging + doctor + atomic activation)
hyphae doctor --data-dir ./restored                       # → healthy, snapshot_verified: true

A Native backup is physical and synchronized, described by a NATIVE_BACKUP.json manifest with an exact inventory. Restore never merges or overwrites: it rebuilds into a sibling staging directory, runs mandatory doctor validation, then activates atomically — the destination must be new. There is no online or incremental backup; that is a declared non-capability, and media policy (where backups live, how long they are kept) belongs to your application, not Hyphae. vacuum rebuilds live roots into a smaller page generation and publishes the result atomically, for reclaiming space after deletes; compact --target structures|search compacts one root family on a schedule you choose. See Operations for doctor's full diagnostic scope.

Result proofs: verifiable without trusting the machine

An eligible read — a catalog lookup, a SQL query, or a product read — can emit a canonical proof plus a witness. Any third party verifies both completely offline, with nothing but a 32-byte trusted anchor supplied independently of the proof itself — no access to your data directory, no network call back to your machine:

# Generate: the query executes and is bound to the artifacts
hyphae proof generate --data-dir "$D" \
  --operation-json '{"operation":"sql","statement":"SELECT id, body FROM notes WHERE id = ?","parameters":[1]}' \
  --proof-out query.hynproof --witness-out query.hynwitness
# → { "anchor": "f68a8eae03a3ea69...", "kind": "sql", "proof_bytes": 620 }

# Verify (another machine, no data access): full semantic re-execution
hyphae proof verify --proof query.hynproof --witness query.hynwitness \
  --anchor f68a8eae03a3ea69...
# → { "status": "verified", "scope": "semantic_reexecution",
#     "semantic_reexecution_performed": true }

The verifier validates both artifacts, requires the independently supplied anchor, re-executes the operation under bounded reference semantics, and compares the exact result — it does not merely check that the proof is internally well-formed. CLI-provable operations are catalog_list, catalog_describe, and sql; the SDKs additionally expose prove, prove_sql, and verify_proof. Formats: native result proof v2 and native directory witness v2.

Witnesses and the external trusted anchor

A witness bundles every directory below the native data root needed to re-execute the proved operation, carrying the same directory lineage, history epoch, and visible CSN as the proof. The ExternalTrustedAnchor that verification requires binds the 24-byte directory lineage and nonzero history epoch, the visible CSN and catalog version, the complete immutable all-engine root digest, and the durable checkpoint's visible CSN and manifest digest — the producer checkpoints the exact root that produced the result while it holds the directory lock, and the verifier requires its own reopened, retained authority to equal that anchor exactly.

Self-consistency is not trust. A proof that only checks against itself proves nothing about the world outside the machine that generated it. Verification always requires the anchor from somewhere else — an escrow, a second party, a published ledger — obtained independently of the proof and witness you are handed. Hyphae's own verifier will not skip this step, and neither should yours.