KB-35D7

GPT Review — 22-P3-P1 Policy + Canonical Marker Prompt rev3

6 min read Revision 1
gpt-reviewpack-22p3p1canonical-markerrev4-required

GPT Review — 22-P3-P1 Policy + Canonical Marker Prompt rev3

Date: 2026-05-06
Reviewer: GPT-5.5 Thinking / Incomex Hội đồng AI
Reviewed: knowledge/dev/laws/dieu44-trien-khai/prompts/22-p3-p1-iu-gateway-policy-and-canonical-marker-prompt.md rev3

Verdict

Do not dispatch rev3. Rev4 required.

Rev3 fixes the big idempotency blocker: CREATE OR REPLACE is now shell-branched and will not run in PATCHED_EXACT. That is the right direction.

However, a few last shell-safety/report-safety issues remain. These are small but real: under failure paths, the script can still abort before final verdict due to unset variables, and final verdict can pass without proving all 9 policy keys exist.

Required rev4 patches

P1 — Initialize KEY_COUNT and avoid unset-variable failure

Rev3 echoes:

echo "gateway_keys=$KEY_COUNT"

But KEY_COUNT is only set inside if [ $PSQL_EXIT -eq 0 ]; then .... If SQL fails, KEY_COUNT is unset and set -u can terminate the script before final report.

Patch:

KEY_COUNT="NOT_RUN"

at initialization.

P2 — Final verdict must require KEY_COUNT=9

Policy keys are half of P3-P1. Rev3 verifies key count post-commit but does not use it in final verdict.

Patch final condition:

if [ $PSQL_EXIT -eq 0 ] && [ $POST_EXIT -eq 0 ] && [ "$POST_STATUS" = "PASS" ] && [ "$LEAK_STATUS" = "PASS" ] && [ "$KEY_COUNT" = "9" ]; then

If KEY_COUNT is not 9, phase FAIL / P3P2 BLOCKED.

P3 — Normalize KEY_COUNT output

The key-count query can return noisy output or fail. Normalize it:

KEY_COUNT=$(echo "$KEY_COUNT" | tr -d '[:space:]')
if ! [[ "$KEY_COUNT" =~ ^[0-9]+$ ]]; then
  KEY_COUNT="INVALID_OUTPUT"
fi

P4 — Patch state detection failure/empty result must STOP safely

Rev3 only blocks UNKNOWN_PATCH_STATE. If the detection query fails or returns empty, the script proceeds with an invalid branch.

Patch:

if [ "$PATCH_STATE" != "PATCHED_EXACT" ] && [ "$PATCH_STATE" != "UNPATCHED" ]; then
  echo "STOP: invalid patch_state=$PATCH_STATE"
  echo "phase_status=BLOCKED"
  echo "=== UPLOAD REPORT NOW ==="
  exit 0
fi

Keep explicit UNKNOWN_PATCH_STATE handling.

P5 — Validate pilot address before SQL

Rev3 embeds PILOT_ADDRESS into the generated SQL DO block. It is generated internally, but writer prompts should still validate before use.

Add strict regex:

if ! [[ "$PILOT_ADDRESS" =~ ^pilot\.p3\.p1\.[0-9]{8}-[0-9]{6}\.[0-9a-f]{8}$ ]]; then
  echo "STOP: invalid pilot address: $PILOT_ADDRESS"
  echo "phase_status=BLOCKED"
  echo "=== UPLOAD REPORT NOW ==="
  exit 0
fi

P6 — PUBLIC EXECUTE check should cover both fn_iu_create and fn_iu_create_plan

Rev3 checks only fn_iu_create. Since P3-P1 policy references both canonical and plan functions, check both:

WHERE routine_schema='public'
  AND routine_name IN ('fn_iu_create','fn_iu_create_plan')
  AND grantee='PUBLIC'

P7 — Directus effective execute should be machine-checked

Rev3 displays routine privileges, but final safety should assert directus can execute fn_iu_create after patch.

Add DO block before COMMIT:

DO $$
BEGIN
  IF NOT has_function_privilege('directus', 'public.fn_iu_create(text,text,text,text,text,text,text,text,uuid)', 'EXECUTE') THEN
    RAISE EXCEPTION 'directus lacks EXECUTE on fn_iu_create';
  END IF;
END $$;

P8 — Trigger-count unchanged should be machine-checked, not display-only

Rev3 displays before/after trigger counts but does not assert they match. Since P3-P1 must not create trigger guard, add expected count variables inside SQL or a simple DO block:

  • capture pre-counts into temp settings or temp variables in transaction;
  • after pilot, compare counts;
  • if changed, raise exception.

Keep it simple. Example with transaction-local temp table is acceptable:

CREATE TEMP TABLE p3p1_baseline(k text primary key, v int) ON COMMIT DROP;
INSERT INTO p3p1_baseline VALUES ('iu_triggers', ...), ('uv_triggers', ...);
...
DO $$
DECLARE v_iu int; v_uv int;
BEGIN
  SELECT count(*) INTO v_iu FROM pg_trigger ... information_unit ...;
  SELECT count(*) INTO v_uv FROM pg_trigger ... unit_version ...;
  IF v_iu <> (SELECT v FROM p3p1_baseline WHERE k='iu_triggers') THEN RAISE EXCEPTION ...; END IF;
  IF v_uv <> (SELECT v FROM p3p1_baseline WHERE k='uv_triggers') THEN RAISE EXCEPTION ...; END IF;
END $$;

P9 — Report should include function_replace branch even on early STOP

If early STOP occurs due invalid patch state or invalid pilot address, report should still include:

  • patch_state
  • function_replace=NOT_RUN
  • phase_status=BLOCKED
  • reason.

Directive to Opus

Patch P3-P1 prompt to rev4 with P1–P9.

The rev3 direction is acceptable; do not redesign. This is last-mile hardening only.

Do not dispatch after patch; return for GPT/User approval.

Hard boundaries remain

  • no trigger guard creation;
  • no GRANT/REVOKE;
  • no Directus permission changes;
  • no role separation;
  • no detector implementation;
  • no DOT registration;
  • no adapter implementation;
  • no cleanup pilots;
  • no Pack 2C.

Summary

Rev3 solved the stale-body clobber issue. Rev4 should prevent failure-path shell aborts and ensure the final PASS proves all required outcomes: SQL success, post-commit invariant success, marker no-leak, exactly 9 policy keys, no PUBLIC execute, directus execute intact, and trigger counts unchanged.

Back to Knowledge Hub knowledge/dev/laws/dieu44-trien-khai/reviews/gpt-review-22-p3-p1-policy-marker-prompt-rev3-2026-05-06.md