diff --git a/supabase/README.md b/supabase/README.md index 247191bb7..1d6bf081a 100644 --- a/supabase/README.md +++ b/supabase/README.md @@ -123,7 +123,7 @@ The database gate proves migration replay and pgTAP assertions locally. It does `20260927170000_debate_context_pins.sql` is additive: it creates `debate_context_pins`, the saved results a student pins per debate, with RLS and a composite key to the owner's debate. -`20260926090100_legacy_debate_cleanup.sql` is destructive and one-time: it deletes legacy results, chats, flowcharts, sparring rounds, and sources that belong to no debate and had no activity in the 30 days before `20260926090000_current_debates.sql` recorded its rollout time in `private.current_debate_rollout`. Work created after that time is never touched, however late the cleanup runs. Keep it separate from the additive `20260926090000_current_debates.sql`, and apply it to a remote project only with explicit authorization for that environment. +`20260926090100_legacy_debate_cleanup.sql` defines `private.purge_legacy_debate_material`, which deletes legacy results, chats, flowcharts, sparring rounds, and sources that belong to no debate and had no activity in the 30 days before `20260926090000_current_debates.sql` recorded its rollout time in `private.current_debate_rollout`. The migration does not call it, so applying it deletes nothing; legacy rows stay in the Unsorted view. Running the purge on a remote project is a separate, destructive step that needs explicit authorization for that environment. Work created after the rollout is never touched, however late it runs. ## Edge Function tests diff --git a/supabase/migrations/20260926090100_legacy_debate_cleanup.sql b/supabase/migrations/20260926090100_legacy_debate_cleanup.sql index 858e5b704..6a910fcf9 100644 --- a/supabase/migrations/20260926090100_legacy_debate_cleanup.sql +++ b/supabase/migrations/20260926090100_legacy_debate_cleanup.sql @@ -1,14 +1,19 @@ --- DESTRUCTIVE, ONE-TIME: remove legacy material that predates Current Debate --- and had no activity in the 30 days before it shipped. Recent legacy material --- stays, without a debate, in the Unsorted view until the user confirms where --- it belongs. +-- One-time purge of legacy material that predates Current Debate and had no +-- activity in the 30 days before it shipped. This migration only defines the +-- function; it does not run it. Adam chose on 2026-09-30 to keep production's +-- legacy material, so any purge is a separate, explicitly authorized call: -- --- Only rows with no debate that were created before the rollout are candidates, --- so neither debate work nor later one-off work can be removed, however late --- this runs. Nothing schedules it; this migration calls it once. Activity is --- the latest edit where a table records one (flowcharts, sparring sessions) and --- the latest message for chats. Chat messages and source files go with their --- parents through ON DELETE CASCADE; evidence cards keep a null source. +-- SELECT private.purge_legacy_debate_material( +-- (SELECT started_at FROM private.current_debate_rollout) +-- ); +-- +-- Until then, legacy material stays, without a debate, in the Unsorted view. +-- Only rows with no debate that were created before the rollout are +-- candidates, so neither debate work nor later one-off work can be removed, +-- however late it runs. Activity is the latest edit where a table records one +-- (flowcharts, sparring sessions) and the latest message for chats. Chat +-- messages and source files go with their parents through ON DELETE CASCADE; +-- evidence cards keep a null source. CREATE FUNCTION private.purge_legacy_debate_material(p_rollout timestamptz) RETURNS void @@ -39,7 +44,3 @@ $$; REVOKE ALL ON FUNCTION private.purge_legacy_debate_material(timestamptz) FROM PUBLIC, anon, authenticated, service_role; - -SELECT private.purge_legacy_debate_material( - (SELECT started_at FROM private.current_debate_rollout) -);