T1 FIX7 Blueprint Patch - G-NOLEGACY Phase Fix (BLOCKER 2)
03 - BLOCKER 2: G-NOLEGACY Phase-Deadlock Fix
Codex finding
A single G-NOLEGACY was required green before PKG-F, but PKG-F is the step that revokes EXECUTE
and makes its ACL clause green. PKG-D ran the full guard while every legacy routine was still
PUBLIC-executable; S15 listed it as proof after the step. This is a deadlock / false-green invite.
(Codex CHECK_G FAIL.)
The fix - split into phase-specific contracts (blueprint doc 06)
G-NOLEGACY is replaced by two phase-correct guards (no readiness gate added):
- G-NOLEGACY-PRE (gates the cutover; run at S13/PKG-D and as the S15 in-transaction precondition):
a structural/closure + readiness proof that does NOT require EXECUTE already revoked. It asserts:
dependency_manifest#11 closure from the new entrypoints reaches 0 legacy objects (recursive, non-vacuous — roots exist, traversal non-empty); the sealed legacy-disposition set is complete (0 unknown, both-EXCEPT vs catalog empty); every member has exactly one disposition; rollback artifacts staged (pinned #27 source for STUB_FAIL_CLOSED, captured ACL for REVOKE_ONLY). - G-NOLEGACY-POST (verifies the cutover; run after S15 and at S19): over the sealed set,
non-owner effective EXECUTE (role-membership expanded via
pg_auth_members) = 0; every STUB_FAIL_CLOSED member is fail-closed; REVOKE_ONLY members are EXECUTE-revoked with body unchanged. Non-vacuous (the sealed set is non-empty and the check ran over all of it).
Package/order mapping (blueprint docs 04, 07)
- PKG-D / S13 gate =
G-NOLEGACY-PREonly. PKG-D explicitly never runs the post-state guard, so it does not falsely require EXECUTE already revoked while legacy is still PUBLIC-executable. - PKG-F / S15 precondition =
G-NOLEGACY-PRE; post-proof =G-NOLEGACY-POST. - S19 / PKG-I re-runs
G-NOLEGACY-POST.
The impossible "POST must pass before the action that creates POST state" is removed: PRE gates the action, POST verifies it.
Self-check
PASS only if the PRE/POST split resolves the deadlock → PASS. PRE is satisfiable before any REVOKE (it is a structural/closure/completeness proof); POST is only asserted after the REVOKE. The non-vacuity rule (guard-quality rule 1) still binds both, so neither can pass via an empty/mis-rooted computation.