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
authorityclassification per row (Đ0-G birth-gate distinction) - explicit
canonical_address_format_versionper row (forward-compat for future grammar revisions) - a separate
canonical_address_aliastable (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.