fix(ops): make Capgo-EU reclaim SQL Editor safe - #2733
Conversation
Drop VACUUM and psql \\gexec from the dashboard reclaim/verify path so the scripts can be pasted into Supabase SQL Editor; keep VACUUM as a psql-only follow-up. Co-authored-by: Cursor <cursoragent@cursor.com>
📝 WalkthroughWalkthroughThe PR updates Supabase swap operation scripts for SQL Editor compatibility, separates psql vacuum maintenance, adds a standalone HTTP-response truncation script, and replaces dynamic queue verification with explicit checks. ChangesSupabase swap operations
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Comment |
Merging this PR will not alter performance
Comparing Footnotes
|
|
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_5e37abde-8d64-4f36-8c71-50b891d454ce) |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@scripts/ops/reclaim_supabase_swap_truncate_http.sql`:
- Around line 1-5: Update the standalone reclaim statement around TRUNCATE TABLE
net._http_response to bound lock acquisition before truncating. Use a single DO
statement that sets local lock_timeout and statement_timeout values before
executing the truncate, or document the required client/session timeout directly
in this script while preserving its standalone execution requirement.
In `@scripts/ops/reclaim_supabase_swap.sql`:
- Around line 20-24: Update the preflight function-existence check in the
reclaim script to include cleanup_queue_messages() and cleanup_old_audit_logs(),
matching the functions invoked later by the script. Keep
cleanup_net_http_response() only if it is part of the migration’s required
contract, and preserve the existing exception behavior when any required
function is missing.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: b8cf108f-9e8b-4dde-99e9-8cd81837f95e
📒 Files selected for processing (5)
scripts/ops/reclaim_supabase_swap.sqlscripts/ops/reclaim_supabase_swap_index.sqlscripts/ops/reclaim_supabase_swap_truncate_http.sqlscripts/ops/reclaim_supabase_swap_vacuum.sqlscripts/ops/verify_supabase_swap.sql
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
Cap-go/capacitor-updater(manual)
| -- Capgo-EU immediate reclaim — safe for Supabase SQL Editor. | ||
| -- Single statement. Run alone. No migration required. | ||
| -- Frees net._http_response bloat (~5GB on Capgo-EU when empty/stale). | ||
|
|
||
| TRUNCATE TABLE net._http_response; |
There was a problem hiding this comment.
🩺 Stability & Availability | 🔵 Trivial
Bound lock acquisition for the standalone TRUNCATE.
Unlike reclaim_supabase_swap.sql, this one-statement variant has no lock_timeout or statement_timeout. A conflicting long-running transaction can leave SQL Editor waiting indefinitely. Document the required client/session timeout or replace the one-liner with a single DO statement that sets local timeouts before truncating.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/ops/reclaim_supabase_swap_truncate_http.sql` around lines 1 - 5,
Update the standalone reclaim statement around TRUNCATE TABLE net._http_response
to bound lock acquisition before truncating. Use a single DO statement that sets
local lock_timeout and statement_timeout values before executing the truncate,
or document the required client/session timeout directly in this script while
preserving its standalone execution requirement.
| IF to_regprocedure('public.null_migrated_app_version_manifests()') IS NULL | ||
| OR to_regprocedure('public.cleanup_net_http_response()') IS NULL THEN | ||
| RAISE EXCEPTION | ||
| 'Missing reclaim functions. Deploy migration 20260722082019_fix_supabase_swap_memory first.'; | ||
| END IF; |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Make the preflight match the functions this script invokes.
The check omits cleanup_queue_messages() and cleanup_old_audit_logs(), which are called at Lines 69 and 79. If either is missing, preflight passes and execution fails only after the TRUNCATE at Line 64. Add the missing checks; retain cleanup_net_http_response() only if the full migration contract requires it.
🔧 Proposed fix
IF to_regprocedure('public.null_migrated_app_version_manifests()') IS NULL
+ OR to_regprocedure('public.cleanup_queue_messages()') IS NULL
+ OR to_regprocedure('public.cleanup_old_audit_logs()') IS NULL
OR to_regprocedure('public.cleanup_net_http_response()') IS NULL THEN📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| IF to_regprocedure('public.null_migrated_app_version_manifests()') IS NULL | |
| OR to_regprocedure('public.cleanup_net_http_response()') IS NULL THEN | |
| RAISE EXCEPTION | |
| 'Missing reclaim functions. Deploy migration 20260722082019_fix_supabase_swap_memory first.'; | |
| END IF; | |
| IF to_regprocedure('public.null_migrated_app_version_manifests()') IS NULL | |
| OR to_regprocedure('public.cleanup_queue_messages()') IS NULL | |
| OR to_regprocedure('public.cleanup_old_audit_logs()') IS NULL | |
| OR to_regprocedure('public.cleanup_net_http_response()') IS NULL THEN | |
| RAISE EXCEPTION | |
| 'Missing reclaim functions. Deploy migration 20260722082019_fix_supabase_swap_memory first.'; | |
| END IF; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@scripts/ops/reclaim_supabase_swap.sql` around lines 20 - 24, Update the
preflight function-existence check in the reclaim script to include
cleanup_queue_messages() and cleanup_old_audit_logs(), matching the functions
invoked later by the script. Keep cleanup_net_http_response() only if it is part
of the migration’s required contract, and preserve the existing exception
behavior when any required function is missing.
There was a problem hiding this comment.
6 issues found across 5 files
Confidence score: 3/5
- In
scripts/ops/verify_supabase_swap.sql, queue verification now checks only four queues, so a run can appear clean while otherpgmqqueues still retain reclaimable rows; this can mask incomplete cleanup and leave backlog in production — restore verification coverage to all deployed queues (or generate checks dynamically frompgmq.list_queues()). - In
scripts/ops/reclaim_supabase_swap_truncate_http.sql, the standalone truncate path can block indefinitely behind locks/workers, causing SQL Editor runs to hang and operational reclaim steps to stall — apply the same lock/statement timeout guards as the full reclaim path. - In
scripts/ops/reclaim_supabase_swap_vacuum.sql, vacuuming only named queue pairs and waiting for notices to hit zero can leave dead tuples in other queues and allow bloat to accumulate between passes; this risks slower performance after reclaim — generate VACUUM targets frompgmq.list_queues()and run per-pass vacuuming instead of deferring. - In
scripts/ops/verify_supabase_swap.sqlandscripts/ops/reclaim_supabase_swap.sql, unbounded full-table manifest counting can add heavy production load, and a session-levelstatement_timeoutcan leak into later SQL Editor queries; together this can cause timeouts in both this workflow and unrelated follow-up work — bound the verification query and useSET LOCAL statement_timeout = '180s'for scoped limits.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="scripts/ops/reclaim_supabase_swap_truncate_http.sql">
<violation number="1" location="scripts/ops/reclaim_supabase_swap_truncate_http.sql:5">
P2: On a busy database, this standalone path can wait indefinitely behind an active query or pg_net worker and leave the SQL Editor run hanging. Adding the same lock and statement time bounds as the full reclaim path, or requiring them in the operator session, would keep this emergency script bounded.</violation>
</file>
<file name="scripts/ops/verify_supabase_swap.sql">
<violation number="1" location="scripts/ops/verify_supabase_swap.sql:54">
P2: Running this verification now scans every non-null manifest to produce an exact count, which can add substantial load or time out in SQL Editor on the production-sized `app_versions` table. Keeping this metric bounded like the existing sample, or making the global count a separate opt-in check, would keep the pasteable verification path lightweight.
(Based on your team's feedback about bounded verification queries.) [FEEDBACK_USED].</violation>
<violation number="2" location="scripts/ops/verify_supabase_swap.sql:96">
P2: Queue verification now reports only four queues, so the SQL Editor run can show a clean result while other deployed pgmq queues still contain rows that `cleanup_queue_messages()` is expected to reclaim. Preserving the all-queue coverage through SQL-Editor-compatible dynamic SQL, or explicitly covering every deployed queue, would avoid this false negative.</violation>
</file>
<file name="scripts/ops/reclaim_supabase_swap.sql">
<violation number="1" location="scripts/ops/reclaim_supabase_swap.sql:13">
P3: A successful run can leak the new 180-second timeout into a reused SQL Editor session, causing later unrelated queries to fail after 180 seconds. `SET LOCAL statement_timeout = '180s'` would constrain the limit to this pasted transaction instead of changing the session.</violation>
</file>
<file name="scripts/ops/reclaim_supabase_swap_vacuum.sql">
<violation number="1" location="scripts/ops/reclaim_supabase_swap_vacuum.sql:2">
P2: Cleanup functions are capped per invocation, so a non-zero SQL Editor pass commits dead tuples before the next pass; waiting for notices to reach 0 lets bloat accumulate during a reclaim. The runbook should run this psql file after every reclaim pass, then rerun the full reclaim script until the notices are 0.
(Based on your team's feedback about rerunning the full reclaim script after cleanup batches.) [FEEDBACK_USED]</violation>
<violation number="2" location="scripts/ops/reclaim_supabase_swap_vacuum.sql:7">
P2: The reclaim step cleans every `pgmq.list_queues()` queue, but this file vacuums only the four named queue pairs, leaving other queues' deleted rows unreclaimed. Generating the VACUUM statements from `pgmq.list_queues()` would keep this psql-only script aligned with `cleanup_queue_messages()`.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| -- Single statement. Run alone. No migration required. | ||
| -- Frees net._http_response bloat (~5GB on Capgo-EU when empty/stale). | ||
|
|
||
| TRUNCATE TABLE net._http_response; |
There was a problem hiding this comment.
P2: On a busy database, this standalone path can wait indefinitely behind an active query or pg_net worker and leave the SQL Editor run hanging. Adding the same lock and statement time bounds as the full reclaim path, or requiring them in the operator session, would keep this emergency script bounded.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/ops/reclaim_supabase_swap_truncate_http.sql, line 5:
<comment>On a busy database, this standalone path can wait indefinitely behind an active query or pg_net worker and leave the SQL Editor run hanging. Adding the same lock and statement time bounds as the full reclaim path, or requiring them in the operator session, would keep this emergency script bounded.</comment>
<file context>
@@ -0,0 +1,5 @@
+-- Single statement. Run alone. No migration required.
+-- Frees net._http_response bloat (~5GB on Capgo-EU when empty/stale).
+
+TRUNCATE TABLE net._http_response;
</file context>
| SELECT count(*)::bigint AS non_null_manifest_versions | ||
| FROM public.app_versions | ||
| WHERE manifest IS NOT NULL; | ||
|
|
There was a problem hiding this comment.
P2: Running this verification now scans every non-null manifest to produce an exact count, which can add substantial load or time out in SQL Editor on the production-sized app_versions table. Keeping this metric bounded like the existing sample, or making the global count a separate opt-in check, would keep the pasteable verification path lightweight.
(Based on your team's feedback about bounded verification queries.) .
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/ops/verify_supabase_swap.sql, line 54:
<comment>Running this verification now scans every non-null manifest to produce an exact count, which can add substantial load or time out in SQL Editor on the production-sized `app_versions` table. Keeping this metric bounded like the existing sample, or making the global count a separate opt-in check, would keep the pasteable verification path lightweight.
(Based on your team's feedback about bounded verification queries.) .</comment>
<file context>
@@ -52,6 +51,10 @@ FROM (
)
) AS eligible;
+SELECT count(*)::bigint AS non_null_manifest_versions
+FROM public.app_versions
+WHERE manifest IS NOT NULL;
</file context>
| SELECT count(*)::bigint AS non_null_manifest_versions | |
| FROM public.app_versions | |
| WHERE manifest IS NOT NULL; | |
| SELECT count(*)::bigint AS non_null_manifest_versions_sample | |
| FROM ( | |
| SELECT 1 | |
| FROM public.app_versions | |
| WHERE manifest IS NOT NULL | |
| ORDER BY id | |
| LIMIT 1000 | |
| ) AS sample; |
| ) | ||
| FROM pgmq.list_queues() | ||
| \gexec | ||
| -- Fixed Capgo-EU queue set (no psql \gexec). |
There was a problem hiding this comment.
P2: Queue verification now reports only four queues, so the SQL Editor run can show a clean result while other deployed pgmq queues still contain rows that cleanup_queue_messages() is expected to reclaim. Preserving the all-queue coverage through SQL-Editor-compatible dynamic SQL, or explicitly covering every deployed queue, would avoid this false negative.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/ops/verify_supabase_swap.sql, line 96:
<comment>Queue verification now reports only four queues, so the SQL Editor run can show a clean result while other deployed pgmq queues still contain rows that `cleanup_queue_messages()` is expected to reclaim. Preserving the all-queue coverage through SQL-Editor-compatible dynamic SQL, or explicitly covering every deployed queue, would avoid this false negative.</comment>
<file context>
@@ -82,33 +93,44 @@ SELECT EXISTS (
-)
-FROM pgmq.list_queues()
-\gexec
+-- Fixed Capgo-EU queue set (no psql \gexec).
+SELECT 'a_on_manifest_create' AS queue_name,
+ EXISTS (
</file context>
| VACUUM (VERBOSE) pgmq.a_on_version_update; | ||
| VACUUM (VERBOSE) pgmq.a_on_manifest_create; | ||
| VACUUM (VERBOSE) pgmq.a_webhook_dispatcher; | ||
| VACUUM (VERBOSE) pgmq.a_on_channel_update; | ||
| VACUUM (VERBOSE) pgmq.q_on_version_update; | ||
| VACUUM (VERBOSE) pgmq.q_on_manifest_create; | ||
| VACUUM (VERBOSE) pgmq.q_webhook_dispatcher; | ||
| VACUUM (VERBOSE) pgmq.q_on_channel_update; |
There was a problem hiding this comment.
P2: The reclaim step cleans every pgmq.list_queues() queue, but this file vacuums only the four named queue pairs, leaving other queues' deleted rows unreclaimed. Generating the VACUUM statements from pgmq.list_queues() would keep this psql-only script aligned with cleanup_queue_messages().
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/ops/reclaim_supabase_swap_vacuum.sql, line 7:
<comment>The reclaim step cleans every `pgmq.list_queues()` queue, but this file vacuums only the four named queue pairs, leaving other queues' deleted rows unreclaimed. Generating the VACUUM statements from `pgmq.list_queues()` would keep this psql-only script aligned with `cleanup_queue_messages()`.</comment>
<file context>
@@ -0,0 +1,22 @@
+-- Example:
+-- psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f scripts/ops/reclaim_supabase_swap_vacuum.sql
+
+VACUUM (VERBOSE) pgmq.a_on_version_update;
+VACUUM (VERBOSE) pgmq.a_on_manifest_create;
+VACUUM (VERBOSE) pgmq.a_webhook_dispatcher;
</file context>
| VACUUM (VERBOSE) pgmq.a_on_version_update; | |
| VACUUM (VERBOSE) pgmq.a_on_manifest_create; | |
| VACUUM (VERBOSE) pgmq.a_webhook_dispatcher; | |
| VACUUM (VERBOSE) pgmq.a_on_channel_update; | |
| VACUUM (VERBOSE) pgmq.q_on_version_update; | |
| VACUUM (VERBOSE) pgmq.q_on_manifest_create; | |
| VACUUM (VERBOSE) pgmq.q_webhook_dispatcher; | |
| VACUUM (VERBOSE) pgmq.q_on_channel_update; | |
| SELECT pg_catalog.format('VACUUM (VERBOSE) pgmq.%I', 'a_' || q.queue_name) | |
| FROM pgmq.list_queues() AS q | |
| \gexec | |
| SELECT pg_catalog.format('VACUUM (VERBOSE) pgmq.%I', 'q_' || q.queue_name) | |
| FROM pgmq.list_queues() AS q | |
| \gexec |
| @@ -0,0 +1,22 @@ | |||
| -- Optional Capgo-EU reclaim VACUUM — psql only (NOT SQL Editor). | |||
| -- Run after scripts/ops/reclaim_supabase_swap.sql when deleted/updated notices are 0. | |||
There was a problem hiding this comment.
P2: Cleanup functions are capped per invocation, so a non-zero SQL Editor pass commits dead tuples before the next pass; waiting for notices to reach 0 lets bloat accumulate during a reclaim. The runbook should run this psql file after every reclaim pass, then rerun the full reclaim script until the notices are 0.
(Based on your team's feedback about rerunning the full reclaim script after cleanup batches.)
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/ops/reclaim_supabase_swap_vacuum.sql, line 2:
<comment>Cleanup functions are capped per invocation, so a non-zero SQL Editor pass commits dead tuples before the next pass; waiting for notices to reach 0 lets bloat accumulate during a reclaim. The runbook should run this psql file after every reclaim pass, then rerun the full reclaim script until the notices are 0.
(Based on your team's feedback about rerunning the full reclaim script after cleanup batches.) </comment>
<file context>
@@ -0,0 +1,22 @@
+-- Optional Capgo-EU reclaim VACUUM — psql only (NOT SQL Editor).
+-- Run after scripts/ops/reclaim_supabase_swap.sql when deleted/updated notices are 0.
+--
+-- Example:
</file context>
| -- Run after scripts/ops/reclaim_supabase_swap.sql when deleted/updated notices are 0. | |
| -- Run after every scripts/ops/reclaim_supabase_swap.sql pass; rerun the reclaim script until deleted/updated notices are 0. |
| -- Optional later via psql: scripts/ops/reclaim_supabase_swap_vacuum.sql | ||
|
|
||
| SET lock_timeout = '5s'; | ||
| SET statement_timeout = '180s'; |
There was a problem hiding this comment.
P3: A successful run can leak the new 180-second timeout into a reused SQL Editor session, causing later unrelated queries to fail after 180 seconds. SET LOCAL statement_timeout = '180s' would constrain the limit to this pasted transaction instead of changing the session.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/ops/reclaim_supabase_swap.sql, line 13:
<comment>A successful run can leak the new 180-second timeout into a reused SQL Editor session, causing later unrelated queries to fail after 180 seconds. `SET LOCAL statement_timeout = '180s'` would constrain the limit to this pasted transaction instead of changing the session.</comment>
<file context>
@@ -1,26 +1,28 @@
+-- Optional later via psql: scripts/ops/reclaim_supabase_swap_vacuum.sql
SET lock_timeout = '5s';
+SET statement_timeout = '180s';
-- ---------------------------------------------------------------------------
</file context>
| SET statement_timeout = '180s'; | |
| SET LOCAL statement_timeout = '180s'; |





Summary (AI generated)
scripts/ops/reclaim_supabase_swap.sqlandverify_supabase_swap.sqlsafe to paste into Supabase SQL Editor (noVACUUM, no\\gexec)VACUUMtoreclaim_supabase_swap_vacuum.sql(psql-only)reclaim_supabase_swap_truncate_http.sqlfor immediatenet._http_responsereclaimMotivation (AI generated)
SQL Editor wraps multi-statement runs in a transaction, so
VACUUM/CREATE INDEX CONCURRENTLY/ psql meta-commands fail. Ops needs a dashboard-runnable reclaim path.Business Impact (AI generated)
Unblocks Capgo-EU swap reclaim from the dashboard after migrations are deployed.
Test Plan (AI generated)
reclaim_supabase_swap_truncate_http.sqlin Capgo-EU SQL Editor and confirmnet._http_responsesize dropsreclaim_supabase_swap.sql, re-run until notices are 0verify_supabase_swap.sqland confirm sizes/cron/index checksGenerated with AI
Made with Cursor
Summary by CodeRabbit
New Features
Bug Fixes