KB-6B15

O8E pre-production hardening (Contabo) — 04-revert-compensation-runbook

7 min read Revision 1
dieu44iu-cutterv0.6o8epre-production-hardening

O8E Report 04 — Per-cut revert / compensation runbook (G4 / GAP6)

  • macro: v0.6-o8e-pre-production-hardening-bundle
  • date_utc: 2026-05-21 · host: Contabo vmi3080463
  • gate covered: G4 — GAP6 per-cut revert / compensation
  • result: G4 PASS — runbook authored, non-mutating checks validated

1. Scope distinction

sql/lifecycle/rollback_runbook.sql (shipped in the tree) reverses the DDL bundles A–E — a fresh-environment / recovery procedure, NOT a per-cut data revert. GAP6 is the missing piece: reverting a single orchestrator-managed cut/enact at the data level.

Foundational fact (O8C Report 04, re-confirmed): each adapter method owns exactly one atomic transaction. Any failure within a phase ⇒ ROLLBACK, re-raise, zero partial write. Compensation is therefore only needed for phases that already COMMITTED before a later phase failed.

Phase order (mutating): pre_write_backupcut_leg_aleg_b_recordwrite_verifylifecycle_enact.

2. Before-run snapshot (MANDATORY — non-mutating, validated)

Capture to /var/lib/cutter/rollback/<run_id>/pre.json before the run:

-- public mutation surface
SELECT count(*) FROM public.information_unit;          -- baseline 158
SELECT count(*) FROM public.unit_version;              -- baseline 165
SELECT count(*) FROM public.iu_lifecycle_log;          -- baseline 60
-- governance surface (run as cutter_exec — query_pg RO role cannot read it)
SELECT count(*) FROM cutter_governance.cut_change_set;
SELECT count(*) FROM cutter_governance.manifest_envelope;
SELECT count(*) FROM cutter_governance.review_decision;
SELECT count(*) FROM cutter_governance.verify_result;
SELECT count(*) FROM cutter_governance.dot_pair_signature;
-- immutability triggers (catalog — always readable)
SELECT tgname, tgenabled FROM pg_trigger
 WHERE tgname IN ('trg_iu_enacted_immut','trg_uv_enacted_immut');

Validated non-mutating (O8E): public counts 158/165/60; both triggers present + tgenabled='O' (enabled); fn_iu_create + fn_iu_enact exist. These queries are read-only and were run safely via query_pg this macro.

3. Per-phase failure → compensation matrix

Failed phase Already-committed phases Compensation
pre_write_backup none No DB state changed. Discard backup artifact. HOLD — re-run from clean.
cut_leg_a backup Adapter ROLLED BACK the whole fn_iu_create fan-out (proven). 0 IU/UV rows. Discard backup. HOLD.
leg_b_record backup, cut_leg_a (IUs committed) IUs are lifecycle_status='draft' (not yet enacted). Compensation A below.
write_verify backup, cut_leg_a, leg_b_record IUs draft; governance leg-B rows committed. Compensation A + B.
lifecycle_enact backup, cut_leg_a, leg_b_record, write_verify If fn_iu_enact fan-out failed it ROLLED BACK (proven) → IUs still draft → as write_verify failure. If it COMMITTED, the run succeeded — no compensation.

Compensation A — revert committed draft IUs of one cut

Draft IUs are safe to revert: the trg_iu_enacted_immut / trg_uv_enacted_immut triggers protect only enacted rows, so draft rows of a single change_set_id can be removed inside one sovereign-gated txn:

BEGIN;
-- guard: refuse if ANY IU of this change_set is already enacted
SELECT count(*) FROM public.information_unit iu
  JOIN cutter_governance.cut_change_set_affected_row a
    ON a.information_unit_id = iu.id
 WHERE a.change_set_id = :cs AND iu.lifecycle_status = 'enacted';
-- if > 0  → ABORT, escalate to sovereign (enacted state is immutable)
DELETE FROM public.unit_version       WHERE information_unit_id IN
  (SELECT information_unit_id FROM cutter_governance.cut_change_set_affected_row
    WHERE change_set_id = :cs);
DELETE FROM public.information_unit   WHERE id IN
  (SELECT information_unit_id FROM cutter_governance.cut_change_set_affected_row
    WHERE change_set_id = :cs);
-- verify counts return to the pre.json baseline BEFORE commit
COMMIT;   -- only if the in-txn re-count matches pre.json

NO HARD DELETE BY DEFAULT. Compensation A is the escalation path; the recommended default is a sovereign-reviewed soft-revert — set the cut's IUs to a superseded/withdrawn lifecycle status if the schema supports it, preserving audit lineage. Hard delete only on an explicit sovereign decision and only while every affected row is still draft.

Compensation B — neutralise committed leg-B / verify governance rows

Governance rows (manifest_envelope, cut_change_set, verify_result, dot_pair_signature) are an append-only audit ledger. They are not deleted. Compensation: append a sovereign-signed compensating review_decision that marks the change_set_id as reverted, cross- referencing the revert run id. The ledger keeps the full forward+reverse history. Authoring this compensating-decision writer is a small Mac source task (see Report 09).

4. Partial governance recording

If leg_b_record / write_verify fail mid-writer, the adapter's single-txn ROLLBACK leaves zero governance rows for that phase (proven, O8A test_*_rolls_back_on_failure). There is no partial-governance state to compensate — only a fully-committed phase needs Compensation B.

5. Disable / HOLD state

On ANY unrecovered failure:

1. execution_enabled → flip back to False immediately (kill-switch re-arm).
2. orchestrator run state → set state=STOPPED, last_error recorded
   (StateStore atomic write under fcntl lock).
3. write /var/lib/cutter/locks/HOLD with the run_id + reason.
4. capture post-failure snapshot → /var/lib/cutter/rollback/<run_id>/post.json
5. do NOT retry automatically — route to GPT/sovereign with pre.json+post.json.

6. Non-mutating validation performed (O8E)

pre_snapshot_public_counts:   158 / 165 / 60   — query_pg, read-only        OK
immutability_triggers:        trg_iu/uv_enacted_immut present, tgenabled=O   OK
enact_functions_present:      fn_iu_create=1  fn_iu_enact=1                  OK
mutating_compensation_run:    NOT executed — authored only (correct for O8E)

7. Verdict

gap6_runbook:           AUTHORED — before-snapshot, 5 phase-failure paths,
                        Compensation A (draft revert) + B (ledger compensation),
                        disable/HOLD procedure
hard_delete_default:    NO — soft-revert default; hard delete = sovereign-only,
                        draft-only
non_mutating_checks:    VALIDATED
residual:               compensating-review_decision writer = small Mac task
g4:                     PASS
Back to Knowledge Hub knowledge/dev/laws/dieu44-trien-khai/v0.6-o8e-pre-production-hardening-bundle/04-revert-compensation-runbook.md