D36 NVSZ Macro A — 08 Rollback Plan (ready to apply)
D36 NVSZ Macro A — 08 Rollback Plan
Scope. Fully reverse everything Macro A applied — bounded proof rows, registry rows, gates, retention policies, event types, DOTs, functions, views, sidecar table, and the iu_core schema itself.
Apply mode. Single TX, idempotent, REFUSED-guarded on unexpected actor data. Apply only when no other staging traffic is in flight.
Channel. ssh contabo "docker exec postgres psql -U workflow_admin -d directus -v ON_ERROR_STOP=1 -f /tmp/d36_macroA_rollback.sql".
Pre-flight guard (refuse if foreign actor staging data present)
DO $$
DECLARE v_foreign_count int;
BEGIN
SELECT count(*) INTO v_foreign_count
FROM iu_core.iu_staging_record WHERE owner_actor <> 'd36-macroA-proof';
IF v_foreign_count > 0 THEN
RAISE EXCEPTION 'REFUSED: % foreign staging records present (owner_actor != d36-macroA-proof). Rollback aborted.', v_foreign_count;
END IF;
END$$;
Rollback SQL
BEGIN;
-- 1. Proof rows (actor-scoped)
DELETE FROM iu_core.iu_staging_payload p USING iu_core.iu_staging_record r
WHERE p.staging_record_id = r.staging_record_id AND r.owner_actor = 'd36-macroA-proof';
DELETE FROM iu_core.iu_staging_record WHERE owner_actor = 'd36-macroA-proof';
-- 2. Registry rows (idempotent on absence)
DELETE FROM species_collection_map
WHERE species_code = 'SPE-NVS' AND collection_name IN ('iu_staging_record','iu_staging_payload');
DELETE FROM collection_registry_vector_policy
WHERE collection_registry_id IN (
SELECT id FROM collection_registry WHERE code IN ('COL-IUS-001','COL-IUS-002')
);
DELETE FROM collection_registry WHERE code IN ('COL-IUS-001','COL-IUS-002');
DELETE FROM entity_species WHERE species_code = 'SPE-NVS';
DELETE FROM birth_registry
WHERE entity_code IN ('COL-IUS-001','COL-IUS-002','SPE-NVS')
OR dot_origin LIKE '%D36-Macro-A%';
DELETE FROM event_type_registry
WHERE event_domain = 'staging'
AND event_type IN ('staging.record_created','staging.record_approved','staging.record_consumed','staging.record_rejected','staging.record_cleaned');
DELETE FROM iu_core_retention_policy
WHERE target_table IN ('iu_core.iu_staging_record','iu_core.iu_staging_payload');
DELETE FROM tac_birth_gate_config
WHERE checker_id IN ('iu_core.staging_writes_enabled','iu_core.staging_cleanup_enabled','iu_core.no_vector_staging_excluded');
DELETE FROM dot_iu_command_catalog
WHERE command_name IN ('dot_iu_staging_create','dot_iu_staging_approve','dot_iu_staging_consume','dot_iu_staging_reject');
-- 3. Sidecar + view (public schema)
DROP VIEW IF EXISTS public.v_collection_vector_eligibility;
DROP TABLE IF EXISTS public.collection_registry_vector_policy CASCADE;
-- 4. iu_core schema cascade (drops 2 tables, 2 views, 5 functions, indexes)
DROP SCHEMA IF EXISTS iu_core CASCADE;
COMMIT;
Expected counters after rollback
Restore to pre-apply baseline:
| Counter | Should return to |
|---|---|
information_unit |
175 (unchanged) |
iu_vector_sync_point |
152 (unchanged) |
dot_iu_command_catalog |
26 |
collection_registry |
166 |
entity_species |
41 |
event_type_registry |
26 |
species_collection_map |
162 |
birth_registry |
750,964 (or within trigger drift — see note) |
iu_core.* |
schema absent |
collection_registry_vector_policy |
table absent |
Note: birth_registry rollback drift
Some birth_registry rows were created by triggers on collection_registry and entity_species inserts with dot_origin mutated by the trigger (e.g. SUSPECT:D36-Macro-A). The rollback DELETE uses LIKE '%D36-Macro-A%' to catch them. If the trigger uses a different transformation, manual review may surface 1-3 stragglers — query:
SELECT * FROM birth_registry
WHERE date_created >= '2026-05-25'
AND (entity_code IN ('COL-IUS-001','COL-IUS-002','SPE-NVS','iu_staging_record','iu_staging_payload')
OR jsonb_profile->>'d36' = 'macro-a');
…then DELETE accordingly. The pre/post pg_dump --schema-only diff is a structural rollback witness; row drift is data-only.
Test the rollback after applying
-- All should return 0 / absent
SELECT count(*) FROM information_schema.schemata WHERE schema_name='iu_core';
SELECT count(*) FROM information_schema.tables WHERE table_name='collection_registry_vector_policy';
SELECT count(*) FROM information_schema.views WHERE table_name='v_collection_vector_eligibility';
SELECT count(*) FROM collection_registry WHERE code LIKE 'COL-IUS-%';
SELECT count(*) FROM entity_species WHERE species_code='SPE-NVS';
SELECT count(*) FROM dot_iu_command_catalog WHERE command_name LIKE 'dot_iu_staging_%';
SELECT count(*) FROM event_type_registry WHERE event_domain='staging';
SELECT count(*) FROM tac_birth_gate_config WHERE checker_id LIKE 'iu_core.%';
SELECT count(*) FROM iu_core_retention_policy WHERE target_table LIKE 'iu_core.%';
All =0. Then re-take pg_dump --schema-only and verify sha256 matches the pre-apply baseline 57fbae483215898226d5f7a6cb07a4fb2cd10b75a0210d6275415d8df6737bd9 (modulo row-count differences in data-only system tables).
When NOT to apply this rollback
- If real (non-proof) staging data exists with
owner_actor != 'd36-macroA-proof'— the pre-flight guard refuses. - If another macro has built on top of this substrate (e.g. Macro B added trigger fns referencing
iu_staging_record) — the CASCADE would drop those fns. - If
collection_registry_vector_policyrows exist for non-D36 collections — only the COL-IUS rows are deleted by section 2, but the view + table drop in section 3 would remove all rows. Run
SELECT count(*) FROM collection_registry_vector_policy
WHERE collection_registry_id NOT IN (SELECT id FROM collection_registry WHERE code IN ('COL-IUS-001','COL-IUS-002'));
first — if >0, modify rollback to keep the sidecar table and DROP only the rows + view.