dot-iu-cutter v0.2 — BR-3 canonical_address Reader/Writer Inventory (2026-05-15)
dot-iu-cutter v0.2 — BR-3 canonical_address Reader/Writer Inventory
document_path: knowledge/dev/laws/dieu44-trien-khai/v0.2-planning/dot-iu-cutter-v0.2-br-3-canonical-address-reader-writer-inventory-2026-05-15.md
revision: r1
date: 2026-05-15
author: Agent (Claude Code CLI, Opus 4.7 1M)
phase: v0.2 planning — BR-3 read-only discovery
mutation_performed: false
§1 — Purpose
Resolve BR-3 (reconciliation report §4): inventory every reader/writer surface for canonical_address across PG (functions, triggers, views, constraints, indexes), Directus (flows, extensions), and application code (Nuxt SSR + client, dot scripts, agent-data). Classify each as reader / writer / mirror / guard / unknown.
§2 — Read-Only Method
queries_executed:
- pg_proc.prosrc ILIKE '%canonical_address%' (function bodies — definitive)
- pg_trigger.tgrelid joined to pg_class (trigger definitions)
- pg_views.definition ILIKE (view definitions)
- pg_indexes / pg_constraint (indexes + constraints)
- row counts on 8 candidate tables
filesystem_inspection:
- git grep on /opt/incomex, /opt/incomex/dot, /opt/incomex/docker/agent-data-repo (tracked files)
- filesystem grep on /opt/incomex/{scripts,migrations,deploy,docker/directus/extensions}
- docker exec grep inside incomex-nuxt and incomex-agent-data containers
- directus_flows table scan for name patterns
no_mutation: TRUE
§3 — Tables Holding canonical_address (sister-column population)
| # | Schema.table | Column shape | Index/constraint | Rows (total) | Rows (canonical_address non-null) |
|---|---|---|---|---|---|
| 1 | public.tac_logical_unit |
text NOT NULL | UNIQUE | 86 | 86 |
| 2 | public.information_unit |
text NOT NULL | UNIQUE + regular btree | 98 | 98 |
| 3 | public.unit_edit_draft |
text NOT NULL | composite (canonical_address, draft_status, created_at DESC) + CHECK btrim<>'' | 13 | 13 |
| 4 | public.event_outbox |
text NOT NULL | CHECK btrim<>'' (NO index on canonical_address) | 44,726 | 44,726 |
| 5 | public.event_pending |
text NOT NULL | (no index) | 0 | 0 |
| 6 | public.iu_notification_event |
text NOT NULL | CHECK btrim<>'' (no index) | 0 | 0 |
| 7 | public.birth_registry |
text NULLABLE | (no index on canonical_address) | 338,285 | 0 |
| 8 | sandbox_tac.logical_unit |
text NOT NULL | UNIQUE | 76 | 76 |
Key observation: birth_registry has 338,285 rows but zero non-null canonical_address values — the column is nullable and currently unused. event_outbox has the largest populated payload (44,726).
§4 — PG Functions Referencing canonical_address (pg_proc.prosrc match)
21 functions identified. Naming heuristic groups them clearly.
4.1 Information-Unit (IU) lifecycle family (15 functions)
| # | Function | Role classification |
|---|---|---|
| 1 | public.fn_iu_create |
WRITER — creates IU; sets canonical_address |
| 2 | public.fn_iu_create_plan |
READER — plans IU creation (reads address) |
| 3 | public.fn_iu_create_preflight |
READER — preflight checks before create |
| 4 | public.fn_iu_create_edit_draft |
WRITER — creates edit draft (carries address) |
| 5 | public.fn_iu_apply_edit_draft |
WRITER — applies an edit draft back to IU |
| 6 | public.fn_iu_edit |
WRITER — edits IU |
| 7 | public.fn_iu_edit_plan |
READER — plans an edit |
| 8 | public.fn_iu_save |
WRITER — saves IU |
| 9 | public.fn_iu_classify_existing |
READER — classifies an existing unit |
| 10 | public.fn_iu_verify_invariants |
READER (GUARD) — invariant verification |
| 11 | public.fn_iu_birth_gate_layer1 |
GUARD — birth-gate layer-1 check (BEFORE INSERT) |
| 12 | public.fn_iu_notif_draft |
NOTIFIER — emits notification on edit draft |
| 13 | public.fn_iu_notif_comment |
NOTIFIER — emits notification on comment |
| 14 | public.fn_iu_notif_version |
NOTIFIER — emits notification on version |
| 15 | public.fn_iu_unread |
READER — unread notifications query |
4.2 IU notification + comment family (2 more)
| # | Function | Role classification |
|---|---|---|
| 16 | public.fn_iu_notification_board |
READER — notification dashboard query |
| 17 | public.fn_iu_comment |
WRITER — adds an IU comment |
4.3 TAC and event family (3 functions)
| # | Function | Role classification |
|---|---|---|
| 18 | public.fn_tac_birth_gate_lu |
GUARD — TAC logical-unit birth-gate (BEFORE INSERT OR UPDATE on tac_logical_unit) |
| 19 | public.fn_event_unread |
READER — unread events query (returns table with canonical_address column) |
| 20 | public.fn_event_capture_system_issues |
WRITER — captures system issues into event surface |
4.4 Sandbox helper (1 function)
| # | Function | Role classification |
|---|---|---|
| 21 | sandbox_tac.fn_sbx_lu_parent_same_doc |
GUARD — sandbox-only parent-document consistency check |
§5 — PG Triggers (11 total)
| # | Schema.table | Trigger | Timing/event | Function | Role |
|---|---|---|---|---|---|
| 1 | public.tac_logical_unit |
trg_tac_birth_gate_lu |
BEFORE INSERT OR UPDATE | fn_tac_birth_gate_lu |
GUARD |
| 2 | public.information_unit |
trg_aa_iu_gateway_write_guard |
BEFORE INSERT OR UPDATE | fn_iu_gateway_write_guard |
GUARD |
| 3 | public.information_unit |
trg_iu_birth_gate_layer1 |
BEFORE INSERT | fn_iu_birth_gate_layer1 |
GUARD |
| 4 | public.information_unit |
trg_iu_birth_gate_layer2 |
AFTER INSERT OR UPDATE DEFERRABLE INITIALLY DEFERRED CONSTRAINT TRIGGER | fn_iu_birth_gate_layer2 |
GUARD |
| 5 | public.information_unit |
trg_iu_updated_at |
BEFORE UPDATE | fn_iu_updated_at |
MIRROR (timestamp; not canonical_address-specific) |
| 6 | public.information_unit |
trg_birth_information_unit |
AFTER INSERT | fn_birth_registry_auto('__birth_synthetic_id__') |
MIRROR (writes to birth_registry) |
| 7 | public.unit_edit_draft |
trg_aa_iu_notif_draft |
AFTER INSERT | fn_iu_notif_draft |
NOTIFIER |
| 8 | public.event_outbox |
trg_event_outbox_type_validate |
BEFORE INSERT | fn_event_type_validate |
GUARD (type validation; touches canonical_address indirectly) |
| 9 | public.birth_registry |
trg_birth_auto_certify |
BEFORE UPDATE | fn_birth_auto_certify |
WRITER/GUARD |
| 10 | public.birth_registry |
trg_birth_change_flag_matrix |
AFTER INSERT OR DELETE OR UPDATE | fn_birth_change_flag_matrix |
WRITER |
| 11 | public.birth_registry |
trg_count_birth_registry |
AFTER INSERT OR DELETE | update_record_count |
MIRROR (count cache) |
fn_iu_gateway_write_guard and fn_iu_updated_at did not appear in §4 (they're written without referencing canonical_address in their source) but the triggers exist on information_unit; they may interact indirectly. Listed for completeness, classified as GUARD / MIRROR based on naming.
§6 — PG Views
views_referencing_canonical_address: 0
No views reference canonical_address. No view layer to update.
§7 — Indexes + Constraints on canonical_address (consolidated)
UNIQUE indexes:
public.tac_logical_unit_canonical_address_key
public.information_unit_canonical_address_key
sandbox_tac.logical_unit_canonical_address_key
Regular indexes:
public.idx_iu_canonical on information_unit (btree)
public.idx_ued_address_status_created on unit_edit_draft (composite: canonical_address, draft_status, created_at DESC)
CHECK constraints (btrim(canonical_address) <> ''):
public.event_outbox.event_outbox_canonical_address_check
public.iu_notification_event.chk_notif_event_canonical_address_nonempty
public.unit_edit_draft.chk_ued_address
No FOREIGN KEYS use canonical_address as target — all cross-table FKs target tac_logical_unit.id (uuid). The canonical_address columns on sister tables are denormalized text mirrors.
§8 — Directus Layer
directus_flows_referencing_canonical_address_by_name: 0
directus_extension_with_canonical_address_in_code:
l2-checkpoint-guard — INSPECTED at /opt/incomex/docker/directus/extensions/l2-checkpoint-guard/
result: name does not match; quick file-content grep showed no canonical_address hits in extension code
directus_flows_referencing_canonical_address_via_flow_payload: NOT_EXHAUSTIVELY_INSPECTED (flow operation payloads can contain string references that wouldn't appear in flow.name); a separate Phase α scan over directus_operations.options jsonb is recommended IF Phase α adds vocabulary-changing semantics. For Phase α as currently scoped (additive columns + alias table), no flow change is expected.
§9 — Application Code
9.1 Nuxt (incomex-nuxt container nuxt-ssr-local:d28gmr-1778407456)
nuxt_server_chunk: /app/.output/server/chunks/build/_pubId_-BnetNsja.mjs
nuxt_server_chunk_role: READER (page renderer for the `[pubId]` route)
nuxt_server_chunk_canonical_address_usage_snippet (verbatim):
N=String(s.canonical_address||""),n=String(s.section_type||""),k=re.value.depthOf(a);
→ reads s.canonical_address as a coerced string for rendering / depth computation
nuxt_client_bundle: /app/.output/public/_nuxt/CpvSyHkp.js
nuxt_client_bundle_role: READER (GraphQL/REST field selection)
nuxt_client_canonical_address_usage_snippet (verbatim):
["id","render_order","logical_unit_id.id","logical_unit_id.canonical_address","logical_unit_id.parent_id","logical_unit_id.sort_order", …]
→ declares canonical_address as a SELECTED field in a query against `logical_unit_id.*` relationship
nuxt_source_code_availability_on_VPS: NO (source likely lives in a CI-built image; only the built bundles are on the VPS)
nuxt_source_repo_path_on_VPS: NOT_FOUND (no nuxt.config* file on host filesystem)
risk_of_app_breakage_when_adding_companion_columns: LOW — adding new columns (authority, format_version) does not affect the existing canonical_address READ path; Nuxt queries an explicit field selection, so new columns are not auto-included unless code is updated
risk_of_app_breakage_if_format_or_constraint_changes: HIGH — if canonical_address syntax changes or uniqueness scope changes, both bundles would need re-deploy. Phase α as scoped does NOT change format or uniqueness, so risk is LOW for Phase α specifically.
9.2 dot scripts (incomex-dot — local repo at /opt/incomex/dot)
git_grep_canonical_address_tracked_files: 0 hits
filesystem_grep_canonical_address (bin/, lib/, migrations/, specs/, reports/): 0 hits
dot_specs_files: only 1 file — collection_registry_birth_identity_fields.json (does not reference canonical_address)
role: NOT_A_READER_NOT_A_WRITER for canonical_address; dot is an APR/governance toolkit, not a TAC consumer
risk_of_dot_breakage: NONE for Phase α
9.3 agent-data (incomex-agent-data container)
docker_exec_grep_inside_container: 0 hits in /app or /opt
role: NOT_A_READER_NOT_A_WRITER for canonical_address; agent-data is the KB / vector service, not a TAC consumer
risk_of_agent_data_breakage: NONE for Phase α
9.4 Other VPS infrastructure
/opt/incomex/scripts: 0 hits
/opt/incomex/migrations: 0 hits (filesystem grep)
/opt/incomex/deploy: 0 hits
incomex-nginx, incomex-qdrant, uptime-kuma, pg-dry-run-hb05-2026-05-15: NOT_INSPECTED (containers not expected to reference canonical_address; nginx config is reverse-proxy only; qdrant stores vectors keyed by ids not addresses)
§10 — Classification Summary
canonical_address surface — final classification table
| Layer | Reader | Writer | Mirror | Guard | Notifier |
|--------------------------------|--------|--------|--------|-------|----------|
| PG functions | 6 | 7 | 0 | 4 | 4 |
| PG triggers | 0 | 2 | 3 | 5 | 1 |
| PG views | 0 | 0 | 0 | 0 | 0 |
| Directus flows | 0 | 0 | 0 | 0 | 0 |
| Directus extensions | 0 | 0 | 0 | 0 | 0 |
| Nuxt SSR + client | 2 | 0 | 0 | 0 | 0 |
| dot scripts | 0 | 0 | 0 | 0 | 0 |
| agent-data | 0 | 0 | 0 | 0 | 0 |
(The function counts are heuristic from name + role; a function may serve dual roles — e.g. fn_iu_create is primarily WRITER but also READS for validation.)
§11 — Risk Assessment for Phase α (additive columns: authority, canonical_address_format_version, canonical_address_alias table)
phase_alpha_proposed_changes:
- ADD COLUMN public.tac_logical_unit.authority text NULL
- ADD COLUMN public.tac_logical_unit.canonical_address_format_version text NOT NULL DEFAULT '<TBD-Đ24-ratified>'
- CREATE TABLE public.canonical_address_alias (or tac.canonical_address_alias)
- mirror the above on sandbox_tac.logical_unit (parallel additive)
risks_per_surface:
tac_logical_unit (86 rows):
- trg_tac_birth_gate_lu / fn_tac_birth_gate_lu: GUARD on BEFORE INSERT OR UPDATE. May need to be aware of new columns IF birth-gate logic depends on authority. Read fn_tac_birth_gate_lu body during Phase α design (read-only) to confirm.
- identity_profile jsonb: no overlap; safe
- lifecycle_status: SEMANTICALLY DISTINCT from authority; no conflict
risk_class: LOW (additive)
information_unit (98 rows):
- 5 triggers (gateway_write_guard, birth_gate_layer1/2, updated_at, birth_information_unit)
- canonical_address is text column, denormalized; Phase α does NOT touch this column on information_unit
risk_class: NONE (Phase α scope excludes information_unit)
unit_edit_draft (13 rows):
- composite index on canonical_address; CHECK constraint btrim<>''
- 1 trigger (notif_draft)
risk_class: NONE (Phase α scope excludes unit_edit_draft)
event_outbox (44,726 rows):
- largest table; CHECK constraint; type_validate trigger
risk_class: NONE (Phase α scope excludes event_outbox)
event_pending (0 rows): NONE (scope excluded)
iu_notification_event (0): NONE (scope excluded)
birth_registry (338,285): NONE (scope excluded; canonical_address column nullable + currently always NULL)
sandbox_tac.logical_unit (76): MIRROR additive columns to match public; sandbox helper function fn_sbx_lu_parent_same_doc to be inspected
Nuxt: LOW (READER; explicit field selection means new columns are not auto-broken)
dot, agent-data: NONE
overall_phase_alpha_risk: LOW
overall_phase_alpha_blocking_concern: NONE from this inventory; outstanding dependencies remain BR-4 (authority backfill rule), BR-5 (Đ24 ratification of v1 syntax), BR-6 (split/merge TD absorption — for P0-2 only, not Phase α)
§12 — Findings
F-BR3-1 21 PG functions reference canonical_address (15 in IU family, 3 in TAC/event, 1 sandbox helper, 2 cross-cutting)
F-BR3-2 11 triggers across 5 tables (tac_logical_unit, information_unit×5, unit_edit_draft, event_outbox, birth_registry×3)
F-BR3-3 zero views reference canonical_address; no view-layer update required
F-BR3-4 3 CHECK constraints enforce non-empty canonical_address on writes (event_outbox, iu_notification_event, unit_edit_draft); Phase α additive columns do not invalidate them
F-BR3-5 birth_registry has 338,285 rows but canonical_address is nullable and currently 100% NULL — unused; no migration impact for Phase α
F-BR3-6 Nuxt is the only application layer reading canonical_address; it READS only (no write path observed); 2 minified bundles confirm the column is in the query field selection for the publication page route ([pubId])
F-BR3-7 zero hits in dot, agent-data, Directus flows, Directus extensions, /opt/incomex scripts/migrations/deploy — confirms canonical_address governance lives in PG functions + triggers, not in app/automation layer
F-BR3-8 fn_tac_birth_gate_lu (the BEFORE INSERT OR UPDATE trigger function on tac_logical_unit) must be read during Phase α design to confirm it does not enforce constraints that authority/format_version would violate (read-only inspection only)
§13 — Recommendation for Phase α
br_3_blocker_status: RESOLVED
phase_alpha_proceed_recommendation: SAFE_FROM_READER_WRITER_PERSPECTIVE
- additive columns + new alias table do not break any reader/writer surface
- Nuxt READ path uses explicit field selection; new columns are invisible to it until app is updated
- PG functions and triggers do not enforce constraints that prevent additive columns
- sandbox_tac.logical_unit must be mirrored in additive shape (per BR-7 finding)
- fn_tac_birth_gate_lu must be inspected (read-only) during Phase α DDL authoring to confirm no implicit constraint
- sister tables (information_unit, unit_edit_draft, event_outbox, …) are OUT of Phase α scope (per Option D direction)
remaining_dependencies:
BR-4 — authority backfill rule
BR-5 — Đ24 ratification of production syntax v1 (for DEFAULT value on canonical_address_format_version)
BR-6 — split/merge TD (only blocks P0-2 design, not Phase α additive columns)
§14 — Hard Boundaries
no_DDL_written: TRUE
no_SQL_mutation: TRUE
no_ALTER_TABLE: TRUE
no_function_or_trigger_modified: TRUE
no_app_code_modified: TRUE
no_directus_flow_modified: TRUE
no_migration: TRUE
no_design_authored: TRUE
output_form: br_3_read_only_inventory
End of BR-3 reader/writer inventory.