fabro/lib/components/fabro-petri/README.md
Bryan Helmkamp 3ffe7e00ce
Implement Petri's run store over Fabro's SQLite database
`SqliteRunStore` implements Petri's `RunStore` and `RunLogs` on the pool
Fabro's other stores share. A run's existence and writer lease live in
`petri_runs`; every record of every log lives in `petri_records`, keyed by
(run, log, seq) with the record stored as JSON and read back unchanged;
blobs share the `blobs` table with `BlobStore`. The lease is taken
idempotently per owner, ends when the last handle drops or when an
operator releases it, and never by timeout; every write checks it inside
its own transaction. An append is one `BEGIN IMMEDIATE` transaction per
batch: a repeated record is accepted, a different record at a taken seq or
a seq past the head is a conflict that stores nothing.

Petri's store conformance suite passes against it, with the operator
release, lease exclusivity, a crash between appends, and blob
interoperation checked beside it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-17 19:30:30 -04:00

1.7 KiB

fabro-petri

Fabro's adapters over Petri, the workflow engine Fabro runs its workflows on.

Layering rule

Only this crate imports Petri. The workspace Cargo.toml pins the Petri packages by revision under petri_* keys, and fabro-petri is the only member that lists them as dependencies. Every other Fabro crate reaches the engine through what this crate exports. A Petri pin move is therefore a change to this crate and the lockfile, nothing else.

What it holds

Every adapter the integration plan describes lands here.

  • SqliteRunStore: Petri's RunStore and RunLogs over Fabro's SQLite database, so a run's records live in Fabro's tables (petri_runs for the run and its writer lease, petri_records for every record of every log, and the shared blobs table). The module docs state the lease and append rules.
  • The platform adapters the plan adds after it: hooks, interviews, secrets, output storage, run tools, the event projection.

How it is tested

Integration tests live under tests/:

  • runs.rs runs the hello bundle in memory through Runtime::standard() with the Fabro frontend and the model-free stub registry, then a command-only workflow on the host sandbox through the real step registry. Both skip, and say why, when the sandbox-driver-host plugin executable is not on PATH (every run takes its scope's environment through it); the sandbox-plugins CI job requires them.
  • sqlite_store.rs runs Petri's store conformance suite (petri_testkit::run_store::conformance) against SqliteRunStore, plus the operator release, lease exclusivity, a crash between appends, and blob interoperation with Fabro's BlobStore.

Run them with:

ulimit -n 4096 && cargo nextest run -p fabro-petri