From f7e3d912f55bb77493b03acfee0154853ed2a2b3 Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Wed, 8 Jul 2026 22:53:14 +0800 Subject: [PATCH] fix(db): reconcile retrieval_owner_matches search_path drift (schema.sql -> pg_catalog) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit schema.sql declared `set search_path = public, pg_temp` for retrieval_owner_matches while both live and the migrations (20260705210000, 20260708150000) use `public, pg_catalog`. schema.sql was the sole outlier, so a fresh schema.sql replay diverged from live on this function's def_hash — noise the drift detector would flag. Verified read-only against live (project sjrfecxgysukkwxsowpy) via schema_drift_snapshot(): live body is byte-identical and uses `public, pg_catalog` (def_hash 1d88b539bded5aa40393125f672b8cab). Changes (behaviour-identical — the body references nothing schema-qualified; pg_catalog is the safer choice for an immutable function): - schema.sql: pg_temp -> pg_catalog for retrieval_owner_matches. - drift-manifest.json: def_hash -> live's value; schema_sha256 recomputed (normalizedSchemaSha256 of the edited schema.sql). - drift-allowlist.json: the entry mislabelled this tiny boolean helper as a "live-ahead richer-body" RPC (copy-paste from match_document_chunks et al.). Narrowed to the real remaining drift: the PUBLIC-execute ACL, same posture as search_document_chunks (owner-managed hardening; revoke on live to close). - docs/database-drift-detection.md: removed retrieval_owner_matches from the "forward-codify live bodies" backlog group; noted the partial reconciliation. Manifest was hand-edited (Docker drift:manifest replay OOMs in this env, per the deploy-status notes); a reviewer can run `npm run drift:manifest` to confirm the snapshot def_hash + schema_sha256 match a fresh replay. tests/supabase-schema.test.ts: 42/42 pass. Co-Authored-By: Claude Opus 4.8 --- docs/database-drift-detection.md | 19 ++++++++++++------- supabase/drift-allowlist.json | 2 +- supabase/drift-manifest.json | 4 ++-- supabase/schema.sql | 2 +- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/docs/database-drift-detection.md b/docs/database-drift-detection.md index efd88e2e2..852291ec0 100644 --- a/docs/database-drift-detection.md +++ b/docs/database-drift-detection.md @@ -106,13 +106,18 @@ live project need explicit operator approval. `match_document_chunks_text` / `match_document_table_facts_text` (richer multi-strategy), `match_document_chunks_hybrid` (left-join quality_score), plus `match_documents_for_query`, `get_related_document_metadata`, - `retrieval_owner_matches`, `match_document_memory_cards_hybrid`, - `repair_strict_enrichment_gate_batch`. Applying the OLD `20260705210000` - bodies would regress live, so it is neutralized. Codify the **live** bodies - into schema.sql + a new migration (a generation script, not hand-editing — - the bodies are complex and actively churning) so the repo matches live and a - `db push` never regresses it. These are the currently-allowlisted retrieval - entries. + `match_document_memory_cards_hybrid`, `repair_strict_enrichment_gate_batch`. + Applying the OLD `20260705210000` bodies would regress live, so it is + neutralized. Codify the **live** bodies into schema.sql + a new migration (a + generation script, not hand-editing — the bodies are complex and actively + churning) so the repo matches live and a `db push` never regresses it. These + are the currently-allowlisted retrieval entries. + - **Partially reconciled 2026-07-08:** `retrieval_owner_matches` was in this + group by mistake — its **body is identical** to schema.sql; it only drifted + on `search_path` (live `pg_catalog` vs repo `pg_temp`) and ACL. The + search_path half is now codified into schema.sql + the manifest `def_hash` + (verified read-only against live via `schema_drift_snapshot`); only the + PUBLIC-execute ACL remains allowlisted, same as `search_document_chunks`. 1. ✅ **DONE 2026-07-08** — applied `20260706010000`, `20260706130000`, `20260706200000`, `20260707000000` to live (verified). `check:drift` can now run against live once a service-role key is available in the environment. diff --git a/supabase/drift-allowlist.json b/supabase/drift-allowlist.json index da4fc879b..b73d6df55 100644 --- a/supabase/drift-allowlist.json +++ b/supabase/drift-allowlist.json @@ -110,7 +110,7 @@ "category": "functions", "key": "public.retrieval_owner_matches(uuid,uuid)", "kind": "mismatch", - "reason": "LIVE IS AHEAD of the repo: live carries newer raw-SQL retrieval bodies (e.g. match_document_chunks has an hnsw.ef_search=100 wrapper; chunks_text/table_facts_text carry richer multi-strategy implementations). Migration 20260705210000 (which had OLDER bodies) was NEUTRALIZED 2026-07-08 so a db push can never regress live. DO NOT apply it. Resolution is forward-codification of the live bodies into schema.sql + a migration (drift backlog); until then these are allowlisted. Note: live retrieval RPCs are under active concurrent multi-session edits.", + "reason": "ACL-only drift: live retains a default PUBLIC execute grant (=X/postgres) that schema.sql (service-role-only) does not. Same posture as search_document_chunks — this is a security-invoker helper, RLS still applies; revoke on live via an approved hardening migration, then remove. The prior search_path half of this drift (live pg_catalog vs schema.sql pg_temp) was reconciled 2026-07-08: schema.sql + drift-manifest def_hash now match live's body (verified read-only via schema_drift_snapshot). This function is a stable boolean owner-scoping helper — NOT one of the raw-SQL retrieval RPCs (match_document_chunks et al.) whose bodies genuinely diverge; do not conflate.", "ref": "docs/database-drift-detection.md#reconciliation-backlog" }, { diff --git a/supabase/drift-manifest.json b/supabase/drift-manifest.json index 720134ce2..f37e0b762 100644 --- a/supabase/drift-manifest.json +++ b/supabase/drift-manifest.json @@ -2,7 +2,7 @@ "generated_at": "2026-07-08T06:45:01.039Z", "generator": "scripts/generate-drift-manifest.ts", "postgres_image": "supabase/postgres:17.6.1.127", - "schema_sha256": "430046a9221f4060286c2208800ef794eef407af8997fd4582f414de95e88c44", + "schema_sha256": "f7ca50611471d4ced647bfc7731d72f87856bd03890f03eaca8e0ccb8affc6b0", "replay_seconds": 13, "snapshot": { "views": [ @@ -5930,7 +5930,7 @@ "postgres=X/postgres", "service_role=X/postgres" ], - "def_hash": "2dff50fc9bc17ee3c6d71c9dcf9cee5e", + "def_hash": "1d88b539bded5aa40393125f672b8cab", "signature": "public.retrieval_owner_matches(uuid,uuid)" }, { diff --git a/supabase/schema.sql b/supabase/schema.sql index 484c41b84..5c5a5ddea 100644 --- a/supabase/schema.sql +++ b/supabase/schema.sql @@ -2047,7 +2047,7 @@ returns boolean language sql immutable parallel safe -set search_path = public, pg_temp +set search_path = public, pg_catalog as $$ select case when owner_filter is null then true