-- 08_verify.sql: hard assertions; any failure aborts the whole transaction. DO $$ DECLARE r record; a bigint; bad text := ''; BEGIN -- every moved table keeps its exact row count -- expected = prod count before + rows imported from dev (cs.* only; prod cs was empty) FOR r IN SELECT m.*, b.n + coalesce(i.n, 0) AS n FROM legacy.reorg_table_map m JOIN legacy.reorg_counts_before b ON b.table_name = m.old_name LEFT JOIN legacy.reorg_imports i ON i.dst = m.new_schema || '.' || m.new_name LOOP EXECUTE format('SELECT count(*) FROM %I.%I', r.new_schema, r.new_name) INTO a; IF a <> r.n THEN bad := bad || format('%s.%s %s<>%s; ', r.new_schema, r.new_name, a, r.n); END IF; END LOOP; IF bad <> '' THEN RAISE EXCEPTION 'row count mismatch: %', bad; END IF; IF (SELECT count(*) FROM legacy.reorg_counts_before) <> 58 THEN RAISE EXCEPTION 'expected 58 source tables'; END IF; IF EXISTS (SELECT 1 FROM pg_tables WHERE schemaname = 'public') THEN RAISE EXCEPTION 'public not empty'; END IF; END $$; -- lists: every legacy item is in exactly one lists.* table, except the 4 merged duplicates; done count preserved DO $$ DECLARE t record; n bigint; total bigint := 0; done bigint := 0; d bigint; dropped bigint := (SELECT count(*) FROM legacy.reorg_list_fixes WHERE action = 'dedupe-drop'); BEGIN FOR t IN SELECT * FROM meta.tables WHERE kind = 'list' LOOP EXECUTE format('SELECT count(*) FROM lists.%I', t.table_name) INTO n; total := total + n; IF t.has_done THEN EXECUTE format('SELECT count(*) FROM lists.%I WHERE done_at IS NOT NULL', t.table_name) INTO d; done := done + d; END IF; END LOOP; IF total + dropped <> (SELECT count(*) FROM legacy.list_items) THEN RAISE EXCEPTION 'lists total % + % dropped <> legacy %', total, dropped, (SELECT count(*) FROM legacy.list_items); END IF; -- expected done = legacy completions minus dedupe pairs where BOTH copies were done (they collapse to one) d := (SELECT count(*) FROM legacy.list_item_completions) - (SELECT count(*) FROM dedupe x WHERE EXISTS (SELECT 1 FROM legacy.list_item_completions c WHERE c.item_id = x.keep_id) AND EXISTS (SELECT 1 FROM legacy.list_item_completions c WHERE c.item_id = x.drop_id)); IF done <> d THEN RAISE EXCEPTION 'done count % <> expected %', done, d; END IF; IF (SELECT count(*) FROM meta.tables WHERE kind = 'list') <> (SELECT count(*) FROM legacy.lists) THEN RAISE EXCEPTION 'list count mismatch'; END IF; RAISE NOTICE 'lists OK: % rows (+% merged dupes), % done', total, dropped, done; END $$; -- every table with updated_at has the trigger DO $$ DECLARE missing text; BEGIN SELECT string_agg(n.nspname || '.' || c.relname, ', ') INTO missing FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace JOIN pg_attribute a ON a.attrelid = c.oid AND a.attname = 'updated_at' AND NOT a.attisdropped WHERE c.relkind = 'r' AND n.nspname NOT IN ('legacy','pg_catalog','information_schema') AND n.nspname !~ '^pg_' AND NOT EXISTS (SELECT 1 FROM pg_trigger tg WHERE tg.tgrelid = c.oid AND tg.tgfoid = 'meta.touch_updated_at()'::regprocedure); IF missing IS NOT NULL THEN RAISE EXCEPTION 'missing updated_at trigger: %', missing; END IF; -- every table has a PK SELECT string_agg(n.nspname || '.' || c.relname, ', ') INTO missing FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace WHERE c.relkind = 'r' AND n.nspname NOT IN ('legacy','pg_catalog','information_schema') AND n.nspname !~ '^pg_' AND NOT EXISTS (SELECT 1 FROM pg_constraint k WHERE k.conrelid = c.oid AND k.contype = 'p'); IF missing IS NOT NULL THEN RAISE EXCEPTION 'tables without PK: %', missing; END IF; END $$; -- list rows keep their original timestamps DO $$ DECLARE t record; n bigint; bad bigint := 0; BEGIN FOR t IN SELECT table_name FROM meta.tables WHERE kind = 'list' LOOP EXECUTE format('SELECT count(*) FROM lists.%I x JOIN legacy.list_items i ON i.id = x.id WHERE x.updated_at <> i.updated_at OR x.created_at <> i.created_at', t.table_name) INTO n; bad := bad + n; END LOOP; IF bad > 0 THEN RAISE EXCEPTION '% list rows lost their original timestamps', bad; END IF; END $$;