Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion supabase/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
29 changes: 15 additions & 14 deletions supabase/migrations/20260926090100_legacy_debate_cleanup.sql
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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)
);
Loading