fix(reset): fold --user-subset cleanup into scope=all and scope=exam-corpus
Some checks failed
api-ci-deploy / test-build-deploy (push) Has been cancelled

t_d1600327 added a standalone scope=user-subset, but a full reset (scope=all)
and scope=exam-corpus still left the --user-subset cc.users storage objects
orphaned (files rows are wiped by the table clear, but the Storage API objects
are not). Call the same _clear_user_subset_files() helper in both paths so the
finding-#2 gap is fully closed: storage removed before rows, idempotent.

Closes overwatch review finding #2 (user-subset not cleaned by reset).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
CC Worker 2026-06-08 00:26:24 +00:00
parent 7f7e843563
commit a6753d092f

View File

@ -298,11 +298,12 @@ def reset(scope: str = "all") -> Dict[str, Any]:
"""Destructive reset. scope ∈ {all, exam-corpus, timetable, user-subset}. """Destructive reset. scope ∈ {all, exam-corpus, timetable, user-subset}.
- all : full wipe (Neo4j + Supabase data + auth users) AND the entire - all : full wipe (Neo4j + Supabase data + auth users) AND the entire
exam-marker subsystem listed below. exam-marker subsystem listed below, including --user-subset copies.
- exam-corpus : ONLY the entire exam-marker subsystem, not just public papers: - exam-corpus : ONLY the entire exam-marker subsystem, not just public papers:
public corpus/eb_* data, cc.examboards storage objects, exam public corpus/eb_* data, cc.examboards storage objects, exam
templates, template layouts, questions, boundaries, response templates, template layouts, questions, boundaries, response
areas, marking batches, student submissions, and mark entries. areas, marking batches, student submissions, mark entries, and
--user-subset cc.users copies.
- timetable : ONLY timetable/calendar materialization tables. - timetable : ONLY timetable/calendar materialization tables.
- user-subset : ONLY files rows and cc.users storage objects created by - user-subset : ONLY files rows and cc.users storage objects created by
seed_exam_corpus.py --user-subset. seed_exam_corpus.py --user-subset.
@ -314,10 +315,11 @@ def reset(scope: str = "all") -> Dict[str, Any]:
_assert_reset_allowed(url, scope) _assert_reset_allowed(url, scope)
if scope == "exam-corpus": if scope == "exam-corpus":
logger.info("RESET (scope=exam-corpus) — entire exam-marker subsystem: public corpus/eb_* data, cc.examboards storage, templates/layout/questions/boundaries/response areas, marking batches, submissions, mark entries") logger.info("RESET (scope=exam-corpus) — entire exam-marker subsystem: public corpus/eb_* data, cc.examboards storage, templates/layout/questions/boundaries/response areas, marking batches, submissions, mark entries, and --user-subset copies")
user_subset = _clear_user_subset_files()
storage = _clear_exam_storage() storage = _clear_exam_storage()
cleared, failed = _clear_tables(url, headers, EXAM_CORPUS_TABLES) cleared, failed = _clear_tables(url, headers, EXAM_CORPUS_TABLES)
return {"scope": scope, "exam_storage": storage, "tables_cleared": cleared, "tables_failed": failed} return {"scope": scope, "user_subset": user_subset, "exam_storage": storage, "tables_cleared": cleared, "tables_failed": failed}
if scope == "timetable": if scope == "timetable":
logger.info("RESET (scope=timetable) — timetable/calendar tables") logger.info("RESET (scope=timetable) — timetable/calendar tables")
@ -341,6 +343,9 @@ def reset(scope: str = "all") -> Dict[str, Any]:
results["neo4j"] = {"dropped": dropped} results["neo4j"] = {"dropped": dropped}
# ── 2. Supabase: clear all data tables (GAIS preserved) ────────────────── # ── 2. Supabase: clear all data tables (GAIS preserved) ──────────────────
# First remove --user-subset cc.users storage objects (+ their files rows) via the
# Storage API, so the generic files-table clear below doesn't strand orphaned objects.
results["user_subset"] = _clear_user_subset_files()
logger.info("\n[Supabase] Clearing data tables (preserving gais_*)...") logger.info("\n[Supabase] Clearing data tables (preserving gais_*)...")
url, headers = _sb_headers() url, headers = _sb_headers()
cleared, failed = [], [] cleared, failed = [], []