Authority P1 Hardening — 01 P0 Reverification + P1 Gaps
01 — P0 Reverification + P1 Gap Proof
P0 containment still holds (live)
Live read of fn_auto_approve_add confirms the P0 fix is intact: for action='add' it only appends a review-note marker and keeps status='pending'; it no longer sets NEW.status := 'approved' at INSERT. The trigger trg_apr_auto_approve is still present and enabled (not globally disabled). Guard v_authority_p0_still_contained_guard returns PASS on all three assertions (insert_add_not_autoapproved, containment_marker_present, auto_approve_trigger_preserved).
Approval lifecycle (live triggers on approval_requests)
- BEFORE INSERT:
fn_approval_auto_code(code),fn_auto_approve_add(P0-patched),fn_birth_registry_auto(AFTER INSERT, births). - BEFORE UPDATE OF status:
fn_enforce_apr_lifecycle(pending→approved/rejected/expired; approved→applied/rejected; applied/rejected/expired terminal). - BEFORE UPDATE OF status WHEN new=approved AND old=pending:
fn_apr_quorum_check(quorum by risk). - BEFORE UPDATE WHEN new=applied AND old<>applied:
fn_apr_block_unimplemented_handler(apply guard).
The two P1 gaps — proven live, not assumed
P1a scanner auto-apply ungated. auto_apply_approval() loops over pending dot-orphan-scanner / dot-misclass-scanner rows and updates them to applied with no vote/quorum check whatsoever. It is wired to a host cron (daily 04h30 CEST). Currently a daily no-op only because no matching pending rows exist (last scanner rows created 2026-03-28); it is a loaded-but-idle path.
P1b no apply-time quorum re-proof. The only guard at the approved→applied transition was fn_apr_block_unimplemented_handler, which checked only handler_ref and returned early when proposed_action_code IS NULL. Quorum was enforced only at pending→approved. So a row that reached approved without genuine quorum (e.g. a null-action-code graceful pass, or any future bypass) could be applied with zero votes.
Live rehearsal proof (BEGIN..ROLLBACK, birth-neutral)
Run against production in a rolled-back transaction (file 00b_rehearsal.sql):
| Test | Scenario | Result |
|---|---|---|
| T1 | INSERT action=add → stays pending | PASS |
| T2 | pending→approved, high-risk, 0 votes → blocked | PASS |
| T3 | null-action 0-vote approved→applied (PRE-FIX) | GAP-CONFIRMED (reached applied) |
| T4 | same, AFTER fix → blocked | PASS |
| T5 | quorumed low-risk approved→applied under fix | PASS (applies) |
| T6 | rejected→applied | PASS (blocked) |
| T7 | scanner gate: auto_apply skips no-vote scanner row | PASS (returns 0) |
birth before 1,210,800 == after-rollback 1,210,800; trigger_guard_alerts 129==129==129.
T3 is the decisive live proof that P1b was a real exposure, not a theoretical one. After apply, a fresh committed-state BEGIN..ROLLBACK test (LIVE-NEG / LIVE-POS) re-confirmed: the committed guard blocks the null-action 0-vote apply and still admits a properly quorumed apply.