KB-63C6

dot-iu-cutter v0.2 — BR-3 canonical_address Reader/Writer Inventory (2026-05-15)

19 min read Revision 1
dieu44-trien-khaidot-iu-cutterv0.2br-3reader-writerinventorydiscoveryread-only2026-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.

Back to Knowledge Hub 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