KB-2EDE

GPT Review — Trigger Guard DROP Bug Investigation Results

4 min read Revision 1
gptreviewtrigger-guarddrop-buginvestigation-resultsp9s186

GPT Review — Trigger Guard DROP Bug Investigation Results

Date: 2026-04-28

Verdict

Investigation PASS. Agent report is complete and sufficient for a repair gate.

Report reviewed:

knowledge/dev/laws/dieu38-trien-khai/reports/p9-trigger-guard-drop-bug-investigation-2026-04-28.md

Confirmed root cause

fn_evt_trigger_guard_drop() uses nullable r.object_name from pg_event_trigger_dropped_objects() during DROP TRIGGER. For trigger drops, object_name can be NULL. The function then inserts NULL into public.trigger_guard_alerts.trigger_name, which is NOT NULL, causing rollback/DROP TRIGGER to fail.

Secondary defects are also confirmed:

  • unqualified INSERT INTO trigger_guard_alerts;
  • no locked function-level search_path;
  • DROP guard was not updated when DDL guard was repaired;
  • same defective source exists in both directus and incomex_metadata.

Important correction to Opus recommendation

Opus/agent recommend Option A: minimal parity while preserving current security mode.

GPT recommends Option A+, not plain Option A:

  • Use Option A's minimal body change:
    • object_identity fallback;
    • COALESCE for non-null values;
    • public.trigger_guard_alerts;
    • locked search_path = pg_catalog, public.
  • But security mode should match the already-repaired DDL guard per DB:
    • directus: keep SECURITY INVOKER.
    • incomex_metadata: use SECURITY DEFINER if current DDL guard is SECURITY DEFINER, unless a pre-check proves invoker can insert into public.trigger_guard_alerts during the smoke test.

Reason: the prior trigger-guard repair already found incomex_metadata needed SECURITY DEFINER for the DDL guard. Preserving current DROP guard INVOKER there may leave the DROP guard broken or untestable under the executor role.

Decision

Proceed to draft a Trigger Guard DROP Repair Gate — Option A+.

Repair gate requirements

  • Executor: Claude Code via SSH contabo.
  • Effort: medium (ALTER FUNCTION on two DBs + smoke test).
  • Scope: patch only public.fn_evt_trigger_guard_drop() on directus and incomex_metadata.
  • No Gate B/C.
  • No production TAC data changes.
  • Pre-check both DBs:
    • function owner/security/proconfig;
    • DDL guard security mode for parity;
    • alert table schema;
    • event triggers enabled;
    • snapshot old source and metadata.
  • Mutation:
    • replace function body with minimal Option A pattern;
    • lock search_path;
    • schema-qualify insert;
    • set security mode per DB parity decision.
  • Smoke test:
    • create temp table/function/trigger;
    • DROP temp trigger;
    • verify audit row has non-null trigger_name, actual_enabled=false;
    • cleanup temp function/table;
    • run on both DBs, adapting permissions safely.
  • Rollback:
    • restore old source only if new repair fails;
    • do not leave temp artifacts.
  • Action log to KB, no overwrite.
  • STOP after report.

Law / governance notes

  • ALTER FUNCTION is DDL, so it requires explicit gate and User authorization.
  • This is a guard-infrastructure repair under Đ26/Đ31 and must preserve the guard, not bypass or disable it.
  • Do not relax trigger_guard_alerts NOT NULL constraints as primary fix; that would fix the symptom rather than the root cause.

Next direction

Opus should draft the repair execution prompt for Option A+ and submit for review. Do not execute until User GO.