KB-5004

IU-0 Pack 2A — Legal/Tooling Preflight Discovery Report

18 min read Revision 1
iu-0pack-2apreflightdiscoveryread-onlydot-gatewaycollection-registrytrigger-governanceadmin-fallback2026-05-04

IU-0 Pack 2A — Legal/Tooling Preflight Discovery Report

Date: 2026-05-04 Scope: Read-only discovery only. No writes performed. No DOT executed. Author: Claude Code (Opus 4.7) per dispatch from User/GPT after legal recheck blocker. Trigger doc: knowledge/dev/laws/dieu44-trien-khai/reviews/gpt-legal-recheck-pack2a-dot-gateway-risk-2026-05-04.md


Executive Summary

Verdict — abundant legal tooling already exists. Collection birth/registration and trigger governance both have governed DOT tools registered in dot_tools AND deployed at /opt/incomex/dot/bin/. There is NO need for raw SQL INSERT into collection_registry. There is NO need for ADMIN fallback unless a specific tool gap is identified after design. Direct INSERT would violate Đ4 §2, Đ2, Đ35, Đ36, and the §6 9-step DOT-COLLECTION-CREATE protocol.

Recommendation: Pack 2B/2C must use dot-collection-register (and optionally dot-collection-create if PG tables had not been created) — never raw SQL — to register information_unit + unit_version. ADMIN fallback path is available but not justified; no tool gap discovered.


Q1 — Collection registration tooling

LEGAL tools exist on filesystem AND in dot_tools registry.

Tool (filesystem) dot_tools code Tier Paired Coverage Description (truncated)
/opt/incomex/dot/bin/dot-collection-create DOT-COL-CREATE B DOT-COL-HEALTH complete v2.0.0 — Multi-step collection creation. CREATE TABLE + Directus + birth + meta_catalog + species + permissions.
/opt/incomex/dot/bin/dot-collection-create DOT_COLLECTION_CREATE B DOT-HEALTH-DOT Tạo collection trong Directus kèm fields, FK, permissions, đăng ký species. (Vietnamese mirror entry; same script.)
/opt/incomex/dot/bin/dot-collection-register DOT_COLLECTION_REGISTER B DOT-HEALTH-DOT Đăng ký collection vào collection_registry. v1.1.0 supports --update upsert. CHECKED-NO-DUPLICATE in header.
/opt/incomex/dot/bin/dot-collection-field-sync DOT_COLLECTION_FIELD_SYNC B DOT-HEALTH-DOT Field drift detection between code defs and Directus.
/opt/incomex/dot/bin/dot-collection-health DOT-COL-HEALTH / DOT_COLLECTION_HEALTH A complete v2.0.0 — Collection integrity HC, self-healing, 13+ checks. Đ36 GP8.1.
/opt/incomex/dot/bin/dot-schema-registry-collections-ensure DOT_SCHEMA_REGISTRY_COLLECTIONS_ENSURE B DOT-HEALTH-DOT Ensures dot_tools, ui_pages, collection_registry, agents exist in Directus.
/opt/incomex/dot/bin/dot-schema-birth-registry-ensure DOT_SCHEMA_BIRTH_REGISTRY_ENSURE B DOT-HEALTH-DOT Birth registry schema ensure (Đ0-G).
/opt/incomex/dot/bin/dot-birth-trigger-setup DOT_BIRTH_TRIGGER_SETUP B DOT-HEALTH-DOT Deploys AFTER INSERT triggers per governed collection → auto-inserts birth_registry. v1.0.0.
/opt/incomex/dot/bin/dot-birth-backfill DOT_BIRTH_BACKFILL B DOT-HEALTH-DOT Backfill birth_registry for legacy entities.
/opt/incomex/dot/bin/dot-dot-register DOT-REGISTER B DOT-HEALTH-DOT complete Register a new DOT into dot_tools with domain/version/kb_path.
/opt/incomex/dot/bin/dot-species-register (not separately indexed in this query) Species registration (paired with collection birth).

Status field convention: dot_tools.status is text; relevant rows use active. Some rows (e.g. DOT-COL-CREATE) have empty status but coverage_status=complete.

Key write-capable governance gateway = dot-collection-register (Đ4 §2 birth-process tool of record for IU-0 use case, since the IU PG tables already exist — only the catalog/registry registration remains).


Q2 — Trigger / DDL / Audit governance tooling

LEGAL tools exist. Trigger governance is governed by Đ36 collection protocol + a multi-layer enforcement system:

Tool dot_tools code Tier Description
dot-trigger-guard (DOT-316 per source header; not seen in dot_tools query — VERIFY before execute) A (per header) Tầng 1 PG event trigger (real-time) + Tầng 2 DOT cron (enforcement). NT-11 exceptions-only. Reads trigger_guard_exceptions, writes trigger_guard_alerts.
dot-pg-triggers-ensure (not in this query result) B Deploys sequences + functions + triggers for 16 atom collections; idempotent. v1.0.0.
dot-schema-trigger-registry-ensure DOT_SCHEMA_TRIGGER_REGISTRY_ENSURE B Ensures trigger_registry PG table, populates from pg_trigger, registers in meta_catalog, creates sync function. v1.0.0.
dot-pg-audit-ensure (not in this slice) v2.0.0 — audit_relationships + audit_dead_links + run_audit_to_issues() — audit functions for DOT scanning.
dot-label-trigger-setup Auto-label provenance trigger setup.
dot-metadata-audit Audit metadata coverage (description/note/group) across Directus.
dot-layer-integrity-audit / dot-layer3-audit Layer integrity scans.
dot-id-collision-check ID collision audit.

Live event triggers in PG:

  • evt_trigger_guard_ddl → fires on ddl_command_end, enabled O (origin).
  • evt_trigger_guard_drop → fires on sql_drop, enabled O.

Whitelist/exceptions mechanism: YES — trigger_guard_exceptions table with temporary_until column drives NT-11 exceptions-only model (empty table = "all triggers ON"). Companion trigger_guard_alerts records violations. dot-trigger-guard self-checks that 2/2 event triggers are enabled and auto-removes expired exceptions.

trigger_registry is real and populated: 107 rows. Schema includes code, trigger_name, table_name, trigger_type, function_name, fires_on, timing, enabled, _dot_origin, status. Has birth_trigger_trigger_registry, trg_auto_code_trigger_registry, trg_before_birth_gate_trigger_registry.


Q3 — collection_registry current state

Schema (PG):

  • ID/audit: id, status, sort, user_created, date_created, user_updated, date_updated, code (UNIQUE).
  • Identity: name, name_en, description, classification, owner.
  • Collection: collection_name (NOT NULL, the PG table being registered), group (FK → collection_groups.code), icon, field_count, has_note, purpose.
  • Governance: _dot_origin, storage_role, governance_role, source_kind, migration_state, species_code.

Triggers on collection_registry (full enforcement chain):

  • trg_before_birth_gate_collection_registryfn_birth_gate() (BEFORE INSERT)
  • trg_auto_code_collection_registrygen_code_collection_registry() (BEFORE INSERT, auto code COL-NNN)
  • trg_desc_guard_collection_registryfn_description_birth_guard() (BEFORE INSERT/UPDATE description) — auto-fills empty desc from template + enforces minimum length per gov_role.
  • trg_birth_collection_registry + birth_trigger_collection_registryfn_birth_registry_auto('code') (AFTER INSERT, auto-writes birth_registry)
  • trg_desc_provenance_collection_registryfn_auto_label_provenance() (AFTER INSERT)
  • trg_label_assign_collection_registryfn_auto_label_assignment()
  • trg_validate_dot_origin_collection_registryfn_validate_dot_origin() (BEFORE INSERT/UPDATE _dot_origin)
  • trg_refresh_collection_count, trg_refresh_orphan_col → view refresh triggers.

Convention values currently in use (DISTINCT live values):

  • governance_role: governed, observed, excluded, locked, law_artifact.
  • migration_state: unclassified, pilot, classified, registered.
  • source_kind: pg_table, native, derived, policy, registry, infrastructure, aggregation, <empty>.

IU rows: information_unit and unit_version are NOT in collection_registry (0 rows).


Q4 — IU presence in other registries

Registry information_unit unit_version
pg_tables (raw PG) EXISTS EXISTS (also tac_unit_version exists separately)
collection_registry MISSING MISSING
birth_registry MISSING (0 rows) MISSING (0 rows)
meta_catalog MISSING MISSING
directus_collections MISSING MISSING

→ The two PG tables are completely outside catalog/registry governance. This is the audit gap Pack 2A is meant to close. Must be closed via DOT, not raw SQL.


Q5 — TRIGGER-GUARD mechanism

It is NOT just log-WARNING. Architecture is whitelist-by-exception (NT-11):

  • Tầng 1 (real-time): PG event triggers evt_trigger_guard_ddl (ddl_command_end) and evt_trigger_guard_drop (sql_drop) — both currently enabled. They fire automatically on schema change events.
  • Tầng 2 (cron enforcement): dot-trigger-guard script runs periodically; reads pg_event_trigger self-check (must have ≥2 active), enforces trigger_guard_exceptions (with temporary_until expiry), writes alerts to trigger_guard_alerts.
  • Convention: empty trigger_guard_exceptions ⇒ ALL triggers must be ON. Exceptions are temporary and auto-expire.

The event-trigger function bodies (fn_trigger_guard_ddl, fn_trigger_guard_drop) were not extracted in this read-only pass — recommend a follow-up read of the function definitions before any future trigger work that might touch the DDL guard. But the existence of trigger_guard_exceptions + alerts table + the cron tool establishes that this is a real registry-driven governance layer, not just logging.

Additional active gates on registry tables:

  • fn_birth_gate() — BEFORE INSERT on collection_registry/meta_catalog/trigger_registry. Has KILL SWITCH (app.bypass_birth_gate) and mode (warning default vs blocking). Calls fn_pre_birth_check(table, code, name, origin) → 5 birth checks; failures either WARNING or BLOCKED depending on mode.
  • fn_description_birth_guard() — auto-fills description from dot_config templates (4-tier: per-table+level → per-table → per-level → default) for governed rows when empty; enforces description min-length policy per gov_role (Đ4 §2.1).
  • fn_validate_dot_origin() — validates _dot_origin value (DOT name vs DIRECTUS vs ADMIN).

Q6 — Admin fallback infrastructure

Fully exists and is governed.

admin_fallback_log schema (PG):

  • id, dot_code (NOT NULL), reason, backup_path, patch_diff, verify_evidence (jsonb), approved_by (default 'president'), session_code, status
  • status CHECK ∈ {applied, retroactive_documented, audit_overdue, rolled_back}
  • retroactive_apr_id FK → approval_requests(id)
  • retroactive_deadline default now() + 24h
  • Trigger trg_auto_apr_on_fallback AFTER INSERT → fn_auto_apr_on_fallback() (auto-creates linked APR draft).

approval_requests schema (PG): full table — id, code, request_type, entity_type, entity_code, title, current_state(jsonb), proposed_action(jsonb), alternative_actions(jsonb), evidence, source, priority, status, reviewed_by, reviewed_at, review_note, applied_at, action, target_collection, target_entity_code, source_context.

→ ADMIN fallback flow is wired and audited per Đ35 v5.2: fallback INSERT → auto APR draft → 24h retroactive deadline → cron flips to audit_overdue if not documented.


Q7 — Options for IU-0 (register information_unit + unit_version)

# Option Verdict Notes
A Use dot-collection-register (write mode, no --dry-run) for both information_unit and unit_version, supplying explicit --storage_role / --governance_role / --source_kind / --migration_state / --description per Đ36 v4.0. LEGAL — preferred. Goes through Đ4 §2 birth-process tool. All BEFORE/AFTER triggers (fn_birth_gate, fn_description_birth_guard, gen_code_collection_registry, fn_birth_registry_auto) fire automatically — auto-populates birth_registry. Tool is registered in dot_tools (DOT_COLLECTION_REGISTER, status=active, paired with DOT-HEALTH-DOT). Verify with dot-collection-health afterward.
B Run the full 9-step dot-collection-create flow if/when a fresh IU collection is needed and Directus exposure (file 09 §6.2 step 7) must also happen. LEGAL — but check first whether PG tables already exist. The PG tables already exist; running create on existing tables may need an --existing mode. If unavailable, B is stronger than A only when Directus collection registration must happen in same protocol. Confirm with current state of dot-collection-create source before dispatch.
C After A: run dot-schema-trigger-registry-ensure + dot-trigger-guard to backfill any IU triggers into trigger_registry and validate the trigger-guard layer. LEGAL — recommended follow-up. Closes Q4/Q5 gap for IU-derived triggers (e.g., birth_trigger_information_unit, if/when birth-trigger-setup deploys for governed IU rows).
D Backfill via dot-birth-backfill for any pre-existing rows in information_unit/unit_version so they appear in birth_registry. LEGAL — recommended follow-up. Đ0-G compliance.
E Raw SQL INSERT INTO collection_registry ... BLOCKED. Violates Đ4 §2 (must use DOT/script), Đ2 (registry/tooling principle), Đ35 (DOT-first), Đ36 (collection protocol), file 09 §6 (DOT-COLLECTION-CREATE 9-step). No tool gap justifies this — dot-collection-register exists, is active, and is paired.
F ADMIN fallback (insert admin_fallback_log row with reason "tool failure", patch raw, retroactive APR within 24h). LEGAL IF APPROVED — but unjustified now. Prereq per Đ35 v5.2: dot_code of failing tool, reason, backup_path, patch_diff, verify_evidence, explicit User/GPT approval. None of those preconditions are met because no tool failure has been demonstrated. Do NOT preemptively choose F.
G Build a new DOT (e.g., DOT-IU-REGISTER) before registering. UNKNOWN — only if A/B/C-D prove insufficient after design. Per Đ20 design-before-execute, this would require a written design + approval. Premature given existing tools.

Final recommendation

Default path = Option A + Option C + Option D, in that order.

Pack 2B prompt should:

  1. dot-collection-register information_unit --storage_role <X> --governance_role <Y> --source_kind <Z> --migration_state <W> --description "..." --cloud
  2. Same for unit_version.
  3. Verify by querying collection_registry + birth_registry (auto-populated by triggers).
  4. Run dot-collection-health --cloud to confirm Đ36 GP8.1 HC-REG/HC-SCHEMA passes.
  5. Run dot-schema-trigger-registry-ensure --cloud + dot-trigger-guard --cloud to capture any IU triggers.
  6. Run dot-birth-backfill --cloud if pre-existing IU rows lack birth_registry entries.

If any step fails with a tool-side defect, that is the moment to choose between F (ADMIN fallback with full prereqs) or G (build proper tool) — never preemptively raw-SQL.


Read-only commands actually executed (audit trail)

All commands ran on VPS 38.242.240.89 via ssh contabo. No DDL, no INSERT/UPDATE/DELETE. No DOT executed.

ssh contabo "ls /opt/incomex/dot/bin/ | grep -iE 'col|register|trigger|ddl|audit|guard|birth'"
ssh contabo "ls /opt/incomex/scripts/ | grep -iE 'col|register|trigger|ddl|audit|guard|birth'"
ssh contabo "head -40 /opt/incomex/dot/bin/<each candidate>"
docker exec postgres psql -U directus -d directus -c "\d dot_tools"
docker exec postgres psql -U directus -d directus -c "SELECT code,status,tier,paired_dot,coverage_status,description FROM dot_tools WHERE code ~* '(col|trigger|register|audit|guard|ddl|birth)' ORDER BY code;"
docker exec postgres psql -U directus -d directus -c "\d collection_registry / \d birth_registry / \d meta_catalog / \d admin_fallback_log / \d trigger_registry / \d approval_requests"
docker exec postgres psql -U directus -d directus -c "SELECT ... FROM collection_registry WHERE collection_name IN ('information_unit','unit_version');"   -- 0 rows
docker exec postgres psql -U directus -d directus -c "SELECT ... FROM birth_registry WHERE collection_name IN (...);"   -- 0 rows
docker exec postgres psql -U directus -d directus -c "SELECT ... FROM meta_catalog WHERE source_model IN (...);"        -- 0 rows
docker exec postgres psql -U directus -d directus -c "SELECT collection FROM directus_collections WHERE collection IN (...);"  -- 0 rows
docker exec postgres psql -U directus -d directus -c "SELECT tablename FROM pg_tables WHERE ...;"
docker exec postgres psql -U directus -d directus -c "SELECT evtname, evtenabled, evtevent FROM pg_event_trigger;"
docker exec postgres psql -U directus -d directus -c "SELECT DISTINCT governance_role / migration_state / source_kind FROM collection_registry;"
docker exec postgres psql -U directus -d directus -c "SELECT count(*) FROM trigger_registry;"   -- 107
docker exec postgres psql -U directus -d directus -c "SELECT proname, pg_get_functiondef(oid) FROM pg_proc WHERE proname IN ('fn_birth_gate','fn_description_birth_guard');"

HARD STOP

Per dispatch directive: report uploaded. No writes. No Pack 2B/2C. Awaiting User/GPT decision on Option A path.