DB reliability: full-inventory drift detection (check:drift), DR rehearsal, expand/contract migration policy#342
Merged
Merged
Conversation
…n policy check:drift generalizes search_schema_health()'s single-hash approach: a service-role schema_drift_snapshot() RPC (migration 20260706200000, prepared NOT applied) returns the normalized live inventory of every function (comment/whitespace-stripped pg_get_functiondef md5 + sorted ACLs), index, RLS policy, table shape, constraint, trigger, view and bucket, compared against supabase/drift-manifest.json — generated by drift:manifest, which replays schema.sql from scratch into a Docker supabase/postgres container (so replayability is re-proven on every regeneration). Known divergence lives in a 124-entry reasoned allowlist; offline halves (manifest freshness sha256, migration<->schema.sql parity, engine unit tests) run in verify:cheap. Baseline three-way audit (live vs schema.sql vs migration chain, 166 divergent keys, all classified): schema.sql was not from-scratch replayable (document_index_units ordering — fixed); 15 worker-written columns existed only on live (codified in 20260707000000 with the live-only functions/triggers/constraints/reloptions, idempotent and byte-aligned so live apply is a no-op); 20260703030000 is recorded as applied on live but its effects are absent; schema.sql text realigned to migration-chain truth for 4 functions and 6 policies. DR rehearsal: schema restore measured ~19s; search_schema_health ok and all four hybrid retrieval RPCs proven on the restored copy with seeded vectors; runbook with RPO/RTO and the did-not-survive list in docs/disaster-recovery-runbook.md. Expand/contract policy for retrieval tables added to docs/supabase-migration-reconciliation.md. Live project was read-only throughout; both new migrations await an approved supabase db push. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Updates to Preview Branch (claude/db-reliability) ↗︎
Tasks are run on every commit but only new migration files are pushed.
View logs for this Workflow Run ↗︎. |
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
BigSimmo
marked this pull request as ready for review
July 7, 2026 03:13
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
BigSimmo
enabled auto-merge
July 7, 2026 03:13
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
This was referenced Jul 8, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Database reliability workstream: standing full-inventory drift detection, a rehearsed disaster-recovery runbook, and an expand/contract migration policy for retrieval tables. The live project (
sjrfecxgysukkwxsowpy) was read-only throughout — nothing was applied; the two new migrations ship prepared-only.1. Automated drift detection (
npm run check:drift)Generalizes
search_schema_health()'s single-function-hash approach into a comparison of every live function (comment/whitespace-strippedpg_get_functiondefmd5 + sorted ACLs), index, RLS policy, table shape (columns sorted by name), constraint, trigger, view, extension, and storage bucket againstsupabase/schema.sql:20260706200000_schema_drift_snapshot.sql—schema_drift_snapshot(), a service-role-only RPC returning the normalized live inventory (mirrored in schema.sql; byte-parity is test-enforced). Prepared, NOT applied to live —check:driftneeds it applied first.supabase/drift-manifest.json— expected state, generated bynpm run drift:manifest: replays schema.sql from scratch into a disposablesupabase/postgres:17.6.1.127container and snapshots it. Embeds schema.sql's sha256; the freshness test inverify:cheapfails if schema.sql changes without regeneration — which also makes every regeneration a from-scratch replay proof.supabase/drift-allowlist.json— 124 measured, classified, reasoned entries for today's known divergence (pending migrations, legacy index estate, grant-posture decision, codification backlog). Anything not listed exits 1; stale entries are reported.search_path-dependent rendering (pinned to''), column ordinal drift, ACL append order, platform-provisioned extensions, legacy index names (machine-verifiedaliasentries), and duplicate migration-history versions (history is never compared — see below for why).tests/drift-detection.test.ts(10 tests): manifest freshness, migration↔schema.sql snapshot parity, allowlist hygiene, comparison-engine unit tests.2. Baseline three-way audit findings (live vs schema.sql replay vs migration-chain replay)
166 divergent keys, fully classified in docs/database-drift-detection.md. Highlights:
supabase/schema.sqldid not replay from scratch (document_index_unitsdeclared after its first validating reference). Fixed by reordering.document_images×7,document_index_quality×6,ingestion_job_stages×2) — a branch/preview DB restored from the repo had broken ingestion. Codified along with 3NOT VALIDcontent checks, autovacuum reloptions, 4 live-only functions and 2 triggers in20260707000000_codify_live_observed_drift.sql(idempotent; byte-aligned with live so applying it there is a no-op).20260703030000is recorded as applied in live history but its effects are absent — the original incident class, recurring. This is whycheck:driftcompares object state, never history.20260705210000,20260706010000,20260706130000) and clear on the next approveddb push.authenticatedData-API grants on 17 tables (owner-read RLS policies are currently dead on live); 4 security-invoker functions retain PUBLIC execute; ~80 index-estate items.3. DR rehearsal (docs/disaster-recovery-runbook.md)
scripts/sql/drift-replay-scaffold.sql— the chain is not self-sufficient on bare Postgres either).search_schema_health()→ok:true; all four hybrid retrieval RPCs + lexical + doc-query paths return seeded vectors correctly (similarity 1.000 / hybrid 0.760).4. Migration discipline
Expand/contract policy for retrieval tables written into docs/supabase-migration-reconciliation.md, grounded in what the rehearsal exposed ("history presence is not effect presence"; NOT VALID + VALIDATE; side-by-side RPC versions; drops ship separately and later).
Verification
npm run verify:cheap— pass (includes the 10 new drift tests; 41/41 existing schema tests still green after the schema.sql reconciliation).npm run check:supabase-project— pass (targetssjrfecxgysukkwxsowpy).npm run check:indexing— not runnable in this environment (requiresSUPABASE_SERVICE_ROLE_KEY+OPENAI_API_KEY, not present on this machine); its DB-side core was exercised directly:search_schema_health()returnedok:trueon live (via MCP, read-only) and on both replay containers.npm run drift:manifest— run end-to-end (its output is the committed manifest).Operator follow-ups (need your explicit approval — nothing applied)
supabase db pushthe pending stack:20260705210000,20260706010000,20260706130000,20260706200000(enablescheck:drift),20260707000000.20260703030000's statements under a new version (recorded-but-ineffective).npm run check:driftand start burning down the allowlist per the backlog in docs/database-drift-detection.md.🤖 Generated with Claude Code