|
| 1 | +-- One-time cleanup of legacy `system:`-authored blocks (pre-c0d606f6 mints). |
| 2 | +-- |
| 3 | +-- EXECUTED 2026-06-14 against prod: 787 rows zeroed + de-prefixed (verified |
| 4 | +-- remaining=0, zeroed=787); converged on all bridge-connected devices. The e2ee |
| 5 | +-- workspace + mobile converge on their next sync. Rollback source: |
| 6 | +-- blocks_system_backup_20260614 (drop it once clients confirm sync). |
| 7 | +-- |
| 8 | +-- Strips the `system:` prefix from `updated_by` (restoring a plain user-pair |
| 9 | +-- author) and re-stamps the row to the `updated_at = 0` pristine sentinel, so it |
| 10 | +-- re-replicates and converges EVERY device — including any shadowed copy on a |
| 11 | +-- client we can't inspect (an e2ee workspace / mobile) — via the stamp-0 exemption. |
| 12 | +-- `user_updated_at` is captured BEFORE zeroing so display "last edited" survives. |
| 13 | +-- |
| 14 | +-- WHY ZEROING (not a +1 touch): a 0-stamped server row loses to no nonzero local |
| 15 | +-- stamp, so under the CURRENT indiscriminate gate every device yields to it |
| 16 | +-- regardless of its local stamp — healing even a competing-newer-default shadow. |
| 17 | +-- |
| 18 | +-- ORDERING: this MUST run, and converge on every device, BEFORE PR #151 (the |
| 19 | +-- hardened gate) merges. The hardened gate skip-stales a 0-stamped row over a |
| 20 | +-- nonzero local (`local >= 0`), so if it ships first the zero never lands. |
| 21 | +-- |
| 22 | +-- PRE-REQS: every device's upload queue drained (`ps_crud → 0`, incl. the e2ee |
| 23 | +-- workspace + mobile) — a queued edit at run time would race the zero. `e2ee_plaintext_risk` |
| 24 | +-- below must be 0 (the e2ee ciphertext trigger stays ENABLED and would abort the |
| 25 | +-- UPDATE on a plaintext-content row in an e2ee workspace). |
| 26 | +-- |
| 27 | +-- RUN: psql "$PS_DATABASE_URI" -f scripts/system-author-cleanup.sql |
| 28 | +-- (connects as the blocks table owner — required to toggle triggers; the |
| 29 | +-- Supabase Management API can't run this transactional DDL. $PS_DATABASE_URI |
| 30 | +-- is sourced from .env.local.) |
| 31 | + |
| 32 | +\set ON_ERROR_STOP on |
| 33 | + |
| 34 | +-- ── Pre-check (read-only) — eyeball before the write ───────────────────────── |
| 35 | +\echo '── pre-check: system: census + e2ee-plaintext risk (must be 0) ──' |
| 36 | +SELECT count(*) AS total, |
| 37 | + count(*) FILTER (WHERE updated_at <> 0) AS nonzero, |
| 38 | + (SELECT count(*) FROM blocks b JOIN workspaces w ON w.id = b.workspace_id |
| 39 | + WHERE b.updated_by LIKE 'system:%' AND w.encryption_mode = 'e2ee' |
| 40 | + AND b.content NOT LIKE 'enc:v1:%') AS e2ee_plaintext_risk |
| 41 | + FROM blocks WHERE updated_by LIKE 'system:%'; |
| 42 | + |
| 43 | +-- ── Backup snapshot (rollback source; committed, outside the txn) ──────────── |
| 44 | +DROP TABLE IF EXISTS blocks_system_backup_20260614; |
| 45 | +CREATE TABLE blocks_system_backup_20260614 AS |
| 46 | + SELECT id, updated_at, updated_by, user_updated_at |
| 47 | + FROM blocks WHERE updated_by LIKE 'system:%'; |
| 48 | +\echo '── backup rows captured ──' |
| 49 | +SELECT count(*) AS backed_up FROM blocks_system_backup_20260614; |
| 50 | + |
| 51 | +-- ── Cleanup (one transaction; DDL is transactional, so a failure rolls back |
| 52 | +-- the trigger toggles too and leaves them ENABLED) ────────────────────────── |
| 53 | +BEGIN; |
| 54 | +ALTER TABLE public.blocks DISABLE TRIGGER blocks_clamp_updated_at_trg; -- else the floor pins updated_at back up and 0 never lands |
| 55 | +ALTER TABLE public.blocks DISABLE TRIGGER blocks_record_history_trg; -- don't record a stamp "downgrade" in history |
| 56 | + |
| 57 | +UPDATE blocks |
| 58 | + SET user_updated_at = COALESCE(user_updated_at, updated_at), -- preserve display stamp (RHS reads OLD values) |
| 59 | + updated_at = 0, -- pristine sentinel |
| 60 | + updated_by = substring(updated_by FROM length('system:') + 1) -- strip 'system:' prefix |
| 61 | + WHERE updated_by LIKE 'system:%'; |
| 62 | + |
| 63 | +ALTER TABLE public.blocks ENABLE TRIGGER blocks_record_history_trg; |
| 64 | +ALTER TABLE public.blocks ENABLE TRIGGER blocks_clamp_updated_at_trg; |
| 65 | +COMMIT; |
| 66 | + |
| 67 | +-- ── Post-commit verify (expect remaining = 0, zeroed = backed_up) ──────────── |
| 68 | +\echo '── verify ──' |
| 69 | +SELECT |
| 70 | + (SELECT count(*) FROM blocks WHERE updated_by LIKE 'system:%') AS remaining_system, |
| 71 | + (SELECT count(*) FROM blocks b JOIN blocks_system_backup_20260614 z ON z.id = b.id |
| 72 | + WHERE b.updated_at = 0) AS zeroed, |
| 73 | + (SELECT count(*) FROM blocks_system_backup_20260614) AS expected; |
| 74 | + |
| 75 | +-- ── Rollback (only if verify is wrong; needs the clamp trigger off again since |
| 76 | +-- it restores nonzero stamps over the 0s) ───────────────────────────────── |
| 77 | +-- BEGIN; |
| 78 | +-- ALTER TABLE public.blocks DISABLE TRIGGER blocks_clamp_updated_at_trg; |
| 79 | +-- ALTER TABLE public.blocks DISABLE TRIGGER blocks_record_history_trg; |
| 80 | +-- UPDATE blocks b SET updated_at = z.updated_at, updated_by = z.updated_by, |
| 81 | +-- user_updated_at = z.user_updated_at |
| 82 | +-- FROM blocks_system_backup_20260614 z WHERE z.id = b.id; |
| 83 | +-- ALTER TABLE public.blocks ENABLE TRIGGER blocks_record_history_trg; |
| 84 | +-- ALTER TABLE public.blocks ENABLE TRIGGER blocks_clamp_updated_at_trg; |
| 85 | +-- COMMIT; |
0 commit comments