71 — GCOS Rollback & Verification Plan (future build, no mutation now, 2026-06-01)
71 — GCOS Rollback & Verification Plan
Path:
knowledge/dev/reports/architecture/one-roof-governance-technical-addendum-and-implementation-index-2026-06-01/Doc: 71. Role: Branch E of the gated build-intake packet. The rollback + verification plan a future build MUST satisfy before and after each COMMIT step. Status: BUILD-INTAKE / PLAN DOCUMENT ONLY. No mutation. The SQL shown is the template a future authorized build would run; nothing here is executed now. Date: 2026-06-01. Extends: doc 42 §42.7 (reversibility mapping), doc 49 §49.4 (rehearsal evidence), doc 64 (entry==exit method). Pairs with: doc 70 (build order), doc 72 (authorization template).
71.0 Reversibility principle
Per muc-tieu-mo §5 (reversible_by_default: true — "mutation phải có rollback/disable trước khi apply") and doc 49 M-3: a rollback/disable plan must be staged and proven before any COMMIT. The GCOS substrate is greenfield-additive, which makes rollback simple: every object is either a new table (DROP), an additive reuse-table row (DELETE by governance key), or an active=false→active=true flip (flip back). No existing row is ever modified or deleted, so there is no data-restore problem — only additive-removal.
71.1 Preflight backup / snapshot (before any COMMIT step)
pg_dumplogical backup available (muc-tieu-mo §4Epg_dump_backup_available). For Phase-1 the changes are additive-only, but a pre-steppg_dumpof the affected reuse tables (event_type_registry,queue_heartbeat,evolution_snapshots,dot_domains,dot_tools,dot_coverage_required) + a schema dump is required as the disaster fallback.- Baseline numeric snapshot captured read-only (the doc-45 §45.3 block + doc-67 §67.1 query): all reuse-table counts, all target-table
to_regclass,os_proposal_approvals, governance-scope probes. This is the entry row of the entry==exit proof. - Confirm
idle_in_transaction= 0 before starting (no leaked session). - Record the M-1 approval row reference so the post-check can confirm it was present at COMMIT.
71.2 DDL rollback (new tables — Phase-1 steps 1–3, 7)
| Object | Rollback statement |
|---|---|
governance_ruleset (SB-12) |
DROP TABLE IF EXISTS governance_ruleset; |
gov_worker_cursor (SB-13) |
DROP TABLE IF EXISTS gov_worker_cursor; |
governance_candidate_state / governance_candidate_object / candidate_scan_run (SB-10) |
DROP TABLE in reverse-FK order (scan_run → object → state) |
governance_object_ownership / governance_responsibility_scope / v_object_effective_owner (SB-2) |
DROP VIEW v_object_effective_owner; DROP TABLE governance_object_ownership; DROP TABLE governance_responsibility_scope; |
All target tables are greenfield (empty at create), so DROP is a complete, data-loss-free rollback. Proven: every rehearsal DROPped via ROLLBACK and to_regclass returned NULL (docs 58–64).
71.3 Data rollback (additive reuse-table rows)
| Reuse table | Rollback (governance-scoped delete) |
|---|---|
evolution_snapshots |
DELETE FROM evolution_snapshots WHERE scope LIKE 'governance.%'; |
queue_heartbeat |
DELETE FROM queue_heartbeat WHERE executor_name LIKE 'gov\_%'; |
dot_domains |
DELETE FROM dot_domains WHERE code IN ('governance.backfill','governance.handoff','governance.input','governance.candidate'); |
dot_tools |
DELETE FROM dot_tools WHERE code LIKE 'dot_governance_%'; (or GOVDOT-% if renamed per F-R7-2) |
dot_coverage_required |
DELETE FROM dot_coverage_required WHERE domain LIKE 'governance.%'; (delete BEFORE dot_domains — reverse FK, F-R7-1) |
apr_action_types (SB-1) |
DELETE FROM apr_action_types WHERE code IN ('assign_governance_owner','grant_governance_exception','delegate_authority','assign_axis_owner'); |
| candidate seed rows (Branch A) | DELETE FROM governance_candidate_state WHERE last_run_id = <run>; + reset gov_worker_cursor watermark |
Order matters: delete dot_coverage_required before dot_domains (FK); delete candidate rows before dropping governance_ruleset (FK). No existing (non-governance) row is touched.
71.4 Event-registration rollback (SB-11 / step 8)
- Registered but inactive (step 4):
DELETE FROM event_type_registry WHERE event_domain='governance';— no emit occurred (rowsactive=false), so nothing downstream to unwind. - Activated (step 8): first set
UPDATE event_type_registry SET active=false WHERE event_domain='governance';(disable), then optionally delete. Any rows already emitted toevent_outboxare immutable history — do NOT delete outbox rows; disabling stops further emit. This is why activation is the last, separately-gated step.
71.5 DOT-registration rollback (step 6 / 8)
- Registered (step 6):
DELETE FROM dot_tools WHERE code LIKE 'dot_governance_%';(+ coverage + domains per §71.3 order). - Activated (step 8): disable the DOT (DOT disable flag), do not drop, if it has run history; then delete if greenfield. The mutating
dot_governance_assignment_applyis never created (G-APPLY NO-GO), so it has no rollback.
71.6 Verification query set (post-step, after rollback OR after authorized COMMIT)
Run read-only via query_pg in a separate session (the doc-64 method). Two uses: (a) post-ROLLBACK to prove zero residue; (b) post-COMMIT to prove the footprint is exactly the intended additive set and nothing else moved.
-- Target tables (NULL = absent; present = built)
SELECT to_regclass('public.governance_ruleset'), to_regclass('public.gov_worker_cursor'),
to_regclass('public.governance_candidate_state'), to_regclass('public.governance_candidate_object'),
to_regclass('public.candidate_scan_run'), to_regclass('public.governance_object_ownership'),
to_regclass('public.governance_responsibility_scope');
-- Governance-scope residue / footprint probes
SELECT (SELECT count(*) FROM evolution_snapshots WHERE scope LIKE 'governance.%') AS evo_gov,
(SELECT count(*) FROM event_type_registry WHERE event_domain='governance') AS etr_gov,
(SELECT count(*) FROM event_type_registry WHERE event_domain='governance' AND active) AS etr_gov_active,
(SELECT count(*) FROM event_outbox WHERE event_domain='governance') AS outbox_gov,
(SELECT count(*) FROM queue_heartbeat WHERE executor_name LIKE 'gov\_%') AS hb_gov,
(SELECT count(*) FROM dot_tools WHERE code LIKE 'dot_governance_%') AS dot_gov,
(SELECT count(*) FROM dot_domains WHERE code LIKE 'governance.%' AND code NOT IN ('governance.approval','governance.audit')) AS dom_gcos,
(SELECT count(*) FROM event_pending) AS pending;
-- Invariants that must NEVER move during Phase-1
SELECT (SELECT count(*) FROM os_proposal_approvals) AS approvals, -- must match recorded M-1 (0 if rollback)
(SELECT count(*) FROM normative_registry) AS norm, -- must stay 47 (no law change)
(SELECT count(*) FROM law_catalog) AS law, -- must stay 5
(SELECT count(*) FROM apr_action_types) AS action_types;-- 6, unless SB-1 step (+4)
-- Idle transaction / leaked session check
SELECT count(*) FROM pg_stat_activity
WHERE datname='directus' AND state='idle in transaction'; -- must be 0
Pass criteria:
- Post-ROLLBACK: all
to_regclassNULL; all governance-scope probes 0; invariants at baseline; idle-in-transaction 0. (This is the entry==exit proof, doc 64.) - Post-COMMIT (authorized step): exactly the intended new tables present; exactly the intended additive rows;
etr_gov_active=0until step 8;outbox_gov=0until step 8;norm=47,law=5unchanged;os_proposal_approvals≥ the recorded approval; idle-in-transaction 0.
71.7 Idle-transaction check (mandatory)
idle_in_transaction_session_timeout='15s' is set on every author session, and pg_stat_activity is checked for state='idle in transaction' on db directus before and after each step. Any leaked transaction = immediate stop (disaster condition). Proven 0 throughout the rehearsal run (doc 64).
71.8 No-residue proof
Zero-residue is proven by the §71.6 query in a separate session from the one that ran the DDL/DML — the rehearsal method that detected nothing left behind across R-2..R-8 (doc 64). For a rolled-back step: every probe returns 0/NULL. For a committed step: only the intended footprint differs; all unrelated reuse-table counts and all law/approval invariants are byte-identical to the pre-step baseline (the entry==exit comparison, extended to the post-COMMIT case).
71.9 Disaster stop condition
Halt the entire build and restore from the §71.1 pg_dump backup if ANY of:
- a
DROP/DELETErollback statement errors or leaves a target object present; os_proposal_approvalschanges unexpectedly mid-build (approval tampering);- an
idle in transactionsession cannot be terminated; normative_registry/law_catalogcounts change (a law write leaked in);event_outboxgovernance count rises before step 8 (emit-before-activate);- a second bus/store/notifier appears (no-island breach);
- the mutating apply DOT appears without A-9. On disaster: stop, do not attempt further COMMITs, report BLOCKED with the verification-query output and the backup reference, escalate to sovereign.
71.10 Rollback-plan verdict
A complete preflight-backup → DDL-rollback → data-rollback → event-rollback → DOT-rollback → verification-query-set → idle-check → no-residue-proof → disaster-stop chain exists for every build step. The additive-greenfield design makes every rollback a DROP or a governance-keyed DELETE with no existing-row modification. The verification method is the same dual-session entry==exit method already proven across R-2..R-8 (doc 64). Nothing here is executed now.