KB-7613 rev 24

FIX7 Refactor Blueprint - Rollback Blueprint

16 min read Revision 24

05 - Rollback Blueprint

<!-- DOC_STATUS: ACTIVE_AUTHORITY --> <!-- AUTHORITY_BOUNDARY: registry in 00-readme-first.md §Active-authority boundary -->

CODEX RECHECK-3 PATCH (2026-06-09) — typed set separation. The S14/S15 owner+ACL snapshot and its both-direction effective-privilege verification are over the PG-object set U_legacy_object (doc 02 §H.4.A) and the separate principal universe U_effective_privilege_principal (§H.4.B); the snapshot captures object owner/ACL and role-membership effective privilege — a role is a principal, never an object member. Entry-vectors are not snapshotted as objects (§H.4.C).

OPTION-BETA PATCH (2026-06-08). Under the Codex-approved Option Beta, no legacy object body is ever changed, so the legacy rollback has no body-restore path at all — the prior STUB_FAIL_CLOSED body-restore source and the Option α/β branching are removed. Two recheck-2 fixes remain and are unchanged: (G) forward-only history — rollback NEVER clears or edits activated_at; it supersedes forward (new manifest_activation of a prior-payload candidate + predecessor superseded_by_manifest_id), and the current-active route is derived by activated_at IS NOT NULL AND superseded_by_manifest_id IS NULL. (E) unique rollback source — the legacy owner/ACL rollback source is the single S14 snapshot artifact uniquely bound by the existing manifest_activation.rollback_evidence_id FK to evidence_registry.evidence_id (not a bare hash). Because no body changed, the complete legacy rollback is: restore the prior owner + captured effective-privilege ACL by replaying that one verified snapshot. Manifest-object rollback re-activates the prior immutable sealed manifest version (its source bodies are already sealed in that version's payload). evidence_registry is used for the snapshot as evidence only, never as a body-restore authority.

Principle (from approved design): rollback never edits or drops an active/history object. Pre-activation rehearsal may drop empty candidate-only objects in exact reverse dependency order. Post-activation rollback is always "create-and-activate a new candidate with the prior payload, new version/epoch/quorum/evidence." Owner/ACL and live-repoint steps roll back by restoring the prior grant/ownership, never by deleting and never by changing any object body.

step rollback action rollback dependency rollback order verify after safe before activation? safe after activation? needs operator? preserves safe-blocked state?
S01 roles/schema/domains drop empty schema, domains, roles no objects depend last (after S04 reversal) schema absent YES n/a (foundation persists) OP YES
S02 catalog root drop empty catalog (only if no FK/ref/history) catalog has no children yet after S04 catalog absent YES NO (becomes FK-authority root) OP YES
S03 anchors drop empty manifest_* after children dropped after S04 anchors absent YES NO OP YES
S04 27 contracts drop empty tables in doc 02 §2.6 exact reverse order (writer_repoint ... policy_rule) reverse of creation first 27 tables absent YES NO OP YES
S05 operator/operand drop empty none with S04 group absent YES NO OP YES
S06 registries/activation drop empty registries after runtime-evidence dropped after S07 absent YES NO OP YES
S07 runtime-evidence drop empty 11 tables inbound FK only from evidence before S06 absent YES NO OP YES
S08 deferred constraints drop added FK/constraints reverse of S08 add before table drops constraints absent YES NO OP YES
S09/S10 sealed DATA (pre-seal candidate) delete candidate rows (candidate-only, never sealed) candidate not sealed n/a candidate empty YES NO OP YES
S12 seal no unseal; supersede via new candidate version new version forward-only superseded marker n/a new version only OP (quorum) YES
S13 repoint authoring discard #26/#27 candidate rows candidate-only n/a rows absent YES new version T1/OP YES
S14 stage + pre-cutover snapshot (no activation) discard the staged state (manifest stays SEALED-not-active, activated_at NULL) + delete the snapshot artifact; legacy untouched none immediate manifest still STAGED; snapshot artifact absent; legacy intact YES YES OP YES (manifest never became ACTIVE; legacy unchanged)
S15 atomic owner+reconcile+activate+repoint atomic forward-only deactivation-first sequence (note 5): (1) supersede the new authoritative path FORWARD - new manifest_activation of a prior-payload candidate + set predecessor superseded_by_manifest_id; NEVER clear/edit activated_at (recheck-2 BLOCKER G); (2) verify readiness BLOCKED via the derived current-active route; (3) verify the gateway cannot route the new path; (4) restore legacy by replaying the verified S14 snapshot - prior owner (directus) + captured effective-privilege ACL, NO body change (Option Beta), uniquely sourced via manifest_activation.rollback_evidence_id; (5) verify G-NOMIXED-AUTHORITY + G-BIRTH-NEUTRAL the single S14 snapshot (bound by rollback_evidence_id) + prior immutable sealed manifest version immediate, in the order above new path superseded forward (derived current-active = none for writer type; predecessor activated_at immutable); readiness BLOCKED; legacy owner == directus; effective privileges == captured prior set; body unchanged; birth-neutral; qt001_backfill_permit/QT001-apply still independently blocked; no mixed old+new authority n/a YES OP YES (see note 5)
S16 owner/ACL cutover restore prior ownership + prior grants; re-add directus/PUBLIC exactly as captured the S14-captured pre-cutover snapshot immediate ownership/ACL == S14 snapshot n/a YES OP YES (returns to directus-owned blocked state)
S17 legacy retention restore prior grants/owner from the S14 snapshot (effective privileges == captured prior set) snapshot reversible; no body changed immediate legacy grants/owner restored n/a YES OP YES
S18 legacy deprecate-marker clear the deprecation marker marker reversible immediate legacy active again per #21 n/a YES OP YES

Rollback ordering invariants

  1. Pre-activation reversal order is the exact reverse of S04 creation (doc 02 §2.6 enumerated): writer_repoint -> gateway -> plan_payload -> analyzer_contract -> workload_profile -> dynamic_sql_target -> privilege_set -> authority_scope -> quorum_requirement -> activation_policy -> tier -> signoff_requirement -> capability_artifact_requirement -> capability_measurement_requirement -> capability -> bypass_vector -> dependency -> hash_component -> readiness_gate -> principal_separation -> authority_action -> principal_class -> storage_class -> unit -> metric -> operator_primitive -> policy_rule -> manifest_item_envelope -> manifest_set; catalog root last and only when no FK/reference/history exists.

  2. Post-activation never drops; it always creates+activates a prior-payload candidate.

  3. Owner/ACL cutover rollback REQUIRES a captured pre-cutover ownership+ACL snapshot. It is captured at S14, BEFORE the S15.1 ownership transfer and BEFORE any REVOKE (Codex recheck BLOCKER H: the snapshot must precede ownership transfer, not be taken at S16 after directus has already lost ownership) - without it, rollback cannot restore the exact prior owner and grants. The snapshot is PG-native, concrete, and complete (Max-E + Codex BLOCKER 5). Per control object in the sealed U_legacy set it captures:

    • object owner (pg_class.relowner / pg_proc.proowner, resolved to rolname);
    • schema privileges (pg_namespace.nspacl on qt001_cp and any touched schema);
    • table/view privileges - the full relacl: SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER (every privtype, not a subset);
    • function/procedure EXECUTE (proacl);
    • sequence privileges (relacl of every owned sequence);
    • column ACL (pg_attribute.attacl) - table-level relacl does not represent column-level grants, so a column grant would otherwise be silently dropped;
    • default privileges (pg_default_acl) affecting those objects;
    • role memberships / effective privileges (pg_auth_members expansion + aclexplode / has_table_privilege / has_function_privilege with role inheritance) - direct ACL rows alone do not prove the effective privilege a role holds through membership;
    • PUBLIC grants, Directus grants, and qt001_cp_owner/migrator/reader grants, explicitly enumerated;
    • the dependency to pg_roles / pg_auth_members (so a role-drop or membership change is captured; if any package changes role membership it must snapshot and restore it explicitly);
    • a snapshot_sha256 over the whole canonical snapshot (hash-bound). This snapshot is a mandatory output artifact of the stage step S14 (doc 07 PKG-E tail / PKG-F precondition). It must be captured, read-back-verified, and its restore rehearsed BEFORE any ownership transfer or REVOKE (i.e. before S15.1) (MX-3 + Codex recheck BLOCKER H); an unverified or unhashed snapshot blocks the cutover. Verification compares restored effective privilege sets in BOTH directions (pre→post and post→pre), role-membership-aware, not only raw ACL-row equality - G-OWNER-CUTOVER, G-NOLEGACY-POST, and G-U-LEGACY-OPTION-BETA-UNIFORM-ENDSTATE use effective-privilege checks computed over non-superuser, non-owner roles. Superuser disposition (Codex recheck BLOCKER E/H): the cluster superuser workflow_admin (rolsuper=true) inherently bypasses object ACL and cannot be made privilege-zero by ownership/ACL changes; it is excluded from the effective-privilege=0 claim and explicitly recorded as an accepted out-of-band property, not silently passed. Role membership is asserted unchanged by FIX7 packages; if any package changes it, the change is snapshotted and restored explicitly. Because Option Beta changes no object body, the snapshot is the SOLE legacy rollback source — there is no body artifact to capture or restore.
  4. Every rollback returns the system to a safe-blocked state: apply/permit/REAL_RUN/QT001-apply remain blocked; birth-neutral preserved; directus-owned legacy state restorable.

  5. S15 rollback is an explicit, ordered, atomic deactivation-first sequence that cannot leave a mixed old+new authoritative state (Codex BLOCKER 4 / CR-E1). The earlier wording ("the new plane remains present but dormant/superseded") asserted dormancy without an explicit deactivation action; this makes deactivation a first-class, ordered, guard-proven step. The rollback executes strictly in this order, fail-closed at each step:

    1. Supersede the new authoritative path FORWARD (recheck-2 BLOCKER G - forward-only, append-only history): record a NEW manifest_activation of a prior-payload candidate manifest (new activation_id/control_epoch/quorum/evidence) and set the predecessor's superseded_by_manifest_id. No activated_at is cleared or edited and no activation/history row is deleted (CP-01 §2.1/§2.4 immutability). The current active route is derived by the manifest_set partial unique index activated_at IS NOT NULL AND superseded_by_manifest_id IS NULL, which now yields no active manifest for the writer type; the #26 gateway routes fail-closed. G-NOMIXED-AUTHORITY reads this derived current-active fact, never a mutated timestamp.
    2. Verify readiness is BLOCKED (readiness gate facts show blocked) - the new path provides no authority.
    3. Verify the writer gateway cannot route to the new active path (no ACTIVE manifest reachable from the gateway).
    4. Only THEN restore legacy state - for ALL members uniformly, restore the prior owner (directus) + captured effective-privilege ACL by replaying the verified S14 snapshot (the S15.1 ownership transfer and the S15.2 privilege reconcile are reverted). The snapshot is uniquely identified by manifest_activation.rollback_evidence_idevidence_registry.evidence_id (a single approved FK; not a non-unique artifact_sha256 lookup - recheck-2 BLOCKER E); restore fails closed on a missing/revoked/expired evidence row. There is NO body change to restore (Option Beta) — owner-isolation + privilege reconcile already reached effective-EXECUTE = 0 without a stub, so the whole legacy restore is owner + captured ACL. Restoration replays the verified S14 snapshot (which includes the legacy owner and PUBLIC EXECUTE state); it does not issue a fresh blanket GRANT ... TO PUBLIC or set a new owner. So the restored owner+privilege set is exactly the captured prior set - the minimum needed to return to the pre-cutover baseline - never a broader grant.
    5. Verify G-NOMIXED-AUTHORITY (the new active path and any legacy executability are mutually exclusive - it is impossible for both to be active/executable) and G-BIRTH-NEUTRAL (gateway hash unchanged).

    Because the new path is provably inactive before any legacy EXECUTE is restored (steps 1-3 precede step 4), there is no window in which both the new qt001_cp authoritative path and the legacy path are simultaneously executable. The pre-cutover baseline this returns to was itself safe-blocked (QT001 apply has been blocked since Codex NOT_SAFE; no qt001_backfill_permit is open; G-ROLLBACK-SAFE re-asserts these independent blocks). The newly-created qt001_cp control plane is NOT deleted - it is left superseded/inactive (re-attempt re-activates without rebuild). The gateway is never CREATE-OR-REPLACEd - it is the owner-isolated qt001_cp object (and the birth gateway is a HARD_BLOCK boundary). Under Option Beta no legacy object body is ever replaced or restored, so the legacy path performs no function-body operation at all on rollback (the former CR-E3 STUB-body carve-out is removed). If any step cannot prove its safe-blocked condition, the rollback halts fail-closed rather than proceeding to restore executability.

Rollback completeness verdict

ROLLBACK_BLUEPRINT_COMPLETE - every construction step S01..S18 has a defined rollback action, dependency, order, post-verify, operator requirement, and safe-blocked guarantee. The single hard precondition (the S14 pre-cutover ownership/ACL snapshot, captured BEFORE the S15.1 owner transfer per Codex recheck BLOCKER H) is captured as a mandatory package output, not left implicit. Under Option Beta the S15 rollback restores only the prior owner and effective-privilege ACL from that one verified snapshot — there is no body to restore, so the former "restore the STUB bodies from sealed evidence_registry artifacts" step is removed and the body-restore risk surface is eliminated.

Back to Knowledge Hub knowledge/dev/reports/architecture/t1-fix7-existing-system-refactor-execution-blueprint-2026-06-08/05-rollback-blueprint.md