Phase 3B — Rollback Package
Phase 3B — Rollback Package
Scope
This rollback restores the system to the pre-Phase-3B state, i.e. exactly the state at the end of Phase 3 ([[project-dieu45-phase3-mark-cut-queue-pilot-dieu37-write-channel-pass-2026-05-26]]).
It does not roll back Phase 3 itself (the 17 durable Điều 37 IUs, the staging/payload/job_queue rows, the queue_heartbeat snapshot) — those remain.
Backup files
| Stage | path (in postgres container) | size | sha256 |
|---|---|---|---|
| pre-apply (Phase 3B baseline) | /tmp/dieu45_phase3b_pre_apply.dump |
83,241,085 | 28c2a683a3c3ca6b6898d57862702410cc582f4b00d40322528dd2bf7483ddf3 |
| post-apply (Phase 3B exit) | /tmp/dieu45_phase3b_post_apply.dump |
83,249,241 | fd3549d8f62361f0b499cd400c40e81dc6c80aec40e0999b567bcc891653068b |
Both are pg_dump -Fc (custom-format, restorable by pg_restore).
Option A — Surgical rollback (preferred for small revert)
The Phase 3B mutations are deliberately small and individually reversible. Run from psql -U workflow_admin -d directus:
BEGIN;
-- 1) Drop the heartbeat ping wrapper
DROP FUNCTION IF EXISTS public.fn_queue_heartbeat_ping_external(text,text,text,jsonb);
-- 2) Drop the vocab sync check fn and its supporting view
DROP FUNCTION IF EXISTS public.fn_iu_section_type_vocab_sync_check();
DROP VIEW IF EXISTS public.v_iu_section_type_vocab_sync;
-- 3) Remove the 5 added dot_config keys
DELETE FROM public.dot_config WHERE key IN (
'vocab.section_type.invariant_list',
'vocab.section_type.matrix',
'vocab.section_type.open_decision_list',
'vocab.section_type.rationale',
'vocab.section_type.reference_mapping'
);
COMMIT;
After this rollback, post-fix tests will fail:
fn_iu_resolve_default('matrix','iu_create.default_section_type','vocab.section_type.')returnsinvalidagain,- The 5 governed values become un-acceptable to
fn_iu_createagain, - The §15.5 silent-gap marker for
iu_outbound_defaultis still protected as before (Phase 2 created the row; Phase 3B did not touch it), - But there is no longer any safe external heartbeat caller (operators would need to call
fn_queue_heartbeat_tickdirectly with the corresponding risk of false-healingiu_outbound_default).
Net effect = Phase 3 baseline.
Option B — Full restore from pre-apply dump
ssh contabo
# inside the box:
docker exec postgres bash -c 'pg_restore -U workflow_admin -d directus --clean --if-exists /tmp/dieu45_phase3b_pre_apply.dump'
Caveats:
--cleanwill drop the post-apply objects before restoring; this is destructive and should only be used if Phase 3B introduced an unrecoverable problem.- This restore will also revert any unrelated background-rate writes that happened between the pre-apply dump and now (e.g.
event_outboxbackground rows,hc_executor_last_runupdates). - Prefer Option A unless something inside Phase 3B is irreparably broken.
Verification after rollback
SELECT count(*) AS dot_config_vocab_keys
FROM dot_config WHERE left(key,length('vocab.section_type.'))='vocab.section_type.';
-- expect 13 after Option A; could differ after Option B depending on unrelated drift
SELECT count(*) FROM pg_proc WHERE proname IN ('fn_queue_heartbeat_ping_external','fn_iu_section_type_vocab_sync_check');
-- expect 0
SELECT count(*) FROM pg_class WHERE relname='v_iu_section_type_vocab_sync';
-- expect 0
What rollback does NOT touch
| Item | Reason |
|---|---|
| Phase 3 17 Điều 37 IUs | Pre-Phase-3B durable; outside Phase 3B scope. |
Phase 3 queue_heartbeat rows (dieu45_phase3_pilot, iu_outbound_default) |
Created in Phase 3 / Phase 2. |
| Phase 3 6 job_queue rows | Created in Phase 3. |
fn_iu_create body |
Unchanged through Phase 3B (md5 dcade99af1ef096892748c9f14082e11). |
| MARK/CUT alias bodies | Unchanged through Phase 3B (md5 pinned in [[04-queue-d30-regression-pack]]). |
tac_section_type_vocab table |
Untouched. |
event_outbox, iu_vector_sync_point, production_documents, pg_extension |
Untouched. |
| All risk-bearing gates | Already at safe defaults at exit. |
Rollback risk assessment
Option A is low-risk:
- Only 8 catalog objects are dropped/deleted (1 fn wrapper, 1 fn check, 1 view, 5 rows).
- No object outside Phase 3B's add-list depends on them (verified: nothing in
pg_dependreferences the new objects from outside Phase 3B). - Post-rollback, the system reverts to a known-good Phase 3 baseline (governance silent-gap surfaced but unprotected by ping-wrapper, vocab gap re-opened).
Option B carries the standard --clean blast radius (drops the whole post-apply schema before restoring). Reserved as a last resort.