Skip to content

feat(storage): opt-in Postgres backend - #132

Merged
prashar32 merged 1 commit into
mainfrom
feat/postgres-backend
Jun 14, 2026
Merged

feat(storage): opt-in Postgres backend#132
prashar32 merged 1 commit into
mainfrom
feat/postgres-backend

Conversation

@prashar32

Copy link
Copy Markdown
Owner

SQLite is the right default — zero-config, a single file you own. This adds an
opt-in Postgres backend behind the same Store interface for multi-instance /
HA deployments, selected by setting RISKKERNEL_DATABASE_URL. Nothing changes
unless you set it.

export RISKKERNEL_DATABASE_URL="postgres://user:pass@host:5432/riskkernel?sslmode=require"
riskkernel serve   # logs: state store ready  backend=postgres

Design

The Postgres schema mirrors SQLite's exactly — timestamps as RFC3339 text, JSON
marshaled in the application — so every package-level scan/marshal helper is
reused
; only the SQL dialect (placeholder style, the metadata JSON accessor) and
the DDL differ. The existing SQLite backend is left completely untouched, so
there's zero risk to the crash-resume path it already powers.

  • Forward-only migrations on startup via embedded Goose, with the same downgrade
    protection (refuse to boot on a schema newer than the binary).
  • Implements the full Store: runs, steps, the cost ledger and its summaries
    (including metadata grouping), tool-call audit trail, memory facts, approvals,
    policy bundles, and crash-resumable checkpoints.
  • Driver: github.com/jackc/pgx/v5, used via database/sql so the query layer
    stays shared in style with SQLite. (+3 small transitive jackc/* helpers.)

Tests

  • A shared Store conformance suite (conformance_test.go) runs against
    both backends, so a query that works on one but not the other fails CI.
    TestSQLiteConformance runs in ordinary CI; TestPostgresConformance /
    TestPostgresMigrateDowngradeProtection run when RISKKERNEL_TEST_DATABASE_URL
    points at a disposable Postgres (CI provides one as a service).
  • Verified against a real Postgres 18 locally: the conformance suite and the
    downgrade-protection test pass, and a daemon restart against shared Postgres
    state reloaded an in-flight run and kept enforcing its already-spent budget

    crash-resume works across instances, not just on SQLite.
  • go test -race ./... green; go vet ./... clean; gofmt clean.

Docs: docs/POSTGRES.md; compatibility posture updated in
COMPATIBILITY.md (both schemas forward-migratable, parity held by the conformance
suite).

Closes #25

Add a Postgres implementation of the Store interface for HA / multi-instance
setups, selected by setting RISKKERNEL_DATABASE_URL. SQLite stays the zero-config
default; nothing changes unless the URL is set.

The Postgres schema mirrors SQLite's exactly — timestamps as RFC3339 text, JSON
marshaled in the application — so every package-level scan/marshal helper is
shared and only the SQL dialect (placeholders, the metadata JSON accessor) and
the DDL differ. The existing SQLite backend is left untouched, so there's no
risk to the crash-resume path it already powers.

Forward-only migrations run on startup via embedded Goose with the same downgrade
protection (refuse to start on a schema newer than the binary). A shared Store
conformance suite runs against both backends to hold them at behavioral parity;
it covers runs, steps, the cost ledger and its summaries (including metadata
grouping), tool calls, memory facts, approvals, policy bundles, and checkpoints.

Verified against a real Postgres: the conformance and downgrade-protection suites
pass, and a daemon restart against shared Postgres state reloads an in-flight run
and keeps enforcing its already-spent budget — crash-resume works across
instances. The Postgres tests are skipped unless RISKKERNEL_TEST_DATABASE_URL
points at a disposable database.

Dependency: github.com/jackc/pgx/v5 (the standard Postgres driver, used via
database/sql so the query layer stays shared with SQLite).
@prashar32
prashar32 force-pushed the feat/postgres-backend branch from 84948a4 to 74e5936 Compare June 14, 2026 16:11
@prashar32
prashar32 merged commit 0e92040 into main Jun 14, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Postgres storage backend (implement storage.Store)

1 participant