fix(db): skip app_versions bookkeeping in audit_logs - #2760
Conversation
Stop writing upload/migrate pipeline noise (manifest, manifest_count, r2_path, storage_provider, updated_at-only) into audit TOAST, and delete matching historical rows. Keep soft-delete and real user-facing edits. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 12 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe audit trigger now attributes actors, detects changed fields, skips bookkeeping-only updates, strips large app-version payload fields, and preserves meaningful audit events. Tests cover migration finalization, storage-field updates, and soft deletes. ChangesAudit logging
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
Suggested labels: Suggested reviewers: Sequence Diagram(s)sequenceDiagram
participant app_versions
participant audit_log_trigger
participant audit_logs
app_versions->>audit_log_trigger: Update version row
audit_log_trigger->>audit_log_trigger: Resolve actor and compare fields
audit_log_trigger->>audit_log_trigger: Skip bookkeeping-only changes or slim payload
audit_log_trigger->>audit_logs: Insert row for auditable changes
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Comment |
Merging this PR will not alter performance
Comparing Footnotes
|
Co-authored-by: Cursor <cursoragent@cursor.com>
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_10c1c3cc-f370-491f-8b3f-b206b1c95c38) |
Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Stale comment
Risk: high. Not approving: Cursor Bugbot skipped (usage limit reached), so automated review did not complete. This migration also changes audit trigger behavior and deletes historical audit_logs rows, which exceeds the low-risk approval threshold. Human review is needed.
Sent by Cursor Approval Agent: Pull Request Approver External
Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
All reported issues were addressed
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
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_79031104-c558-43fd-95fc-a04a7ce55963) |
There was a problem hiding this comment.
Stale comment
Risk: high. Not approving: Cursor Bugbot skipped (usage limit reached), so automated review did not complete. This migration changes audit trigger behavior and deletes historical audit_logs rows, which exceeds the low-risk approval threshold. Human review is needed; reviewers are already assigned.
Sent by Cursor Approval Agent: Pull Request Approver External
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@supabase/migrations/20260725163259_slim_audit_logs_skip_bookkeeping.sql`:
- Line 4: Update the historical-cleanup comment in the migration to comply with
SQLFluff’s line-length limit by wrapping the text across additional comment
lines, while preserving its meaning.
🪄 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: 01696ae2-5385-4d19-8ba2-ec852d815c50
📒 Files selected for processing (1)
supabase/migrations/20260725163259_slim_audit_logs_skip_bookkeeping.sql
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
Cap-go/capacitor-updater(manual)
There was a problem hiding this comment.
All reported issues were addressed across 1 file (changes from recent commits).
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Co-authored-by: Cursor <cursoragent@cursor.com>
Avoid NEW.column references that break the shared audit trigger on apps/orgs/channels during migration apply. Co-authored-by: Cursor <cursoragent@cursor.com>
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_10bdf57f-22a6-46d6-bf94-ce6e444cf3ac) |
There was a problem hiding this comment.
Stale comment
Risk: medium. Not approving: Cursor Bugbot was present but skipped (usage limit reached), so automated review did not complete. This migration changes
audit_log_triggerbehavior, which exceeds the low-risk approval threshold; Dalanir and WcaleNieWolny are already assigned for human review.Sent by Cursor Approval Agent: Pull Request Approver External
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@supabase/migrations/20260725163259_slim_audit_logs_skip_bookkeeping.sql`:
- Around line 75-90: Remove native_packages from the excluded-field lists in the
comparison between v_old_record and v_new_record, while continuing to exclude
the other bookkeeping fields. Preserve any later logic that removes
native_packages from the persisted audit JSON.
🪄 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: 1e8bb0b6-8f2c-48e3-9a79-90cd259f5137
📒 Files selected for processing (1)
supabase/migrations/20260725163259_slim_audit_logs_skip_bookkeeping.sql
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
Cap-go/capacitor-updater(manual)
Do not treat native_packages-only updates as bookkeeping skips; still strip that fat column from persisted audit JSON. Co-authored-by: Cursor <cursoragent@cursor.com>
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_ade9808f-bb0a-4e34-b146-a2e14a22e671) |
There was a problem hiding this comment.
Stale comment
Risk: medium. Not approving: Cursor Bugbot was present but skipped (usage limit reached), so automated review did not complete. This migration changes
audit_log_triggerbehavior, which exceeds the low-risk approval threshold; Dalanir and WcaleNieWolny are already assigned for human review.Sent by Cursor Approval Agent: Pull Request Approver External
There was a problem hiding this comment.
2 issues found across 1 file (changes from recent commits).
Confidence score: 3/5
- In
supabase/migrations/20260725163259_slim_audit_logs_skip_bookkeeping.sql, the bookkeeping-only fast path still serializes fullmanifest/native_packagesrows before returning, so the intended optimization may not reduce hot-path TOAST CPU/memory pressure as expected — keep the pre-skip comparison on cheap fields and avoid full-row JSONB materialization before the return. - In
supabase/migrations/20260725163259_slim_audit_logs_skip_bookkeeping.sql, the early-return guard always runsto_jsonb(OLD/NEW)even when user-facing changes mean the check fails, which can add avoidable serialization overhead on normal updates and blunt performance gains — restructure the guard to use lightweight comparisons first and only serialize when actually needed for auditing.
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="supabase/migrations/20260725163259_slim_audit_logs_skip_bookkeeping.sql">
<violation number="1" location="supabase/migrations/20260725163259_slim_audit_logs_skip_bookkeeping.sql:73">
P2: Bookkeeping-only updates still serialize the full `manifest` and `native_packages` rows before returning, so the hot path retains the TOAST CPU/memory work this skip is intended to avoid. Keep the pre-skip comparison column-based (or otherwise exclude fat values before conversion) and only build audit JSON after determining that an audit is needed.</violation>
<violation number="2" location="supabase/migrations/20260725163259_slim_audit_logs_skip_bookkeeping.sql:73">
P2: The early-return check for bookkeeping-only updates unconditionally serializes OLD and NEW to JSONB via `to_jsonb()`. When a user-facing field change (comment, checksum, etc.) causes the check to not match, the function falls through to the generic ELSE branch which serializes both rows to JSONB a second time. Since `manifest` is a custom array type (`manifest_entry[]`) that can hold thousands of entries per AGENTS.md, this double-serialization adds unnecessary CPU/memory overhead to every user-facing UPDATE on `app_versions`.
Consider restructuring the early-return check inside the existing ELSE branch so that the `to_jsonb` call happens exactly once — the serialized value is then reused for both the bookkeeping comparison and the changed_fields walk. This avoids redundant work and recovers the performance characteristic the previous column-comparison approach had for the non-skipped path.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
| -- changed_fields walk. Compare via to_jsonb only (this trigger is shared across | ||
| -- tables; never touch NEW.column names that only exist on app_versions). | ||
| IF TG_OP = 'UPDATE' AND TG_TABLE_NAME = 'app_versions' THEN | ||
| v_old_record := pg_catalog.to_jsonb(OLD); |
There was a problem hiding this comment.
P2: Bookkeeping-only updates still serialize the full manifest and native_packages rows before returning, so the hot path retains the TOAST CPU/memory work this skip is intended to avoid. Keep the pre-skip comparison column-based (or otherwise exclude fat values before conversion) and only build audit JSON after determining that an audit is needed.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At supabase/migrations/20260725163259_slim_audit_logs_skip_bookkeeping.sql, line 73:
<comment>Bookkeeping-only updates still serialize the full `manifest` and `native_packages` rows before returning, so the hot path retains the TOAST CPU/memory work this skip is intended to avoid. Keep the pre-skip comparison column-based (or otherwise exclude fat values before conversion) and only build audit JSON after determining that an audit is needed.</comment>
<file context>
@@ -66,34 +66,29 @@ BEGIN
+ -- changed_fields walk. Compare via to_jsonb only (this trigger is shared across
+ -- tables; never touch NEW.column names that only exist on app_versions).
+ IF TG_OP = 'UPDATE' AND TG_TABLE_NAME = 'app_versions' THEN
+ v_old_record := pg_catalog.to_jsonb(OLD);
+ v_new_record := pg_catalog.to_jsonb(NEW);
+ IF (
</file context>
| -- changed_fields walk. Compare via to_jsonb only (this trigger is shared across | ||
| -- tables; never touch NEW.column names that only exist on app_versions). | ||
| IF TG_OP = 'UPDATE' AND TG_TABLE_NAME = 'app_versions' THEN | ||
| v_old_record := pg_catalog.to_jsonb(OLD); |
There was a problem hiding this comment.
P2: The early-return check for bookkeeping-only updates unconditionally serializes OLD and NEW to JSONB via to_jsonb(). When a user-facing field change (comment, checksum, etc.) causes the check to not match, the function falls through to the generic ELSE branch which serializes both rows to JSONB a second time. Since manifest is a custom array type (manifest_entry[]) that can hold thousands of entries per AGENTS.md, this double-serialization adds unnecessary CPU/memory overhead to every user-facing UPDATE on app_versions.
Consider restructuring the early-return check inside the existing ELSE branch so that the to_jsonb call happens exactly once — the serialized value is then reused for both the bookkeeping comparison and the changed_fields walk. This avoids redundant work and recovers the performance characteristic the previous column-comparison approach had for the non-skipped path.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At supabase/migrations/20260725163259_slim_audit_logs_skip_bookkeeping.sql, line 73:
<comment>The early-return check for bookkeeping-only updates unconditionally serializes OLD and NEW to JSONB via `to_jsonb()`. When a user-facing field change (comment, checksum, etc.) causes the check to not match, the function falls through to the generic ELSE branch which serializes both rows to JSONB a second time. Since `manifest` is a custom array type (`manifest_entry[]`) that can hold thousands of entries per AGENTS.md, this double-serialization adds unnecessary CPU/memory overhead to every user-facing UPDATE on `app_versions`.
Consider restructuring the early-return check inside the existing ELSE branch so that the `to_jsonb` call happens exactly once — the serialized value is then reused for both the bookkeeping comparison and the changed_fields walk. This avoids redundant work and recovers the performance characteristic the previous column-comparison approach had for the non-skipped path.</comment>
<file context>
@@ -66,34 +66,29 @@ BEGIN
+ -- changed_fields walk. Compare via to_jsonb only (this trigger is shared across
+ -- tables; never touch NEW.column names that only exist on app_versions).
+ IF TG_OP = 'UPDATE' AND TG_TABLE_NAME = 'app_versions' THEN
+ v_old_record := pg_catalog.to_jsonb(OLD);
+ v_new_record := pg_catalog.to_jsonb(NEW);
+ IF (
</file context>
There was a problem hiding this comment.
2 issues found and verified against the latest diff
Confidence score: 3/5
- In
supabase/migrations/20260725163259_slim_audit_logs_skip_bookkeeping.sql, the current skip logic appears too broad and can suppress audit rows for manifest create/correct operations andnative_packages-only edits, which weakens traceability and can hide real change history — narrow the condition to only the non-NULL→NULL manifest transition as noted. - In
supabase/migrations/20260725163259_slim_audit_logs_skip_bookkeeping.sql, the SECURITY DEFINER function’s execution rights may remain overly permissive if prior grants persist, creating avoidable exposure on a privileged entry point — explicitly REVOKE from PUBLIC and GRANT EXECUTE only toservice_rolein this migration.
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="supabase/migrations/20260725163259_slim_audit_logs_skip_bookkeeping.sql">
<violation number="1" location="supabase/migrations/20260725163259_slim_audit_logs_skip_bookkeeping.sql:77">
P2: Manifest creation/correction and native_packages-only edits now disappear from audit history, not just the reclaim write. Restrict the skip to the non-NULL-to-NULL manifest transition and leave native_packages outside the ignored set.
(Based on your team's feedback about preserving native_packages audit field history.) [FEEDBACK_USED]</violation>
<violation number="2" location="supabase/migrations/20260725163259_slim_audit_logs_skip_bookkeeping.sql:203">
P2: Function privileges remain whatever the target database previously had because this migration only changes ownership. Revoke PUBLIC and grant EXECUTE only to service_role so this SECURITY DEFINER entry point has an enforced, self-contained ACL.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| $$; | ||
|
|
||
|
|
||
| ALTER FUNCTION "public"."audit_log_trigger"() OWNER TO "postgres"; |
There was a problem hiding this comment.
P2: Function privileges remain whatever the target database previously had because this migration only changes ownership. Revoke PUBLIC and grant EXECUTE only to service_role so this SECURITY DEFINER entry point has an enforced, self-contained ACL.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At supabase/migrations/20260725163259_slim_audit_logs_skip_bookkeeping.sql, line 205:
<comment>Function privileges remain whatever the target database previously had because this migration only changes ownership. Revoke PUBLIC and grant EXECUTE only to service_role so this SECURITY DEFINER entry point has an enforced, self-contained ACL.</comment>
<file context>
@@ -0,0 +1,205 @@
+$$;
+
+
+ALTER FUNCTION "public"."audit_log_trigger"() OWNER TO "postgres";
</file context>
| v_new_record := pg_catalog.to_jsonb(NEW); | ||
| IF ( | ||
| v_old_record | ||
| - 'manifest' |
There was a problem hiding this comment.
P2: Manifest creation/correction and native_packages-only edits now disappear from audit history, not just the reclaim write. Restrict the skip to the non-NULL-to-NULL manifest transition and leave native_packages outside the ignored set.
(Based on your team's feedback about preserving native_packages audit field history.)
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At supabase/migrations/20260725163259_slim_audit_logs_skip_bookkeeping.sql, line 77:
<comment>Manifest creation/correction and native_packages-only edits now disappear from audit history, not just the reclaim write. Restrict the skip to the non-NULL-to-NULL manifest transition and leave native_packages outside the ignored set.
(Based on your team's feedback about preserving native_packages audit field history.) </comment>
<file context>
@@ -0,0 +1,205 @@
+ v_new_record := pg_catalog.to_jsonb(NEW);
+ IF (
+ v_old_record
+ - 'manifest'
+ - 'native_packages'
+ - 'updated_at'
</file context>
|
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_f611439d-c8b2-4777-a844-cbd479a2b31e) |
There was a problem hiding this comment.
Risk: medium. Not approving: Cursor Bugbot was present but skipped (usage limit reached), so automated review did not complete. This migration changes audit_log_trigger behavior, which exceeds the low-risk approval threshold; Dalanir and WcaleNieWolny are already assigned for human review.
Sent by Cursor Approval Agent: Pull Request Approver External
There was a problem hiding this comment.
1 issue found across 2 files
Confidence score: 4/5
- In
supabase/migrations/20260725163259_slim_audit_logs_skip_bookkeeping.sql, the migration only stops future bookkeeping audit writes and leaves existing rows intact, so the historical TOAST/storage bloat called out in the PR remains and expected space/perf gains may not materialize; add the promised historical cleanup/backfill step in this migration (or a paired follow-up migration).
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="supabase/migrations/20260725163259_slim_audit_logs_skip_bookkeeping.sql">
<violation number="1" location="supabase/migrations/20260725163259_slim_audit_logs_skip_bookkeeping.sql:4">
P2: Existing bookkeeping audit rows are left untouched, so this migration only prevents future writes and does not remove the historical TOAST footprint described in the PR. The migration should include the promised historical cleanup, or ship an explicit, bounded rollout step that is guaranteed to run alongside it.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| -- Slim audit_logs: do not store internal app_versions upload/migrate bookkeeping. | ||
| -- Capgo-EU evidence: r2_path/storage_provider/manifest pipeline updates were hundreds | ||
| -- of MB of TOAST with no user-facing audit value. Soft-delete and real edits stay. | ||
| -- Historical cleanup stays out of this migration to avoid a WAL/lock storm. |
There was a problem hiding this comment.
P2: Existing bookkeeping audit rows are left untouched, so this migration only prevents future writes and does not remove the historical TOAST footprint described in the PR. The migration should include the promised historical cleanup, or ship an explicit, bounded rollout step that is guaranteed to run alongside it.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At supabase/migrations/20260725163259_slim_audit_logs_skip_bookkeeping.sql, line 4:
<comment>Existing bookkeeping audit rows are left untouched, so this migration only prevents future writes and does not remove the historical TOAST footprint described in the PR. The migration should include the promised historical cleanup, or ship an explicit, bounded rollout step that is guaranteed to run alongside it.</comment>
<file context>
@@ -0,0 +1,203 @@
+-- Slim audit_logs: do not store internal app_versions upload/migrate bookkeeping.
+-- Capgo-EU evidence: r2_path/storage_provider/manifest pipeline updates were hundreds
+-- of MB of TOAST with no user-facing audit value. Soft-delete and real edits stay.
+-- Historical cleanup stays out of this migration to avoid a WAL/lock storm.
+-- Run bounded ops deletes separately if needed.
+
</file context>





Summary (AI generated)
audit_log_triggersoapp_versionsUPDATEs that only touch upload/migrate bookkeeping fields are not written toaudit_logsmanifest,manifest_count,storage_provider,r2_path,updated_atcomment,checksum,deleted, etc.)tests/cleanup_swap_memory.test.tsMotivation (AI generated)
Capgo-EU
audit_logstoast was dominating Postgresshared_buffers(~63% / ~1.3 GB). Live breakdown showed most of the fat was internal pipeline noise (r2_path,storage_provider, dual-storagemanifest/manifest_countupdates), not console user actions. Storing that TOAST for ~800 active users is pure waste and thrash.Business Impact (AI generated)
Reduces primary DB memory/disk pressure without changing customer-visible audit for deletes and intentional version edits. Improves stability of Capgo-EU under current compute size.
Test Plan (AI generated)
bun run supabase:with-env -- bunx vitest run tests/cleanup_swap_memory.test.tsr2_path/storage_provider/ dual-storage finalize UPDATEs do not create audit rowsGenerated with AI
Made with Cursor
Summary by CodeRabbit
Bug Fixes
Tests