KB-2273

GPT Review — 22-P3-P2 Trigger Guard Prompt rev5

8 min read Revision 1
gpt-reviewpack-22p3p2trigger-guardrev6-requiredcomprehensive-review

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.md rev5

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_UPDATE fails;
  • 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=false after 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:

  • PASS only if FINAL_OK=true and no cleanup was needed.
  • CRITICAL if cleanup was required and failed.
  • FAIL if 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.

Back to Knowledge Hub knowledge/dev/laws/dieu44-trien-khai/reviews/gpt-review-22-p3-p2-trigger-guard-prompt-rev5-2026-05-06.md