- Notifications
You must be signed in to change notification settings - Fork 0
fix: implement all 12 database review findings#134
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Uh oh!
There was an error while loading. Please reload this page.
Merged
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
b8a5c62
fix: implement all 12 database review findings
BigSimmo 8dbe257
fix: sync indexing v3 agent job status updates
BigSimmo 5dc4102
Merge branch 'main' into bigsimmo-database-review
BigSimmo a846626
Merge branch 'main' into bigsimmo-database-review
BigSimmo 52cc6ab
Merge branch 'main' into bigsimmo-database-review
BigSimmo 93ae467
Merge branch 'main' into bigsimmo-database-review
BigSimmo e59c73b
fix(schema): keep legacy NULL artifact generations visible
BigSimmo e8b7e04
Sync storage cleanup FK in schema snapshot
BigSimmo 07fea45
Fix schema grant order for indexing helper
BigSimmo 9dbda7e
fix(migration): gate job claims by document status
BigSimmo fcba469
fix(migration): preserve legacy generation rows on commit
BigSimmo d7b5c2f
fix(migration): normalize legacy v3 agent statuses
BigSimmo f9781f0
Merge branch 'main' into bigsimmo-database-review
BigSimmo 091a3ac
Ensure v3 jobs are enqueued during claim
BigSimmo 6843db8
Fix outdated indexing schema assertions
Copilot 9ae1674
fix(migration): fall back to metadata gen for null-typed artifact row…
BigSimmo af745b2
Merge origin/main into bigsimmo-database-review
Copilot b743ca2
Merge origin/main into bigsimmo-database-review
Copilot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Jump to file
Failed to load files.
Loading
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| {"version":1,"sessions":{"70c96a73-49a6-4422-a310-d0294a45dc49":{"updatedAt":1782977742215,"files":{"C:\\Users\\joshs\\.copilot\\repos\\copilot-worktrees\\Database\\bigsimmo-bookish-barnacle\\supabase\\functions\\indexing-v3-agent\\index.ts":{"editCount":1,"findings":[]}}}}} |
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
11 changes: 11 additions & 0 deletions
11 supabase/migrations/20260702100000_add_claim_ingestion_jobs_comment.sql
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| -- Fix #12: Add explanatory comment to claim_ingestion_jobs explaining the | ||
| -- dual-lock (FOR UPDATE OF j, d SKIP LOCKED) pattern. No behaviour change. | ||
| comment on function public.claim_ingestion_jobs(text, integer, integer) is | ||
| 'Claims up to p_limit pending/failed ingestion jobs for the given worker_id. | ||
| Uses "FOR UPDATE OF j, d SKIP LOCKED" to lock both the ingestion_job row (j) | ||
| and the parent document row (d) in a single CTE scan. Locking the document | ||
| prevents two concurrent workers from racing on the same document even when | ||
| separate ingestion jobs reference it (e.g. a retry and a re-queue arriving | ||
| simultaneously). SKIP LOCKED ensures a busy document is silently bypassed | ||
| rather than causing a block, giving other workers fair access.'; |
27 changes: 27 additions & 0 deletions
27 supabase/migrations/20260702110000_drop_redundant_indexes.sql
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| -- Fix #9: Drop redundant indexes. | ||
| -- | ||
| -- 1. documents_owner_hash_idx (owner_id, content_hash) is a plain non-unique | ||
| -- index whose column set is a strict subset of the UNIQUE partial index | ||
| -- documents_owner_content_hash_unique_idx (owner_id, content_hash WHERE | ||
| -- content_hash IS NOT NULL). The unique index is used for duplicate detection | ||
| -- (ON CONFLICT) and also satisfies all equality lookups on (owner_id, | ||
| -- content_hash). The plain index adds write overhead with no read benefit. | ||
| -- | ||
| -- NOTE: DROP INDEX CONCURRENTLY cannot run inside a transaction block. | ||
| -- Supabase migrations are wrapped in a transaction by default, which means | ||
| -- CONCURRENTLY is not available here. We use a plain DROP INDEX instead; | ||
| -- the table is small relative to write load and this is a one-time maintenance | ||
| -- operation. If you prefer zero-impact removal, run this statement manually in | ||
| -- the Supabase SQL editor outside a transaction: | ||
| -- DROP INDEX CONCURRENTLY IF EXISTS public.documents_owner_hash_idx; | ||
| drop index if exists public.documents_owner_hash_idx; | ||
| -- 2. ingestion_jobs_claim_idx covers (status, next_run_at, created_at) WHERE | ||
| -- status IN ('pending','processing'). The superset index | ||
| -- ingestion_jobs_status_next_run_idx covers the same columns with WHERE | ||
| -- status IN ('pending','processing','failed'). PostgreSQL can use the | ||
| -- superset index for any query the subset index would satisfy, so the subset | ||
| -- index is fully redundant once the superset exists. | ||
| drop index if exists public.ingestion_jobs_claim_idx; |
28 changes: 28 additions & 0 deletions
28 supabase/migrations/20260702120000_rag_retrieval_logs_retention.sql
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| -- Fix #6: Add retention policy for rag_retrieval_logs and document audit_logs intent. | ||
| -- | ||
| -- rag_queries already has a purge cron (20260629100000). rag_retrieval_logs has | ||
| -- no TTL. We add a matching cron to purge rows older than 90 days. | ||
| -- audit_logs is intentionally kept indefinitely (compliance requirement); add a | ||
| -- comment so this is self-documenting and not mistaken for an oversight. | ||
| comment on table public.audit_logs is | ||
| 'Append-only audit trail. Rows are retained indefinitely for compliance. | ||
| Writes are best-effort (fire-and-forget) from the application layer; a write | ||
| failure is swallowed and does not affect the calling request. | ||
| Do NOT add an automatic purge to this table without a compliance review.'; | ||
| comment on table public.rag_retrieval_logs is | ||
| 'Per-request retrieval telemetry. Rows older than 90 days are purged nightly | ||
| by the pg_cron job "purge-rag-retrieval-logs". Adjust the retention window | ||
| by changing the interval in that cron job definition.'; | ||
| -- Register the nightly purge cron job. | ||
| -- cron.schedule is idempotent on the job name; re-running this migration is safe. | ||
| select cron.schedule( | ||
| 'purge-rag-retrieval-logs', | ||
| '0 3 * * *', -- 03:00 UTC daily | ||
| $$ | ||
| delete from public.rag_retrieval_logs | ||
| where created_at < now() - interval '90 days'; | ||
| $$ | ||
| ); |
21 changes: 21 additions & 0 deletions
21 supabase/migrations/20260702130000_storage_cleanup_jobs_document_fk.sql
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| -- Fix #3: Add foreign key from storage_cleanup_jobs.document_id to documents(id). | ||
| -- | ||
| -- The column was declared as "uuid" with no referential constraint, meaning | ||
| -- orphaned rows (pointing to deleted documents) would accumulate silently. | ||
| -- We first delete any orphaned rows, then add ON DELETE SET NULL so future | ||
| -- document deletions leave the cleanup job record in place (the worker should | ||
| -- still attempt storage cleanup for any paths recorded before deletion). | ||
| -- Step 1: remove orphans (document_id is non-null but no matching document exists). | ||
| delete from public.storage_cleanup_jobs | ||
| where document_id is not null | ||
| and not exists ( | ||
| select 1 from public.documents d where d.id = storage_cleanup_jobs.document_id | ||
| ); | ||
BigSimmo marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| -- Step 2: add the FK constraint. | ||
| alter table public.storage_cleanup_jobs | ||
| add constraint storage_cleanup_jobs_document_id_fkey | ||
| foreign key (document_id) | ||
| references public.documents(id) | ||
BigSimmo marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| on delete set null; | ||
39 changes: 39 additions & 0 deletions
39 supabase/migrations/20260702140000_fix_reset_document_index_duplicate.sql
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| -- Fix #2: Remove duplicate/incomplete reset_document_index definition. | ||
| -- | ||
| -- schema.sql contained two definitions of reset_document_index. The first | ||
| -- (lines 1075-1091) did NOT delete from document_index_units. The second | ||
| -- (later in the file) does delete from document_index_units and is the | ||
| -- authoritative live version. Because CREATE OR REPLACE is last-write-wins, | ||
| -- the second definition is what the database actually runs. This migration | ||
| -- is a no-op CREATE OR REPLACE of the correct complete definition, making | ||
| -- migration history authoritative and preventing any future schema replay | ||
| -- from accidentally deploying the incomplete version first. | ||
| create or replace function public.reset_document_index(p_document_id uuid) | ||
| returns void | ||
| language plpgsql | ||
| set search_path = public, extensions, pg_temp | ||
| as $$ | ||
| begin | ||
| perform set_config('statement_timeout', '180000', true); | ||
| -- document_index_units must be deleted first (references document_chunks via FK). | ||
| delete from public.document_index_units where document_id = p_document_id; | ||
| delete from public.document_memory_cards where document_id = p_document_id; | ||
| delete from public.document_sections where document_id = p_document_id; | ||
| delete from public.document_table_facts where document_id = p_document_id; | ||
| delete from public.document_embedding_fields where document_id = p_document_id; | ||
| delete from public.document_index_quality where document_id = p_document_id; | ||
| delete from public.document_chunks where document_id = p_document_id; | ||
| delete from public.document_images where document_id = p_document_id; | ||
| delete from public.document_pages where document_id = p_document_id; | ||
| end; | ||
| $$; | ||
| -- Validation: confirm the function exists with the correct signature. | ||
| do $$ | ||
| begin | ||
| if to_regprocedure('public.reset_document_index(uuid)') is null then | ||
| raise exception 'reset_document_index(uuid) not found after migration'; | ||
| end if; | ||
| end; | ||
| $$; |
21 changes: 21 additions & 0 deletions
21 supabase/migrations/20260702150000_documents_owner_covering_index.sql
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| -- Fix #5: Add covering index for RLS correlated subquery on documents. | ||
| -- | ||
| -- Several tables (document_chunks, document_sections, document_memory_cards, | ||
| -- document_index_units, etc.) have RLS policies of the form: | ||
| -- | ||
| -- EXISTS (SELECT 1 FROM documents WHERE id = document_id AND owner_id = auth.uid()) | ||
| -- | ||
| -- The existing documents_owner_idx covers (owner_id) only, so PostgreSQL must | ||
| -- re-fetch the heap to confirm id = document_id. A composite index on | ||
| -- (owner_id, id) allows an index-only scan, eliminating the heap fetch. | ||
| -- The index is small (two uuid columns) and benefits every authenticated read | ||
| -- on the child tables. | ||
| -- | ||
| -- NOTE: CONCURRENTLY cannot run inside a transaction. | ||
| -- If you need a zero-lock creation on a loaded system, run this statement | ||
| -- manually outside a transaction: | ||
| -- CREATE INDEX CONCURRENTLY IF NOT EXISTS documents_owner_id_covering_idx | ||
| -- ON public.documents(owner_id, id); | ||
| create index if not exists documents_owner_id_covering_idx | ||
| on public.documents(owner_id, id); |
57 changes: 57 additions & 0 deletions
57 supabase/migrations/20260702160000_fix_invoke_agent_url_to_guc.sql
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| -- Fix #8: Replace hardcoded project URL in invoke_indexing_v3_agent with a | ||
| -- GUC-based setting, so the function works across all environments (staging, | ||
| -- production, local) without a code change. | ||
| -- | ||
| -- We store the base URL in a database-level GUC (app.indexing_v3_agent_base_url). | ||
| -- current_setting('app.indexing_v3_agent_base_url', true) returns NULL if the | ||
| -- GUC is not set, so the function retains the current project URL as its fallback, | ||
| -- meaning this change is fully backwards-compatible. | ||
| -- Set the default base URL for the current (production) project. | ||
| -- This value must be changed for staging/dev environments via: | ||
| -- ALTER DATABASE postgres SET app.indexing_v3_agent_base_url = '...'; | ||
| alter database postgres | ||
| set app.indexing_v3_agent_base_url = 'https://sjrfecxgysukkwxsowpy.supabase.co'; | ||
| create or replace function public.invoke_indexing_v3_agent(p_limit integer default 1) | ||
| returns bigint | ||
| language plpgsql | ||
| security definer | ||
| set search_path = public, extensions, vault, pg_temp | ||
| as $$ | ||
| declare | ||
| v_request_id bigint; | ||
| v_secret text; | ||
| v_base_url text; | ||
| begin | ||
| select decrypted_secret | ||
| into v_secret | ||
| from vault.decrypted_secrets | ||
| where name = 'indexing_v3_agent_secret' | ||
| limit 1; | ||
| if nullif(v_secret, '') is null then | ||
| raise exception 'indexing_v3_agent_secret is missing from Supabase Vault'; | ||
| end if; | ||
| -- Prefer the GUC; fall back to the hardcoded production URL so that | ||
| -- existing deployments that have not yet set the GUC continue to work. | ||
| v_base_url := coalesce( | ||
| nullif(current_setting('app.indexing_v3_agent_base_url', true), ''), | ||
| 'https://sjrfecxgysukkwxsowpy.supabase.co' | ||
| ); | ||
| select net.http_post( | ||
| url := v_base_url || '/functions/v1/indexing-v3-agent?limit=' | ||
| || greatest(1, least(coalesce(p_limit, 1), 10))::text, | ||
| headers := jsonb_build_object( | ||
| 'Content-Type', 'application/json', | ||
| 'x-indexing-agent-secret', v_secret | ||
| ), | ||
| body := jsonb_build_object('source', 'pg_cron', 'worker', 'v3-indexing-worker', 'ts', now()), | ||
| timeout_milliseconds := 60000 | ||
| ) into v_request_id; | ||
| return v_request_id; | ||
| end; | ||
| $$; |
Oops, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Oops, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
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.
Uh oh!
There was an error while loading. Please reload this page.