Decision 0008 — Durable multi-step execution: step ledger, DBOS deferred
Multi-step choreography runs on a step ledger over the job store, with DBOS deferred.
Status: accepted · 2026-08-22
Context
Upcoming choreographies need crash-resumable multi-step execution with rollback points: DEK rotation (the most dangerous operation in the system), upgrade-with- snapshot, and multi-leg backup verification. Durable-execution engines exist for exactly this. Assessment of the embeddable field (sources in the assessment note):
- DBOS Transact is the only candidate compatible with the invariants:
in-process library, MIT, and — decisively — a SQLite system database — the default
in the Python SDK, and in the Go SDK an explicit driver import (a binary-size
choice, not a maturity signal) backed by the same
modernc.org/sqlitedriver this project already uses; the Go config even accepts a supplied*sql.DBhandle (verified against the vendor docs, 2026-08-22). It genuinely embeds; no second process, no Postgres. DBOS's own production caveat for SQLite is multi-server distribution — a topology this project forbids by invariant, so the caveat does not apply here. - Everything else disqualifies structurally: Restate (separate server, BSL), Inngest (server, source-available), resonate (separate server despite SQLite), Temporal (server cluster), River (Postgres). No mature Go-native SQLite-embedded durable-execution library exists — the gap was searched and is empty.
Decision
Adopt the pattern, not the engine. Multi-step choreographies are built on a
small step-ledger extension of the existing job store: a workflow_step table
(workflow id, step, status, result, rollback marker) written in the same
transaction as each step's effect, idempotent steps, resume-from-ledger in the
boot sweep. The existing queue remains the only execution authority.
DBOS is deferred, not rejected: even as the vendor default, its Go SQLite path is one month past GA, ~90% of commits are one author's, and adopting it would place a second workflow runtime — its own schema, migrations, recovery semantics — beside a queue whose properties (SQL-enforced concurrency keys, redaction at persistence, exit-code doctrine, approval gating, crash sweeps) the test gates have proven and no generic engine provides.
Consequences
We own ~200 more lines of sequencing code and its tests; rotation/upgrade land on
infrastructure the drills already exercise. Revisit DBOS in 6–12 months if its
SQLite backend matures, the contributor base broadens, and a choreography
genuinely outgrows the ledger (fan-out with per-step retries and timers would be
the signal). A future adoption could hand DBOS a *sql.DB over a file in our own
data dir, so the storage story would stay one directory even then.