GPT Review — 22-P3-P2 Trigger Guard Prompt rev5
GPT Review — 22-P3-P2 Trigger Guard Prompt rev5
Date: 2026-05-06
Reviewer: GPT-5.5 Thinking / Incomex Hội đồng AI
Reviewed:knowledge/dev/laws/dieu44-trien-khai/prompts/22-p3-p2-iu-gateway-trigger-guard-prompt.mdrev5
Verdict
Do not dispatch rev5. Rev6 required with 1 conceptual fix + 3 small hardening fixes.
Rev5 is very close and has the right structure. The main remaining issue is state consistency if deployment commits but a later test/final verify fails. In that case the prompt may leave guard triggers active while gateway.mode is prepared, or leave an enforced guard after a failed phase. That is exactly the kind of half-state a gateway pack must avoid.
This review is intentionally comprehensive to reduce further rounds. Apply only the patches below; do not redesign.
Blocking issue
P1 — Cleanup must run for any final failure after guard deployment, not only early test failure
Rev5 cleanup runs only when:
ALL_PASS=false && PSQL_EXIT=0
But there are other failure paths after guard deployment:
- all tests pass, but
MODE_UPDATEfails; - mode becomes
enforced, then post-commit invariant verify fails; - mode becomes
enforced, then leak verify fails; - final verify returns invalid/noisy output;
- any late final condition fails after TX1 already committed guard triggers.
Rev5 only resets mode in some of these cases. That is not enough, because the guard triggers/functions remain active. The system may be physically enforced while policy says prepared, or phase fails while guard is still deployed.
Patch policy:
If
FINAL_OK=falseafter TX1 succeeded, run explicit cleanup unless cleanup has already run.
Cleanup must:
BEGIN;
DROP TRIGGER IF EXISTS trg_iu_gateway_write_guard ON public.information_unit;
DROP TRIGGER IF EXISTS trg_uv_gateway_write_guard ON public.unit_version;
DROP FUNCTION IF EXISTS public.fn_iu_gateway_write_guard();
UPDATE public.dot_config
SET value='prepared', updated_at=now()
WHERE key='iu_create.gateway.mode';
COMMIT;
This cleanup is not optional. It is the rollback path for an enforcement deployment.
Copy-ready shell patch for P1
Add variables near init:
GUARD_CLEANUP_DONE=false
CLEANUP_REASON="NOT_RUN"
Replace the current early rollback block with a reusable cleanup helper:
cleanup_guard() {
CLEANUP_REASON="$1"
if [ "$GUARD_CLEANUP_DONE" = true ]; then
echo "cleanup_guard skipped: already done ($CLEANUP_REASON)" | tee -a "$LOG_PATH"
return
fi
echo "--- Cleanup guard: $CLEANUP_REASON ---" | tee -a "$LOG_PATH"
set +e
"${PSQL_CMD[@]}" >> "$LOG_PATH" 2>&1 <<'CLEANSQL'
BEGIN;
DROP TRIGGER IF EXISTS trg_iu_gateway_write_guard ON public.information_unit;
DROP TRIGGER IF EXISTS trg_uv_gateway_write_guard ON public.unit_version;
DROP FUNCTION IF EXISTS public.fn_iu_gateway_write_guard();
UPDATE public.dot_config SET value='prepared', updated_at=now()
WHERE key='iu_create.gateway.mode';
COMMIT;
CLEANSQL
ROLLBACK_EXIT=$?
if [ $ROLLBACK_EXIT -eq 0 ]; then ROLLBACK_STATUS="PASS"; else ROLLBACK_STATUS="FAIL"; fi
GUARD_CLEANUP_DONE=true
echo "ROLLBACK_EXIT=$ROLLBACK_EXIT rollback_status=$ROLLBACK_STATUS cleanup_reason=$CLEANUP_REASON" | tee -a "$LOG_PATH"
set -uo pipefail
}
After direct tests, keep immediate cleanup for failed tests:
if [ "$ALL_PASS" = false ] && [ $PSQL_EXIT -eq 0 ]; then
cleanup_guard "tests_failed"
fi
After final verification computes FINAL_OK, add:
if [ "$FINAL_OK" = false ] && [ $PSQL_EXIT -eq 0 ] && [ "$GUARD_CLEANUP_DONE" = false ]; then
cleanup_guard "final_verify_failed"
GW_MODE=$("${PSQL_RO[@]}" -c "SELECT value FROM public.dot_config WHERE key='iu_create.gateway.mode';" 2>/dev/null | tr -d '[:space:]')
fi
Then remove or fold the separate MODE_RESET path into cleanup_guard. If Opus keeps MODE_RESET_* variables for reporting, set them to NOT_RUN and do not use them as the main restore path. The important thing is: failed phase after TX1 must not leave active guard triggers behind.
Small hardening fixes
P2 — Final POST_RESULT still uses psql variable inside SQL; make it GUC-style for consistency
This is not inside a DO block, so it may work. But to avoid another quoting edge case and keep the prompt uniform, patch final verify to:
SELECT set_config('app.p3p2_pilot_addr', :'pilot_addr', false);
SELECT CASE WHEN COALESCE((v.vj->>'all_pass')::boolean,false) THEN 'PASS' ELSE 'CRITICAL' END
FROM (SELECT public.fn_iu_verify_invariants(current_setting('app.p3p2_pilot_addr')) AS vj) v;
Then shell should take the last line or use a query that only outputs the final status. Simpler:
POST_RESULT=$("${PSQL_RO[@]}" -v pilot_addr="$PILOT_ADDRESS" <<'PQL'
SELECT set_config('app.p3p2_pilot_addr', :'pilot_addr', false);
SELECT CASE WHEN COALESCE((v.vj->>'all_pass')::boolean,false) THEN 'PASS' ELSE 'CRITICAL' END
FROM (SELECT public.fn_iu_verify_invariants(current_setting('app.p3p2_pilot_addr')) AS vj) v;
PQL
)
POST_STATUS=$(echo "$POST_RESULT" | tail -n 1 | tr -d '[:space:]')
P3 — UV INSERT leak check was removed; restore it
Rev4 had a check that no unit_version row with version_seq=999 was inserted. Rev5 removed it. Restore after the UV INSERT exception block:
IF EXISTS(SELECT 1 FROM public.unit_version uv WHERE uv.version_seq=999 AND uv.unit_id=v_uid) THEN
RAISE EXCEPTION 'UV INSERT leaked';
END IF;
This catches a guard failure that inserts a row and later raises some other error.
P4 — Early STOP should include p3p3 readiness
Patch early_stop() to include:
echo "p3p3_readiness=BLOCKED" | tee -a "$LOG_PATH"
This keeps machine fields consistent even in preflight blocks.
Final verdict logic after rev6
Use three-tier status:
PASSonly ifFINAL_OK=trueand no cleanup was needed.CRITICALif cleanup was required and failed.FAILif deployment/tests failed but cleanup succeeded or no guard was deployed.
Copy-ready final logic:
if [ "$FINAL_OK" = true ]; then
echo "phase_status=PASS" | tee -a "$LOG_PATH"
echo "p3p3_readiness=READY" | tee -a "$LOG_PATH"
elif [ "$ROLLBACK_STATUS" = "FAIL" ]; then
echo "phase_status=CRITICAL" | tee -a "$LOG_PATH"
echo "p3p3_readiness=BLOCKED" | tee -a "$LOG_PATH"
echo "CRITICAL: guard cleanup failed — manual review needed" | tee -a "$LOG_PATH"
else
echo "phase_status=FAIL" | tee -a "$LOG_PATH"
echo "p3p3_readiness=BLOCKED" | tee -a "$LOG_PATH"
fi
Report fields should include:
echo "cleanup_done=$GUARD_CLEANUP_DONE" | tee -a "$LOG_PATH"
echo "cleanup_reason=$CLEANUP_REASON" | tee -a "$LOG_PATH"
echo "rollback_status=$ROLLBACK_STATUS" | tee -a "$LOG_PATH"
Do not change
- Keep separate sessions.
- Keep GUC pilot handling.
- Keep SECURITY DEFINER + REVOKE PUBLIC.
- Keep direct INSERT/UPDATE block tests for both IU and UV.
- Keep no table permission changes.
- Keep no Directus/DOT/adapter/detector/role-separation scope.
- Do not add new architecture.
Directive to Opus
Patch P3-P2 prompt to rev6 with P1–P4 only.
This should be the final review round if applied cleanly. The key is state consistency: a failed enforcement pack must either pass fully or restore the gateway to prepared with no active guard.
Return rev6 for final approval. Do not dispatch.
Summary
Rev5 is almost ready but still can leave a half-enforced system when late checks fail. Rev6 must use one cleanup path for any failed final state after guard deployment. The rest is small consistency hardening.