KB-781A

71 — GCOS Rollback & Verification Plan (future build, no mutation now, 2026-06-01)

10 min read Revision 1
one-roof-governancegcosbuild-intakerollback-planverificationpreflight-backupentry-equals-exitidle-transactionno-mutation2026-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=falseactive=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)

  1. pg_dump logical backup available (muc-tieu-mo §4E pg_dump_backup_available). For Phase-1 the changes are additive-only, but a pre-step pg_dump of 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.
  2. 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.
  3. Confirm idle_in_transaction = 0 before starting (no leaked session).
  4. 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 (rows active=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 to event_outbox are 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_apply is 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_regclass NULL; 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=0 until step 8; outbox_gov=0 until step 8; norm=47, law=5 unchanged; 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/DELETE rollback statement errors or leaves a target object present;
  • os_proposal_approvals changes unexpectedly mid-build (approval tampering);
  • an idle in transaction session cannot be terminated;
  • normative_registry/law_catalog counts change (a law write leaked in);
  • event_outbox governance 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.

Back to Knowledge Hub knowledge/dev/reports/architecture/one-roof-governance-technical-addendum-and-implementation-index-2026-06-01/71-gcos-rollback-and-verification-plan.md