Repo copy of this guide:
docs/architecture/DATABASE_SCHEMA_REFERENCE.md,
kept in sync with this page. Verified against the live production database and
all 28 supabase/migrations/*.sql files. See Storage
first for the conceptual model.DATABASE_URL), not through
PostgREST — a direct connection bypasses Row Level Security the same way a table owner does.
RLS below matters for what a different credential (e.g. Supabase’s anon role) could see,
not what the application’s own connection can.
Quick index
Tables that share one shape
consumed_nonces, consumed_approval_nonces, consumed_policy_change_step_up_nonces are
three deliberately separate tables, not duplication — each backs a distinct trust
domain’s nonce namespace (a Gateway envelope, an Approval Artifact, a checker’s step-up
key), issued by different parties. Sharing one table would let a coincidental collision
between unrelated namespaces falsely report “already consumed.” All three: TEXT PRIMARY KEY
nonce column (the PK is the atomicity mechanism — a concurrent duplicate insert hits
Postgres 23505 unique_violation, mapped to “already consumed,” no separate locking
needed), expires_at TIMESTAMPTZ NOT NULL, consumed_at TIMESTAMPTZ DEFAULT now().
executions, verifications, receipts, overrides also share a near-identical shape:
an id, a business_transaction_id FK (ON DELETE RESTRICT), a JSONB payload column, a
timestamp, and a seq BIGSERIAL (added by 20260711120000 for exact insertion-order —
millisecond timestamps can tie under fast concurrent appends).
Tables worth extra attention
caller_audit_events — the most-altered table in the schema (8 migrations). Its type
CHECK constraint was widened 5 times. One of those widenings
(20260911090000_add_capability_granted_to_caller_audit_events.sql) was a bug-fix:
application code had already been writing 'caller.capability_granted' before any
migration allowed it, so every successful authenticated request failed closed with 503 AUDIT_UNAVAILABLE until fixed. Adding a new event type here and forgetting the matching
migration reproduces this exact outage. Chained per caller_id via a Postgres advisory
lock on hashtext(caller_id), not one global lock.
execution_audit_events — the only table written to by code outside this repository.
parmana-paytm-agent writes directly to it (its own src/parmana/audit.ts), correlated by
business_transaction_id (not authorization_id, which is Parmana-internal and never
crosses the trust boundary). Its rows are unsigned/unchained — that service holds only
Parmana’s public key, never a private key. Chained per authorization_id on this
repo’s own side.
policy_change_approval_records — the only table with a real RLS policy attached
(anon role, read-only, for CI). As of this writing, zero rows — none of the 10 real
production policies have been approved by a distinct human checker yet. Expected, not a bug.
challenge_records — the only mutable table in the schema. Every other table here is
append-only by convention; this one is explicitly updated as an investigation proceeds.
Deliberately unsigned: the writer and the party who could misrepresent it are the same
party, so a signature would prove tamper-evidence of bytes without addressing the actual
trust question.
rate_limit_counters — the only table without RLS enabled (deliberately — no business
data, no dashboard access path). See docs/VERIFICATION-GAPS.md G-49 (repo root) for why
this table’s keys are now prefixed per rate limiter.
Common SQL for troubleshooting, audit, and verification
Trace one transaction across every table
The single most useful query — everything that happened for onebusiness_transaction_id:
parmana-paytm-agent had recorded
authorization.verified for a transaction Parmana’s own logs only showed a generic 500
for.
Trace one caller’s audit history
Check a rate limiter’s current state for a caller
Audit the maker-checker approval queue
Migration-sync verification (files vs. tracking table)
Check a table’s actual CHECK constraints
Several tables’ constraints have been widened repeatedly — don’t trust the originalCREATE TABLE statement alone:
Find foreign keys pointing at a table (before ever dropping one)
docs/architecture/DATABASE_SCHEMA_REFERENCE.md, for the complete
per-table column reference and additional queries (row-count health snapshots, RLS status
listing, nonce-consumption checks).
Next
Storage
The conceptual model this reference builds on.
Caller Audit Trail
The concept
caller_audit_events backs.