KB-7AC5 rev 7

22-P3-P2 — IU Gateway Trigger Guard Deployment Prompt (rev7)

21 min read Revision 7
pack-22p3p2gatewaytrigger-guardpromptrev7

22-P3-P2 — IU Gateway Trigger Guard Deployment (rev7)

Date: 2026-05-06 | Status: PROMPT rev7 — chờ approve + dispatch Rev7: rename triggers trg_aa_iu/uv_gateway_write_guard (fire before birth gate) Rev6 proved: cleanup works, no half-enforced. Only naming fix needed.


#!/usr/bin/env bash
# 22-P3-P2 rev7 — IU Gateway Trigger Guard
set -uo pipefail

PG_CONTAINER="${PG_CONTAINER:-postgres}"
PG_USER="${PG_USER:-directus}"
PG_DB="${PG_DB:-directus}"
PSQL_CMD=(docker exec -i "$PG_CONTAINER" psql -v ON_ERROR_STOP=1 -U "$PG_USER" -d "$PG_DB")
PSQL_RO=(docker exec -i "$PG_CONTAINER" psql -v ON_ERROR_STOP=1 -U "$PG_USER" -d "$PG_DB" -tA)

LOG_PATH="/tmp/22-p3-p2.$(date -u +%Y%m%d-%H%M%S).log"
PSQL_EXIT=0; CAN_EXIT=0; BLOCK_EXIT=0; MODE_EXIT=0; POST_EXIT=0
ROLLBACK_EXIT=0; ROLLBACK_STATUS="NOT_RUN"
GUARD_CLEANUP_DONE=false; CLEANUP_REASON="NOT_RUN"
POST_STATUS="NOT_RUN"; LEAK_STATUS="NOT_RUN"; CANONICAL_STATUS="NOT_RUN"
IU_INSERT_BLOCK="NOT_RUN"; UV_INSERT_BLOCK="NOT_RUN"
IU_UPDATE_BLOCK="NOT_RUN"; UV_UPDATE_BLOCK="NOT_RUN"
TRG_COUNT_STATUS="NOT_RUN"; GW_MODE="NOT_RUN"

make_uuid() {
  if command -v uuidgen >/dev/null 2>&1; then uuidgen | tr 'A-F' 'a-f'
  elif [ -r /proc/sys/kernel/random/uuid ]; then cat /proc/sys/kernel/random/uuid
  else "${PSQL_RO[@]}" -c "SELECT gen_random_uuid()" 2>/dev/null; fi
}
early_stop() {
  echo "STOP: $1" | tee -a "$LOG_PATH"; echo "phase_status=BLOCKED" | tee -a "$LOG_PATH"
  echo "p3p3_readiness=BLOCKED" | tee -a "$LOG_PATH"; echo "reason=$1" | tee -a "$LOG_PATH"
  echo "=== UPLOAD REPORT NOW ===" | tee -a "$LOG_PATH"; exit 0
}
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_aa_iu_gateway_write_guard ON public.information_unit;
DROP TRIGGER IF EXISTS trg_aa_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
}

PILOT_ADDRESS="pilot.p3.p2.$(date -u +%Y%m%d-%H%M%S).$(make_uuid | cut -c1-8)"
echo "=== P3-P2 rev7 ===" | tee "$LOG_PATH"
echo "PILOT=$PILOT_ADDRESS" | tee -a "$LOG_PATH"
if ! [[ "$PILOT_ADDRESS" =~ ^pilot\.p3\.p2\.[0-9]{8}-[0-9]{6}\.[0-9a-f]{8}$ ]]; then early_stop "invalid pilot: $PILOT_ADDRESS"; fi

# === PREFLIGHT ===
set +e
MARKER_CHECK=$("${PSQL_RO[@]}" -c "SELECT CASE WHEN prosrc LIKE E'%set\\_config(''app.canonical\\_writer''%' THEN 'OK' ELSE 'MISSING' END FROM pg_proc WHERE proname='fn_iu_create';" 2>/dev/null | tr -d '[:space:]')
echo "marker_in_fn=$MARKER_CHECK" | tee -a "$LOG_PATH"
[ "$MARKER_CHECK" != "OK" ] && early_stop "fn_iu_create missing marker"
GUARD_FN=$("${PSQL_RO[@]}" -c "SELECT to_regprocedure('public.fn_iu_gateway_write_guard()') IS NOT NULL;" 2>/dev/null | tr -d '[:space:]')
echo "guard_fn_exists=$GUARD_FN" | tee -a "$LOG_PATH"
if [ "$GUARD_FN" != "t" ] && [ "$GUARD_FN" != "f" ]; then early_stop "invalid guard_fn=$GUARD_FN"; fi
[ "$GUARD_FN" = "t" ] && early_stop "guard function already exists"
GUARD_TRG=$("${PSQL_RO[@]}" -c "SELECT count(*) FROM pg_trigger WHERE NOT tgisinternal AND ((tgrelid='public.information_unit'::regclass AND tgname='trg_aa_iu_gateway_write_guard') OR (tgrelid='public.unit_version'::regclass AND tgname='trg_aa_uv_gateway_write_guard'));" 2>/dev/null | tr -d '[:space:]')
echo "guard_trg_count=$GUARD_TRG" | tee -a "$LOG_PATH"
if ! [[ "$GUARD_TRG" =~ ^[0-9]+$ ]]; then early_stop "invalid guard_trg=$GUARD_TRG"; fi
[ "$GUARD_TRG" != "0" ] && early_stop "gateway triggers exist ($GUARD_TRG)"
set -uo pipefail

# === TX1: DEPLOY ===
echo "--- TX1: Deploy ---" | tee -a "$LOG_PATH"
set +e
"${PSQL_CMD[@]}" > "$LOG_PATH.tx1" 2>&1 <<'TX1SQL'
DO $$ DECLARE v_c int; BEGIN
  WITH required(key) AS (VALUES
    ('iu_create.gateway.mode'),('iu_create.gateway.canonical_function'),('iu_create.gateway.plan_function'),
    ('iu_create.gateway.marker_key'),('iu_create.gateway.marker_value'),('iu_create.gateway.direct_insert_policy'),
    ('iu_create.gateway.policy_doc_path'),('iu_create.gateway.readme_path'),('iu_create.gateway.exempt_policy'))
  SELECT count(*) INTO v_c FROM required r JOIN public.dot_config d USING (key);
  IF v_c!=9 THEN RAISE EXCEPTION 'keys: %/9',v_c; END IF;
END $$;

BEGIN;
CREATE TEMP TABLE _bl(k text primary key, v int) ON COMMIT DROP;
INSERT INTO _bl(k,v) VALUES
  ('iu',(SELECT count(*) FROM pg_trigger WHERE tgrelid='public.information_unit'::regclass AND NOT tgisinternal)),
  ('uv',(SELECT count(*) FROM pg_trigger WHERE tgrelid='public.unit_version'::regclass AND NOT tgisinternal));
SELECT k,v FROM _bl ORDER BY k;

CREATE FUNCTION public.fn_iu_gateway_write_guard()
RETURNS trigger LANGUAGE plpgsql SECURITY DEFINER SET search_path=pg_catalog,public AS $$
DECLARE v_mk text;v_mv text;v_cur text;v_readme text;v_canon text;
BEGIN
  SELECT value INTO v_mk FROM public.dot_config WHERE key='iu_create.gateway.marker_key';
  SELECT value INTO v_mv FROM public.dot_config WHERE key='iu_create.gateway.marker_value';
  v_mk:=COALESCE(v_mk,'app.canonical_writer'); v_mv:=COALESCE(v_mv,'fn_iu_create');
  v_cur:=COALESCE(current_setting(v_mk,true),'');
  IF v_cur=v_mv THEN RETURN NEW; END IF;
  SELECT value INTO v_readme FROM public.dot_config WHERE key='iu_create.gateway.readme_path';
  SELECT value INTO v_canon FROM public.dot_config WHERE key='iu_create.gateway.canonical_function';
  RAISE EXCEPTION 'IU Gateway blocked: direct % on "%" not permitted. Use canonical: %. README: %',
    TG_OP,TG_TABLE_NAME,COALESCE(v_canon,'fn_iu_create(...)'),COALESCE(v_readme,'(see dot_config)');
END;$$;

REVOKE ALL ON FUNCTION public.fn_iu_gateway_write_guard() FROM PUBLIC;

-- Name prefix `trg_aa_` is intentional: gateway wrong-door blocker must fire
-- before downstream business gates (e.g. birth gate L1 = trg_iu_birth_*)
-- so callers receive canonical README/function guidance, not domain errors.
CREATE TRIGGER trg_aa_iu_gateway_write_guard BEFORE INSERT OR UPDATE ON public.information_unit FOR EACH ROW EXECUTE FUNCTION public.fn_iu_gateway_write_guard();
CREATE TRIGGER trg_aa_uv_gateway_write_guard BEFORE INSERT OR UPDATE ON public.unit_version FOR EACH ROW EXECUTE FUNCTION public.fn_iu_gateway_write_guard();

DO $$ BEGIN IF to_regprocedure('public.fn_iu_gateway_write_guard()') IS NULL THEN RAISE EXCEPTION 'guard fn missing'; END IF; END $$;
DO $$ DECLARE v_sd boolean;v_cfg text[]; BEGIN
  SELECT prosecdef,proconfig INTO v_sd,v_cfg FROM pg_proc WHERE proname='fn_iu_gateway_write_guard';
  IF NOT v_sd THEN RAISE EXCEPTION 'not SECDEF'; END IF;
  IF NOT ('search_path=pg_catalog, public'=ANY(v_cfg) OR 'search_path=pg_catalog,public'=ANY(v_cfg)) THEN RAISE EXCEPTION 'search_path: %',v_cfg; END IF;
END $$;
DO $$ DECLARE v_c int; BEGIN
  SELECT count(*) INTO v_c FROM pg_trigger WHERE NOT tgisinternal AND tgrelid='public.information_unit'::regclass AND tgname='trg_aa_iu_gateway_write_guard';
  IF v_c!=1 THEN RAISE EXCEPTION 'IU guard=%',v_c; END IF;
  SELECT count(*) INTO v_c FROM pg_trigger WHERE NOT tgisinternal AND tgrelid='public.unit_version'::regclass AND tgname='trg_aa_uv_gateway_write_guard';
  IF v_c!=1 THEN RAISE EXCEPTION 'UV guard=%',v_c; END IF;
END $$;
DO $$ DECLARE v_bad int; BEGIN
  SELECT count(*) INTO v_bad FROM pg_trigger WHERE tgname IN ('trg_aa_iu_gateway_write_guard','trg_aa_uv_gateway_write_guard') AND tgenabled<>'O';
  IF v_bad!=0 THEN RAISE EXCEPTION 'not enabled: %',v_bad; END IF;
END $$;
DO $$ DECLARE v_def text; BEGIN
  SELECT pg_get_triggerdef(oid) INTO v_def FROM pg_trigger WHERE tgname='trg_aa_iu_gateway_write_guard';
  IF v_def NOT LIKE '%BEFORE INSERT OR UPDATE%' AND v_def NOT LIKE '%BEFORE UPDATE OR INSERT%' THEN RAISE EXCEPTION 'IU def: %',v_def; END IF;
  SELECT pg_get_triggerdef(oid) INTO v_def FROM pg_trigger WHERE tgname='trg_aa_uv_gateway_write_guard';
  IF v_def NOT LIKE '%BEFORE INSERT OR UPDATE%' AND v_def NOT LIKE '%BEFORE UPDATE OR INSERT%' THEN RAISE EXCEPTION 'UV def: %',v_def; END IF;
END $$;
DO $$ DECLARE v_ib int;v_ub int;v_ia int;v_ua int; BEGIN
  SELECT v INTO v_ib FROM _bl WHERE k='iu'; SELECT v INTO v_ub FROM _bl WHERE k='uv';
  SELECT count(*) INTO v_ia FROM pg_trigger WHERE tgrelid='public.information_unit'::regclass AND NOT tgisinternal;
  SELECT count(*) INTO v_ua FROM pg_trigger WHERE tgrelid='public.unit_version'::regclass AND NOT tgisinternal;
  IF v_ia!=v_ib+1 THEN RAISE EXCEPTION 'IU trg:%->%',v_ib,v_ia; END IF;
  IF v_ua!=v_ub+1 THEN RAISE EXCEPTION 'UV trg:%->%',v_ub,v_ua; END IF;
  RAISE NOTICE 'TRIGGER_COUNT_OK: IU=% UV=%',v_ia,v_ua;
END $$;
DO $$ DECLARE v_c int; BEGIN
  SELECT count(*) INTO v_c FROM information_schema.routine_privileges WHERE routine_schema='public' AND routine_name='fn_iu_gateway_write_guard' AND grantee='PUBLIC';
  IF v_c>0 THEN RAISE EXCEPTION 'PUBLIC EXECUTE'; END IF;
END $$;

COMMIT;
TX1SQL
PSQL_EXIT=$?
echo "TX1_EXIT=$PSQL_EXIT" | tee -a "$LOG_PATH"
cat "$LOG_PATH.tx1" >> "$LOG_PATH"; cat "$LOG_PATH.tx1"
set -uo pipefail
if [ $PSQL_EXIT -ne 0 ]; then
  echo "TX1 FAILED" | tee -a "$LOG_PATH"; echo "phase_status=FAIL" | tee -a "$LOG_PATH"
  echo "p3p3_readiness=BLOCKED" | tee -a "$LOG_PATH"; echo "=== UPLOAD REPORT NOW ===" | tee -a "$LOG_PATH"; exit 0
fi
TRG_COUNT_STATUS="PASS"

# === CANONICAL TEST (fresh session) ===
echo "--- Canonical Create ---" | tee -a "$LOG_PATH"
set +e
"${PSQL_CMD[@]}" -v pilot_addr="$PILOT_ADDRESS" > "$LOG_PATH.canonical" 2>&1 <<'CANSQL'
SELECT set_config('app.p3p2_pilot_addr', :'pilot_addr', false);
DO $$ DECLARE v_r jsonb;v_v jsonb;v_i jsonb;v_c bigint;v_a text; BEGIN
  v_a:=current_setting('app.p3p2_pilot_addr');
  v_r:=public.fn_iu_create(v_a,'P3-P2 Guard Test','Content by P3-P2.','agent:p3-p2-test');
  IF v_r->>'status'!='created' THEN RAISE EXCEPTION 'create: %',v_r->>'status'; END IF;
  IF NOT COALESCE((v_r->>'invariants_verified')::boolean,false) THEN RAISE EXCEPTION 'inv_flag'; END IF;
  v_v:=public.fn_iu_verify_invariants(v_a);
  IF NOT COALESCE((v_v->>'all_pass')::boolean,false) THEN RAISE EXCEPTION 'inv: %',v_v; END IF;
  SELECT count(*) INTO v_c FROM public.information_unit WHERE canonical_address=v_a;
  IF v_c!=1 THEN RAISE EXCEPTION 'IU=%',v_c; END IF;
  v_i:=public.fn_iu_create(v_a,'X','X','a');
  IF v_i->>'status'!='exists_complete' THEN RAISE EXCEPTION 'idem: %',v_i->>'status'; END IF;
  RAISE NOTICE 'CANONICAL_CREATE=PASS %',v_a;
END $$;
CANSQL
CAN_EXIT=$?
echo "CAN_EXIT=$CAN_EXIT" | tee -a "$LOG_PATH"
cat "$LOG_PATH.canonical" >> "$LOG_PATH"; cat "$LOG_PATH.canonical"
if [ $CAN_EXIT -eq 0 ] && grep -q 'CANONICAL_CREATE=PASS' "$LOG_PATH.canonical"; then CANONICAL_STATUS="PASS"; else CANONICAL_STATUS="FAIL"; fi
set -uo pipefail

# === DIRECT BLOCK TESTS (fresh session, NO marker) ===
if [ "$CANONICAL_STATUS" != "PASS" ]; then
  echo "SKIP block tests — canonical failed" | tee -a "$LOG_PATH"
else
  echo "--- Direct Block Tests ---" | tee -a "$LOG_PATH"
  set +e
  "${PSQL_CMD[@]}" -v pilot_addr="$PILOT_ADDRESS" > "$LOG_PATH.block" 2>&1 <<'BLOCKSQL'
SELECT set_config('app.p3p2_pilot_addr', :'pilot_addr', false);

DO $$ DECLARE v_ok boolean:=false;v_msg text; BEGIN
  BEGIN INSERT INTO public.information_unit(id,canonical_address,unit_kind,owner_ref,created_by,updated_by,identity_profile) VALUES(gen_random_uuid(),'test.p3p2.direct.block','design_doc_section','t','t','t','{}'::jsonb);
  EXCEPTION WHEN OTHERS THEN v_msg:=SQLERRM;
    IF v_msg LIKE '%IU Gateway blocked%' AND (v_msg LIKE '%fn_iu_create%' OR v_msg LIKE '%canonical%') AND (v_msg LIKE '%README%' OR v_msg LIKE '%readme%') THEN v_ok:=true;
    ELSE RAISE EXCEPTION 'IU INSERT wrong: %',v_msg; END IF;
  END;
  IF NOT v_ok THEN RAISE EXCEPTION 'IU INSERT not blocked'; END IF;
  IF EXISTS(SELECT 1 FROM public.information_unit WHERE canonical_address='test.p3p2.direct.block') THEN RAISE EXCEPTION 'IU INSERT leaked'; END IF;
  RAISE NOTICE 'IU_INSERT_BLOCK=PASS';
END $$;

DO $$ DECLARE v_ok boolean:=false;v_msg text;v_uid uuid; BEGIN
  SELECT id INTO v_uid FROM public.information_unit WHERE canonical_address=current_setting('app.p3p2_pilot_addr');
  IF v_uid IS NULL THEN RAISE EXCEPTION 'no pilot IU'; END IF;
  BEGIN INSERT INTO public.unit_version(id,unit_id,body,content_hash,version_seq,created_by) VALUES(gen_random_uuid(),v_uid,'direct','direct',999,'direct_test');
  EXCEPTION WHEN OTHERS THEN v_msg:=SQLERRM;
    IF v_msg LIKE '%IU Gateway blocked%' AND (v_msg LIKE '%fn_iu_create%' OR v_msg LIKE '%canonical%') AND (v_msg LIKE '%README%' OR v_msg LIKE '%readme%') THEN v_ok:=true;
    ELSE RAISE EXCEPTION 'UV INSERT wrong: %',v_msg; END IF;
  END;
  IF NOT v_ok THEN RAISE EXCEPTION 'UV INSERT not blocked'; END IF;
  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;
  RAISE NOTICE 'UV_INSERT_BLOCK=PASS';
END $$;

DO $$ DECLARE v_ok boolean:=false;v_msg text;v_before text;v_after text; BEGIN
  SELECT updated_by INTO v_before FROM public.information_unit WHERE canonical_address=current_setting('app.p3p2_pilot_addr');
  BEGIN UPDATE public.information_unit SET updated_by='direct_test' WHERE canonical_address=current_setting('app.p3p2_pilot_addr');
  EXCEPTION WHEN OTHERS THEN v_msg:=SQLERRM;
    IF v_msg LIKE '%IU Gateway blocked%' AND (v_msg LIKE '%fn_iu_create%' OR v_msg LIKE '%canonical%') AND (v_msg LIKE '%README%' OR v_msg LIKE '%readme%') THEN v_ok:=true;
    ELSE RAISE EXCEPTION 'IU UPDATE wrong: %',v_msg; END IF;
  END;
  IF NOT v_ok THEN RAISE EXCEPTION 'IU UPDATE not blocked'; END IF;
  SELECT updated_by INTO v_after FROM public.information_unit WHERE canonical_address=current_setting('app.p3p2_pilot_addr');
  IF v_before IS DISTINCT FROM v_after THEN RAISE EXCEPTION 'IU UPDATE leaked'; END IF;
  RAISE NOTICE 'IU_UPDATE_BLOCK=PASS';
END $$;

DO $$ DECLARE v_ok boolean:=false;v_msg text;v_before text;v_after text;v_uid uuid; BEGIN
  SELECT uv.id INTO v_uid FROM public.unit_version uv JOIN public.information_unit iu ON iu.id=uv.unit_id WHERE iu.canonical_address=current_setting('app.p3p2_pilot_addr') LIMIT 1;
  IF v_uid IS NULL THEN RAISE EXCEPTION 'no UV'; END IF;
  SELECT created_by INTO v_before FROM public.unit_version WHERE id=v_uid;
  BEGIN UPDATE public.unit_version SET created_by='direct_test' WHERE id=v_uid;
  EXCEPTION WHEN OTHERS THEN v_msg:=SQLERRM;
    IF v_msg LIKE '%IU Gateway blocked%' AND (v_msg LIKE '%fn_iu_create%' OR v_msg LIKE '%canonical%') AND (v_msg LIKE '%README%' OR v_msg LIKE '%readme%') THEN v_ok:=true;
    ELSE RAISE EXCEPTION 'UV UPDATE wrong: %',v_msg; END IF;
  END;
  IF NOT v_ok THEN RAISE EXCEPTION 'UV UPDATE not blocked'; END IF;
  SELECT created_by INTO v_after FROM public.unit_version WHERE id=v_uid;
  IF v_before IS DISTINCT FROM v_after THEN RAISE EXCEPTION 'UV UPDATE leaked'; END IF;
  RAISE NOTICE 'UV_UPDATE_BLOCK=PASS';
END $$;
BLOCKSQL
  BLOCK_EXIT=$?
  echo "BLOCK_EXIT=$BLOCK_EXIT" | tee -a "$LOG_PATH"
  cat "$LOG_PATH.block" >> "$LOG_PATH"; cat "$LOG_PATH.block"
  if [ $BLOCK_EXIT -eq 0 ]; then
    grep -q 'IU_INSERT_BLOCK=PASS' "$LOG_PATH.block" && IU_INSERT_BLOCK="PASS" || IU_INSERT_BLOCK="FAIL"
    grep -q 'UV_INSERT_BLOCK=PASS' "$LOG_PATH.block" && UV_INSERT_BLOCK="PASS" || UV_INSERT_BLOCK="FAIL"
    grep -q 'IU_UPDATE_BLOCK=PASS' "$LOG_PATH.block" && IU_UPDATE_BLOCK="PASS" || IU_UPDATE_BLOCK="FAIL"
    grep -q 'UV_UPDATE_BLOCK=PASS' "$LOG_PATH.block" && UV_UPDATE_BLOCK="PASS" || UV_UPDATE_BLOCK="FAIL"
  else
    IU_INSERT_BLOCK="SQL_FAIL"; UV_INSERT_BLOCK="SQL_FAIL"; IU_UPDATE_BLOCK="SQL_FAIL"; UV_UPDATE_BLOCK="SQL_FAIL"
  fi
  set -uo pipefail
fi

ALL_PASS=false
if [ "$CANONICAL_STATUS" = "PASS" ] && [ "$IU_INSERT_BLOCK" = "PASS" ] && [ "$UV_INSERT_BLOCK" = "PASS" ] \
   && [ "$IU_UPDATE_BLOCK" = "PASS" ] && [ "$UV_UPDATE_BLOCK" = "PASS" ]; then
  ALL_PASS=true
fi

if [ "$ALL_PASS" = false ] && [ $PSQL_EXIT -eq 0 ]; then cleanup_guard "tests_failed"; fi

# === MODE UPDATE ===
if [ "$ALL_PASS" = true ]; then
  echo "--- Setting mode=enforced ---" | tee -a "$LOG_PATH"
  set +e
  "${PSQL_CMD[@]}" -c "UPDATE public.dot_config SET value='enforced',updated_at=now() WHERE key='iu_create.gateway.mode';" >> "$LOG_PATH" 2>&1
  MODE_EXIT=$?; echo "MODE_EXIT=$MODE_EXIT" | tee -a "$LOG_PATH"
  set -uo pipefail
fi

# === FINAL VERIFY ===
echo "--- Final Verify ---" | tee -a "$LOG_PATH"
set +e
LEAK_RESULT=$("${PSQL_RO[@]}" -c "SELECT COALESCE(current_setting('app.canonical_writer',true),'(not set)');" 2>/dev/null | tr -d '[:space:]')
if [ "$LEAK_RESULT" = "(notset)" ] || [ "$LEAK_RESULT" = "" ] || [ "$LEAK_RESULT" = "(not set)" ]; then LEAK_STATUS="PASS"; else LEAK_STATUS="LEAK"; fi

if [ "$CANONICAL_STATUS" = "PASS" ]; then
  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_EXIT=$?; POST_STATUS=$(echo "$POST_RESULT" | tail -n1 | tr -d '[:space:]')
  if [ "$POST_STATUS" != "PASS" ] && [ "$POST_STATUS" != "CRITICAL" ]; then POST_STATUS="INVALID_OUTPUT"; fi
else
  POST_STATUS="NOT_RUN"; POST_EXIT=0
fi

GW_MODE=$("${PSQL_RO[@]}" -c "SELECT value FROM public.dot_config WHERE key='iu_create.gateway.mode';" 2>/dev/null | tr -d '[:space:]')

"${PSQL_CMD[@]}" >> "$LOG_PATH" 2>&1 <<'CSQL'
SELECT 'information_unit' AS tbl,count(*) FROM public.information_unit
UNION ALL SELECT 'unit_version',count(*) FROM public.unit_version
UNION ALL SELECT 'birth_iu',count(*) FROM public.birth_registry WHERE collection_name='information_unit';
CSQL
set -uo pipefail

FINAL_OK=false
if [ $PSQL_EXIT -eq 0 ] && [ $CAN_EXIT -eq 0 ] && [ $BLOCK_EXIT -eq 0 ] && [ $MODE_EXIT -eq 0 ] \
   && [ $POST_EXIT -eq 0 ] && [ "$POST_STATUS" = "PASS" ] && [ "$LEAK_STATUS" = "PASS" ] \
   && [ "$CANONICAL_STATUS" = "PASS" ] \
   && [ "$IU_INSERT_BLOCK" = "PASS" ] && [ "$UV_INSERT_BLOCK" = "PASS" ] \
   && [ "$IU_UPDATE_BLOCK" = "PASS" ] && [ "$UV_UPDATE_BLOCK" = "PASS" ] \
   && [ "$TRG_COUNT_STATUS" = "PASS" ] && [ "$GW_MODE" = "enforced" ]; then
  FINAL_OK=true
fi

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

# === VERDICT ===
echo "=== FINAL VERDICT ===" | tee -a "$LOG_PATH"
echo "tx1_exit=$PSQL_EXIT" | tee -a "$LOG_PATH"
echo "canonical_exit=$CAN_EXIT" | tee -a "$LOG_PATH"
echo "canonical_status=$CANONICAL_STATUS" | tee -a "$LOG_PATH"
echo "block_exit=$BLOCK_EXIT" | tee -a "$LOG_PATH"
echo "iu_insert_block=$IU_INSERT_BLOCK" | tee -a "$LOG_PATH"
echo "uv_insert_block=$UV_INSERT_BLOCK" | tee -a "$LOG_PATH"
echo "iu_update_block=$IU_UPDATE_BLOCK" | tee -a "$LOG_PATH"
echo "uv_update_block=$UV_UPDATE_BLOCK" | tee -a "$LOG_PATH"
echo "mode_exit=$MODE_EXIT" | tee -a "$LOG_PATH"
echo "trigger_count=$TRG_COUNT_STATUS" | tee -a "$LOG_PATH"
echo "post_exit=$POST_EXIT" | tee -a "$LOG_PATH"
echo "post_status=$POST_STATUS" | tee -a "$LOG_PATH"
echo "leak_status=$LEAK_STATUS" | tee -a "$LOG_PATH"
echo "gateway_mode=$GW_MODE" | tee -a "$LOG_PATH"
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"
echo "pilot=$PILOT_ADDRESS" | tee -a "$LOG_PATH"

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: 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
echo "=== UPLOAD REPORT NOW ===" | tee -a "$LOG_PATH"

Report path

knowledge/dev/laws/dieu44-trien-khai/reports/22-p3-p2-iu-gateway-trigger-guard-report.md

Hard Boundaries

❌ No GRANT/REVOKE except REVOKE PUBLIC on fn_iu_gateway_write_guard — No role separation — No Directus changes — No detector — No DOT — No adapter — No cleanup pilots — No Pack 2C


22-P3-P2 rev7 | 2026-05-06 | Trigger rename trg_aa_ prefix | Chờ approve + dispatch.