KB-5CBA

dot-iu-cutter v0.2 — Phase α Design Master (2026-05-15)

20 min read Revision 1
dieu44-trien-khaidot-iu-cutterv0.2phase-alphadesign-masterno-ddlno-execution2026-05-15

dot-iu-cutter v0.2 — Phase α Design Master

document_path: knowledge/dev/laws/dieu44-trien-khai/v0.2-design/dot-iu-cutter-v0.2-phase-alpha-design-master-2026-05-15.md
revision: r1
date: 2026-05-15
author: Agent (Claude Code CLI, Opus 4.7 1M)
sovereign: User / anh Huyên
verifier: GPT (Đ32 HIGH-risk path)
secondary: Opus
phase: v0.2 — Phase α design (logical design only; no DDL; no execution)
predecessor_chain:
  - v0.1 production execution (5 cutter_governance tables, success, GPT-ratified)
  - v0.2 canonical_address reconciliation report (Option D selected by GPT)
  - BR-2/3/7 discovery closures
  - BR-4 authority backfill rule closed_with_notes (Candidate B)
  - BR-5 canonical-address-v1 ratification closed_with_notes
mutation_performed: false
ddl_written: false
dry_run_started: false
production_migration_allowed: false

§1 — Phase α Objective

Add the first wave of Option D companion vocabulary onto the existing canonical_address SSOT, without altering the SSOT column itself and without touching sister tables. The wave delivers:

  • explicit authority classification per row (Đ0-G birth-gate distinction)
  • explicit canonical_address_format_version per row (forward-compat for future grammar revisions)
  • a separate canonical_address_alias table (rename / supersession / external-reference history)
  • parallel additive mirror on the sandbox schema

The objective is operationally low-risk by construction: every change is additive on the v0.1-shipped surface; nothing is altered; rollback is DROP COLUMN / DROP TABLE.


§2 — Scope

2.1 In scope (Phase α)

public.tac_logical_unit:
  + ADD COLUMN authority text NULL DEFAULT 'draft'
  + ADD COLUMN canonical_address_format_version text NOT NULL DEFAULT 'canonical-address-v1'
  + backfill of existing 86 rows per BR-4 Candidate B mapping
    (current data: all 86 are lifecycle_status='draft_only' → authority='draft'; format_version handled via DEFAULT at column-add)

sandbox_tac.logical_unit:
  + ADD COLUMN authority text NULL DEFAULT 'draft'
  + ADD COLUMN canonical_address_format_version text NOT NULL DEFAULT 'canonical-address-v1'
  + NO backfill of 76 sandbox rows in Phase α (deferred to Phase β alongside the production write hook)

new_table:
  + cutter_governance.canonical_address_alias  (recommended placement; see alias design doc and §6 below)
    purpose: rename / redirect / supersession / external-reference history for canonical_address values
    rows at creation: 0 (no historical data to backfill)

what_is_NOT_done_in_phase_alpha:
  - no change to the SSOT column public.tac_logical_unit.canonical_address (preserved verbatim per Option D)
  - no change to any sister-table canonical_address column
  - no change to event_outbox, information_unit, unit_edit_draft, iu_notification_event, event_pending, birth_registry
  - no application code change
  - no Directus flow change
  - no manifest_envelope / manifest_unit_block design or DDL (P0-2; blocked by BR-6)
  - no review_decision design or DDL (P0-6; awaits BR-6 + Phase α landing)
  - no decision_backlog remainder design or DDL (P0-5; can run on a parallel track per Option D; NOT Phase α)
  - no NOT NULL constraint on the new authority column (deferred to Phase β)
  - no PG-constraint enforcement of authority enum values (deferred to Phase β alongside vocab table)
  - no CUT / VERIFY operations (separate authorization)

2.2 Out of scope (explicit non-scope)

out_of_scope_v0_2_phase_alpha:
  - any DDL targeting sister tables (information_unit, event_outbox, etc.)
  - any change to existing PG functions (fn_iu_*, fn_event_*, fn_tac_birth_gate_lu)
  - any change to existing triggers
  - any change to Nuxt SSR / client bundles
  - any backfill of birth_registry.canonical_address (currently 100% NULL across 338,285 rows; unused)
  - cleanup of duplicate canonical_address inside identity_profile jsonb (BR-2 cosmetic finding)
  - any Phase β work: lifecycle-transition write hook; NOT NULL promotion; vocab tables; supersession FKs
  - any Phase γ work: birth_gate_class refinement; format_version upgrade machinery
  - any v0.3+ work
  - any P0 item beyond canonical_address reconciliation
  - manifest_envelope, manifest_unit_block, review_decision design or implementation

§3 — Dependency Graph

v0.1 cutter_governance schema (live in production; immutable for Phase α)
                              ↓
                              ↓  (no schema-level coupling; Phase α additive on tac_logical_unit only)
                              ↓
v0.1 SSOT: public.tac_logical_unit.canonical_address  (preserved unchanged)
                              ↓
        ┌─────────────────────┼─────────────────────┐
        ↓                     ↓                     ↓
Phase α adds:           Phase α adds:        Phase α creates:
  authority col           format_version col   cutter_governance.canonical_address_alias
  (nullable;              (NOT NULL; DEFAULT   (0 rows at create;
   DEFAULT draft;          'canonical-          history target for renames/redirects)
   BR-4 mapping            address-v1';
   backfill)               trivial DEFAULT
                           backfill)
        │                     │                     │
        └─────────────────────┴─────────────────────┘
                              ↓
              sandbox_tac.logical_unit  MIRROR (Phase α; no backfill)
                              ↓
                              ↓  (Phase β downstream — out of scope here)
                              ↓
Phase β:  lifecycle-transition write hook → authority auto-updates on lifecycle change
          NOT NULL constraint on authority
          (then v0.3 candidate items)


what_phase_α_does_NOT_couple_to:
  - cut_change_set / cut_change_set_affected_row     (v0.1; remain empty; no CUT yet)
  - dot_pair_signature                                (v0.1; remain empty; no signature yet)
  - verify_result                                     (v0.1; remain empty; no VERIFY yet)
  - decision_backlog_entry                            (v0.1; may receive backlog records emitted by Phase α dry-run only)
  - manifest_envelope / manifest_unit_block / review_decision  (NOT YET DESIGNED; blocked by BR-6 for P0-2)

§4 — Design Assumptions

assumption_1: v0.1 cutter_governance schema is stable and untouched
  evidence: v0.1 production execution report verifies 5 tables exist, 0 rows, structurally intact

assumption_2: existing canonical_address SSOT column is treated as authoritative and immutable in v0.2
  evidence: Option D selection by GPT; BR-5 ratifies the current syntax as canonical-address-v1

assumption_3: tac_lu_lifecycle_vocab is stable (3 entries: active, draft_only, retired)
  evidence: BR-4 read-only inspection
  contingency: any future vocab expansion requires Đ0-G + Đ24 review before Phase β work proceeds

assumption_4: no concurrent writers to tac_logical_unit during Phase α production migration
  evidence: only 86 rows, all lifecycle='draft_only', no observed CUT/VERIFY traffic; existing writers go through fn_iu_create (which is paused/quiet given current data scale)
  mitigation: Phase α production execution session takes a fresh < 60-min backup per HB-08/HB-09 pattern; ON_ERROR_STOP=1 in a single transaction

assumption_5: Nuxt readers depend on explicit field selection (BR-3 finding)
  evidence: `logical_unit_id.canonical_address` appears in client bundle's field list verbatim
  consequence: new columns (authority, format_version) are INVISIBLE to current Nuxt code; no app deploy is required for Phase α to land

assumption_6: identity_profile jsonb's duplicated canonical_address is cosmetic
  evidence: BR-2 finding; same value as the column on 27/86 rows
  treatment: ignore for Phase α; revisit in cosmetic pass later

assumption_7: sandbox_tac is a static test fixture (BR-7) and mirroring additive columns is low-cost
  evidence: 76 rows, single-timestamp seed, disjoint namespace
  treatment: ADD same columns; do NOT backfill in Phase α

§5 — Phase α Design Surfaces

5.1 authority column

table: public.tac_logical_unit
column_name: authority
type: text
nullable_in_phase_α: YES (intentional; promotion to NOT NULL is Phase β)
default_in_phase_α: 'draft'
allowed_values_per_BR_4: { 'enacted', 'draft', 'runtime' } — application-layer enforcement; NO CHECK constraint in Phase α
backfill_rule (BR-4 Candidate B):
  for_existing_86_rows:
    CASE lifecycle_status
      WHEN 'draft_only' THEN 'draft'
      WHEN 'active'     THEN 'enacted'
      WHEN 'retired'    THEN 'enacted'
    END
  expected_outcome_on_today_s_data: all 86 → 'draft'
mirror_on_sandbox_tac.logical_unit: same column added; NO backfill in Phase α

5.2 canonical_address_format_version column

table: public.tac_logical_unit
column_name: canonical_address_format_version
type: text
nullable_in_phase_α: NO (NOT NULL with DEFAULT)
default: 'canonical-address-v1'
backfill: AUTOMATIC at column-add time via DEFAULT (no separate UPDATE)
mirror_on_sandbox_tac.logical_unit: same column added with same default; 76 rows automatically backfilled
future_phase_β_or_γ_considerations:
  - FK to a vocabulary table (Đ24-managed) — Phase γ candidate
  - CHECK constraint enforcing version-string shape — Phase γ
  - migration to v1.1 / v2 grammar via per-row version stamp — supports lazy migration

5.3 canonical_address_alias table (new)

recommended_placement: cutter_governance.canonical_address_alias  (see alias design doc for full rationale)
purpose: history of address renames / redirects / external references
rows_at_creation: 0
phase_α_writers: NONE (the table is created but no rows are written in Phase α — actual rename pathways are Phase β)
phase_α_readers: NONE (no consumer wired yet)
fields (logical; full design in companion doc):
  - alias_id (uuid PK, default gen_random_uuid)
  - target_unit_id (uuid; FK to public.tac_logical_unit.id eventually — or text mirror; design doc decides)
  - alias_text (text; the historical/alternate address)
  - alias_kind (text; enum-ish: 'previous_canonical', 'rename', 'redirect', 'external_reference')
  - valid_from (timestamptz NOT NULL DEFAULT now())
  - valid_until (timestamptz NULL)
  - created_by (text)
  - rationale (text NULL)
  - scenario_ref (text NULL — links to dry-run / production scenarios)
phase_α_constraints:
  - PRIMARY KEY (alias_id)
  - NO FK to public.tac_logical_unit yet (cross-schema FK is feasible but adds coupling; design doc decides)
  - NO UNIQUE on alias_text (multiple aliases per address are expected; supersession history)
mirror_on_sandbox: sandbox_tac.canonical_address_alias OR omit sandbox mirror for the new table — design doc recommends OMIT (sandbox is for tac_logical_unit; alias governance is a governance concern; sandbox-level rename history is not needed)

5.4 sandbox_tac mirror

sandbox_tac.logical_unit:
  + ADD COLUMN authority text NULL DEFAULT 'draft'
  + ADD COLUMN canonical_address_format_version text NOT NULL DEFAULT 'canonical-address-v1'
  + no backfill of authority (76 rows have authority=NULL after column-add)
  + format_version automatically populated via DEFAULT at column-add
sandbox_tac.canonical_address_alias:
  decision: OMIT (per §5.3 rationale)

§6 — Risk Classification

risk_class_for_phase_α: STANDARD
rationale:
  - all changes are ADDITIVE; no ALTER on existing columns or constraints
  - 86 production rows + 76 sandbox rows — small data scale
  - rollback is trivial (DROP COLUMN / DROP TABLE)
  - no reader/writer surface needs change (Nuxt is invisible to new columns; PG functions/triggers do not reference new columns; no app deploy)
  - existing SSOT column unchanged

risk_class_DOES_NOT_escalate_to_HIGH_because:
  - no DOT-pair signing in this phase (no cut_change_set / verify_result rows written)
  - no Đ32 HIGH-risk gates triggered (those apply to P0-3/P0-4 which are v0.1-live but unused in Phase α)

risk_class_could_escalate_to_HIGH_IF (NOT applicable to Phase α as-designed):
  - we added an authority CHECK constraint that rejects existing data
  - we touched event_outbox or birth_registry
  - we changed canonical_address syntax (we don't — BR-5 ratifies the existing syntax)
  - we attempted to make authority NOT NULL in Phase α (we don't — deferred to Phase β)

§7 — What Must Happen Before Dry-Run

prereqs_before_authoring_phase_α_DDL:
  - [x] BR-4 closed
  - [x] BR-5 closed
  - [ ] alias table placement decided (see companion alias design doc — recommendation: cutter_governance)
  - [ ] read-only inspection of fn_tac_birth_gate_lu body (BR-3 §13 followup) to confirm no implicit constraint clash
  - [ ] read-only inspection of fn_iu_birth_gate_layer1 (touches information_unit only; informational; no Phase α direct impact)
  - [ ] dry-run plan authored (companion doc)
  - [ ] risk review plan authored (companion doc)
  - [ ] explicit GPT/User prompt authorizing DDL authoring (NOT yet given)

prereqs_before_dry_run_execution:
  - explicit prompt to ENTER the dry-run authoring lane
  - dry-run env: extend pg-dry-run-hb05-2026-05-15 OR spin a fresh sibling env (decision in dry-run plan)
  - baseline restored from a fresh production backup taken at dry-run setup time
  - HB-equivalent scenarios authored (companion dry-run plan doc)
  - dry-run DDL authored (separate session; explicit prompt; refers to this design)
  - GPT review of dry-run DDL + plan

§8 — What Must Happen Before Production

post_dry_run_requirements:
  - dry-run 100% PASS across scenario matrix
  - blocker-closure pass (HB-equivalent) recorded
  - final readiness review for v0.2 Phase α
  - production command-review package for Phase α (mirrors v0.1 pattern: backup, snapshot, identity preflight, DDL hash gate, migration, verify, rollback, failure-stop)
  - GPT review of command-review package
  - explicit User production execution prompt referencing the command-review package by path
  - separate session for production execution
  - fresh < 60-min production-bound backup at execution time (HB-08 pattern)

production_execution_gates (analog of v0.1 §8 G-1..G-8):
  - production target identity (db=directus on incomex-postgres)
  - cutter_governance schema is the v0.1 set verbatim — must not have drifted
  - existing tac_logical_unit.canonical_address column unchanged (verify by sha256 of post-execution schema diff)
  - dot_tools 991/992 still active and unchanged
  - dry-run env still UP at execution time (per HB-05 rule retained for v0.1; same rule for v0.2 until v0.2 success declared)
  - DDL source has a stable sha256 captured at GPT-review time; sha256 -c gate before production dispatch
  - single-transaction + ON_ERROR_STOP=1

post_production_requirements (analog of v0.1):
  - production execution report
  - GPT ratification of the execution report
  - v0.2 handoff/status document
  - phase β backlog item

§9 — Open Questions for GPT Review

Q1: alias table placement — cutter_governance vs public.tac.* vs new schema?
    agent_recommendation: cutter_governance.canonical_address_alias
    rationale (full in alias design doc): consistent with governance-table location; renames driven by review/change-set workflows; keeps public schema clean

Q2: alias table FK to public.tac_logical_unit(id)?
    agent_recommendation: NO in Phase α; uuid stored without FK
    rationale: cross-schema FK is feasible but adds coupling; alias may also need to reference dropped/retired rows historically; treat target_unit_id as a soft reference

Q3: sandbox_tac.canonical_address_alias mirror?
    agent_recommendation: OMIT
    rationale: alias governance is a public-data concern; sandbox is a fixture; mirroring would duplicate without operational benefit

Q4: identity_profile jsonb cleanup (BR-2 cosmetic finding)?
    agent_recommendation: NOT IN Phase α
    rationale: cosmetic; out of additive-only Phase α scope; revisit later

Q5: authority CHECK constraint in Phase α?
    agent_recommendation: NO
    rationale: nullable column; values can be 'draft'/'enacted'/'runtime' but enforcement waits for Phase β vocab table + NOT NULL

Q6: dry-run env: extend HB-05's OR fresh?
    agent_recommendation: SPIN A FRESH SIBLING dry-run env (e.g., pg-dry-run-v0.2-phase-alpha-2026-05-XX)
    rationale: HB-05 env carries v0.1 dry-run-only cutter_governance + 26-scenario harness state; Phase α dry-run is logically separate; mixing risks cross-contamination

§10 — Status

phase_α_design_master_status: authored_pending_gpt_review
ddl_written: false
mutation_performed: false
dry_run_started: false
production_migration_allowed: false
agent_self_advance_to_DDL_authoring: PROHIBITED
agent_self_advance_to_dry_run: PROHIBITED
each_next_step_terminates_at_GPT_review_or_explicit_user_prompt: TRUE
br_6_status: still OPEN; blocks ONLY P0-2 manifest design; does NOT block Phase α additive work

§11 — Cross-References

companion_design_docs (this session):
  - schema_design:    knowledge/dev/laws/dieu44-trien-khai/v0.2-design/dot-iu-cutter-v0.2-phase-alpha-canonical-address-schema-design-2026-05-15.md
  - alias_design:     knowledge/dev/laws/dieu44-trien-khai/v0.2-design/dot-iu-cutter-v0.2-phase-alpha-canonical-address-alias-design-2026-05-15.md
  - dry_run_plan:     knowledge/dev/laws/dieu44-trien-khai/v0.2-design/dot-iu-cutter-v0.2-phase-alpha-dry-run-plan-2026-05-15.md
  - risk_review_plan: knowledge/dev/laws/dieu44-trien-khai/v0.2-design/dot-iu-cutter-v0.2-phase-alpha-risk-review-plan-2026-05-15.md
  - design_report:    knowledge/dev/laws/dieu44-trien-khai/v0.2-design/dot-iu-cutter-v0.2-phase-alpha-design-report-2026-05-15.md

inputs_(closures):
  - br_4_closure: knowledge/dev/laws/dieu44-trien-khai/v0.2-planning/dot-iu-cutter-v0.2-br-4-authority-backfill-rule-closure-2026-05-15.md
  - br_5_closure: knowledge/dev/laws/dieu44-trien-khai/v0.2-planning/dot-iu-cutter-v0.2-br-5-canonical-address-v1-ratification-closure-2026-05-15.md
  - br_4_5_closure_report: knowledge/dev/laws/dieu44-trien-khai/v0.2-planning/dot-iu-cutter-v0.2-br-4-5-closure-report-2026-05-15.md

inputs_(discovery):
  - br_2_3_7_consolidated: knowledge/dev/laws/dieu44-trien-khai/v0.2-planning/dot-iu-cutter-v0.2-br-2-3-7-discovery-report-2026-05-15.md
  - reconciliation_report: knowledge/dev/laws/dieu44-trien-khai/v0.2-planning/dot-iu-cutter-v0.2-canonical-address-reconciliation-report-2026-05-15.md

v0_1_predecessors:
  - production_handoff: knowledge/dev/laws/dieu44-trien-khai/execution/dot-iu-cutter-v0.1-production-handoff-status-2026-05-15.md
  - v0_2_scope_backlog: knowledge/dev/laws/dieu44-trien-khai/planning/dot-iu-cutter-v0.2-scope-backlog-2026-05-15.md
  - v0_1_p0_1_design (superseded for syntax; retained for authority enum source): knowledge/dev/laws/dieu44-trien-khai/migration-design/dot-iu-cutter-v0.1-p0-1-canonical-address-migration-design-2026-05-15.md

open_blocker:
  - split_merge_metadata_TD (BR-6; gates P0-2 only): knowledge/dev/laws/dieu44-trien-khai/backlog/td-p1-split-merge-metadata-propagation-gap-2026-05-15.md

End of Phase α design master.

Back to Knowledge Hub knowledge/dev/laws/dieu44-trien-khai/v0.2-design/dot-iu-cutter-v0.2-phase-alpha-design-master-2026-05-15.md