KB-680C

D36 NVSZ Macro A — 08 Rollback Plan (ready to apply)

6 min read Revision 1
d36rollbackmacro-a2026-05-25

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_policy rows 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.

Back to Knowledge Hub knowledge/dev/laws/dieu44-trien-khai/v0.6-d36-no-vector-staging-zone-macro-a-substrate-birth-dot-healthcheck/08-rollback-plan.md