Birth Gateway SSOT + QT-001 Repair — Canonical Design (Reconstructed)
📋 HO SO QUA TRINH — THIET KE, KHONG PHAI MO TA HE THONG DANG CHAY
Day la ban ghi mot vong thiet ke da ket thuc (2026-06-06). Doc de hieu boi canh lich su, DUNG lam can cu de quyet dinh hay thuc thi.
⚠️ Tai lieu tu ghi "Status: OFFICIAL — staged design, Stage 0 in execution". Do la trang thai thang 6. Dot do 2026-07-29 khong xac minh cac giai doan sau co chay xong hay khong. Muon biet he thong dang chay gi thi do thang trong PostgreSQL, dung suy tu tai lieu nay.
BOI CANH 2026-07-29 — chu he thong xac nhan cum KHAI SINH la huong chua biet dung the nao, chua chac kha thi, dang dat sang mot ben. Nhung chua go duoc vi con nam tren duong GHI (166 trigger, ham khong co EXCEPTION). Thu tu bat buoc neu go: TRIGGER TRUOC, bang/ham SAU.
DO: 2026-07-29 HAN DUNG: tu 2027-01-29 nhan nay la GIA THUYET — DO LAI truoc khi dua vao no. CHI TIET:
docs/BAN-DO-HE-THONG-20260729.md
Birth Gateway SSOT + QT-001 Repair — Canonical Design (Reconstructed)
Date: 2026-06-06 · Status: OFFICIAL — staged design, Stage 0 in execution.
0. Provenance
The Codex design package authored only 00-readme-first.md and 11-final-summary.md; detailed docs 01..10 were never written. This document reconstructs ONE executable design from those two docs + checkpoint-codex-birth-gateway-ssot-qt001-design-plan-2026-06-06.md + checkpoint-codex-birth-first-side-door-compatibility-audit-2026-06-06.md, cross-checked against live production (2026-06-06). No unknown implementation details were invented; every "CURRENT" fact below is live-verified, every "TARGET" item is carried verbatim-in-intent from the source design.
1. Problem statement (the side door)
The live birth gateway fn_birth_registry_auto() was patched (P0 remediation) to skip births for EXEMPT/DEFERRED collections (it reads collection_registry.coverage_status / BIRTH_EXEMPT). But the DOT dot-birth-trigger-setup (DOT-119) still embeds and installs an OLD version of that same function via CREATE OR REPLACE FUNCTION fn_birth_registry_auto() (its line 113) — a version that looks up only governance_role and has no coverage_status / BIRTH_EXEMPT guard. Running that DOT silently reverts the gateway to pre-fix logic across 166 triggers / 148 tables, reopening the birth/object-pollution P0 for 36 EXEMPT + 58 DEFERRED collections. dot-birth-backfill (DOT-118) independently does direct INSERT INTO birth_registry and is incompatible with 22/36 governed collections (can partially execute). This is operational SSOT drift: runtime can be overridden by stale DOT source.
2. Gateway SSOT decision
- The single source of truth for the gateway is an immutable, versioned Git migration release of the birth policy/identity/register functions — NOT a DOT-embedded heredoc.
- Runtime proof of integrity is an append-only semantic function contract registry + SHA-256 (or normalized-md5) verifier: the live function's normalized source hash must match the approved release hash, and must contain the required policy markers (
coverage_status,BIRTH_EXEMPT). Any divergence is machine-detectable and fails closed. - No tool may define the gateway by shipping its own copy of the function body.
3. Rule: dot-birth-trigger-setup must NEVER CREATE OR REPLACE FUNCTION
dot-birth-trigger-setupis redesigned to trigger-reconcile only: it mayDROP/CREATE TRIGGER ... EXECUTE FUNCTION fn_birth_registry_auto(...)to attach the already-released gateway to a collection, but it may never contain or apply aCREATE OR REPLACE FUNCTIONfor anyfn_birth*.- The embedded "Step 2: Creating master birth trigger function" block must be deleted from the DOT in Stage 1; the function comes only from the immutable release.
- Same rule applies to
dot-schema-birth-registry-ensure(it must ensure schema/meta only, never afn_birth*body that competes with the release).
4. Shared function architecture (TARGET — Stage 1)
Realtime birth (QT-002) and backfill (QT-001) must share ONE policy/identity/register path so they can never diverge:
| Function | Responsibility |
|---|---|
fn_birth_policy_decision |
Given a collection, return BIRTH / SKIP_EXEMPT / DEFER from collection_registry.coverage_status (the exempt guard, single definition). |
fn_birth_resolve_identity |
Resolve entity identity (code field / birth_code_strategy / birth_identity_source) for the collection — replaces hardcoded TG_ARGV code-field maps. |
fn_birth_register |
Perform the birth_registry insert (idempotent, ON CONFLICT DO NOTHING), used by BOTH the realtime trigger and the QT-001 apply DOT. |
CURRENT: these three functions do not exist yet. The live gateway fn_birth_registry_auto() inlines all three concerns. Stage 1 extracts them into the immutable release and rewrites the realtime trigger + QT-001 to call them.
5. QT disposition
| QT | Meaning | CURRENT | TARGET |
|---|---|---|---|
| QT-001 | Backfill birth for existing rows | dot-birth-backfill direct INSERT; incompatible 22/36; no permit/ledger |
Paired metadata-driven plan/apply DOTs: exact preflight, batch transactions, exempt audit ledgers, uncertified births, calls fn_birth_register |
| QT-002 | Birth-first for new entity | Live; enforced by fn_birth_registry_auto (AFTER INSERT) + fn_birth_gate (BEFORE INSERT) |
Unchanged path, but trigger calls the shared release functions |
| QT-003 | New collection registration | Soft/detect-only; dot-collection-create calls dot-birth-trigger-setup (guarded by -x) |
Hard first-row gate; never redefines gateway |
| QT-003R | Retroactive registration (0-row tables) | Soft; >0 rows must STOP→QT-001 |
Hard first-row gate |
| QT-005 | Promote/demote governance_role | Detect-only; birth records kept on demote | One orchestrated state transition preserving history |
| QT-006 | Death / lifecycle | Absent (no death trigger) | Separate approved universal lifecycle-state program; birth fact remains immutable |
6. Stage 0..5 rollout
- Stage 0 — FREEZE + GUARD (this macro). Freeze/guard accidental execution of
dot-birth-trigger-setupanddot-birth-backfill; make gateway-SSOT drift machine-detectable; do not worsen any live QT path; author Stage 1 packet. Reversible; additive views only; no gateway/trigger/data mutation. - Stage 1 — GATEWAY SSOT IMPLEMENTATION. Immutable Git release of
fn_birth_policy_decision/fn_birth_resolve_identity/fn_birth_register; runtime semantic contract registry + verifier; stripCREATE OR REPLACE FUNCTIONfromdot-birth-trigger-setup(reconcile-only); birth admission permit + backfill ledger tables. - Stage 2 — QT-001 plan/apply. Paired metadata-driven backfill with exact preflight, exempt audit, uncertified births; classify the 43 unclassified identity strategies first.
- Stage 3 — QT-003 / QT-003R first-row hard gate.
- Stage 4 — QT-005 governance transition (single orchestrated, history-preserving).
- Stage 5 — QT-006 universal lifecycle / death (separate approved program).
7. Forbidden DOTs until fixed
Until Stage 1 passes source-parity / preflight review, do not run: dot-birth-trigger-setup, dot-birth-backfill, and (because it invokes trigger-setup) the trigger-setup step of dot-collection-create. No CREATE OR REPLACE FUNCTION fn_birth* from any DOT. No raw SQL INSERT into birth_registry. No trigger DROP/CREATE for birth outside the reconcile-only path.
8. Rollback / no-go
- Stage 0 is reversible: every guard is an additive view (
DROP VIEWrollback); any execution-path quarantine has a stagedmv-back rollback (BIRTH_STAGE0_FREEZE_ROLLBACK.md). - No-go if: live read of gateway source fails; the freeze would break a non-degrading caller; any action would mutate
birth_registry, a birth trigger, or afn_birth*body; OOM/512MB risk on heavy scans. - Birth-neutral invariant:
birth_registrycount before == after for every applied DDL (anchor 1,210,834).
9. Live baseline (verified 2026-06-06)
| Item | Value |
|---|---|
birth_registry rows |
1,210,834 |
| coverage_status | BIRTH_REQUIRED 74 / BIRTH_DEFERRED_NEEDS_REVIEW 58 / EXEMPT (junction 20 + log/audit 12 + derived-cache 4 = 36) |
| governance_role | observed 67 / excluded 60 / governed 36 / locked 3 / law_artifact 2 |
| BIRTH_REQUIRED identity_source | unclassified 43 / inferred_from_existing_trigger 28 / migration_seed 2 / manual 1 |
BIRTH_REQUIRED with native status col |
54/74 |
| BIRTH_REQUIRED without birth trigger | 2 (iu_staging_payload, iu_staging_record — no PG table) |
gateway fn_birth_registry_auto |
GUARDED: has coverage_status + BIRTH_EXEMPT; 166 triggers / 148 tables; normalized-md5 c022f849c2c7d57a720c4cc172789d70 |
fn_birth_registry_auto_id |
NO exempt guard; 3 BIRTH_REQUIRED tables only |
| danger DOT md5 | trigger-setup a0b926d3fd373b8995aea2f4e8136e01; backfill f04cdbf5363a67cd837fdad9d649df2a |
10. Next macro
BIRTH_STAGE1_GATEWAY_SSOT_IMPLEMENTATION — implement the immutable gateway release + runtime semantic contract registry, strip gateway-redefine from the setup DOT, and create the birth admission permit + backfill ledger. See BIRTH_STAGE1_GATEWAY_SSOT_IMPLEMENTATION_PACKET.md.
11. Stage 1 result — LIVE (2026-06-06)
Stage 1 executed PASS. What is now live (additive, reversible; rollback /opt/incomex/docs/mcp-writes/birth-stage1-2026-06-06/99_rollback_stage1.sql):
- Runtime contract registry
birth_gateway_release_registry(releasev1-stage1-2026-06-06, append-only by convention), seeded from live capture for 5 fns with normalized-md5 + semantic SHA-256. Views:v_birth_gateway_release_current,v_birth_gateway_release_drift_guard,v_birth_gateway_contract_integrity_dashboard(all OK). This realizes the SSOT decision (§2): there is now ONE live place to check which gateway contract is current, with machine-detectable, fail-closed semantic drift. - Shared functions (§4) now exist:
fn_birth_policy_decision(text)(EXEMPT→skip / REQUIRED→birth / DEFERRED→defer / else UNKNOWN_BLOCK; deterministic, no-write, STABLE, fail-closed);fn_birth_resolve_identity(text,jsonb)(readsbirth_code_*/birth_identity_source; NULL-row = eligibility preflight; never invents identity for the 43 unclassified; no-write);fn_birth_register(text,jsonb,boolean,text)(policy→identity→idempotentON CONFLICT (entity_code)insert; p_dry_run defaults TRUE; single-row, not bulk). Proven in BEGIN..ROLLBACK: dry-run REQUIRED→would_register, EXEMPT/DEFERRED→skipped (even non-dry), real register→registered (+1), duplicate→skipped (idempotent), unknown→blocked, ROLLBACK→net 0. - Permit + ledger (§ packet):
birth_admission_permit+birth_backfill_ledgercreated, empty (fail-closed; QT-001 apply will require an open permit).
What was deliberately NOT done (kept for Stage 2 / T2 review):
- The live trigger gateway
fn_birth_registry_autowas NOT rewritten to call the new functions (integration Option A = parity-guard-only). Reason: preserve the QT-002 live path with zero behavior change. Parity holds for EXEMPT (both skip) and REQUIRED (both birth); for DEFERRED and UNREGISTERED the Stage 1 contract is stricter (defer/block where the live gateway still births) — i.e. the contract can only ever produce fewer births, never more (no-worse proven). Full thin-wrapper integration (Option C) and the setup-DOTCREATE OR REPLACE FUNCTIONstrip are staged for Stage 2 under T2 review. Live gateway norm-md5c022f849unchanged; tga 129; birth before==after. - No QT-001 backfill. See
BIRTH_STAGE2_QT001_METADATA_BACKFILL_REPAIR_PACKET.md.
Next macro: BIRTH_STAGE2_QT001_IDENTITY_CLASSIFICATION_AND_METADATA_BACKFILL — classify the 43 unclassified identities, resolve the 2 no-table REQUIRED collections, build paired plan/apply DOTs over fn_birth_register, open per-collection permits, dry-run→batched-apply→rerun-delta=0.
12. Stage 2 result — PARTIAL (2026-06-06)
Stage 2 executed PARTIAL (all safe branches complete; real backfill apply deliberately NOT committed — gated by independent T2 review per packet section 7 + owner permit). Additive, reversible, birth-neutral; macro net births = 0. Live fn_birth_registry_auto and all triggers unchanged (tga 129; no_go 4/4; contract all_ok).
- Identity classified 39 of 43 (resolvable 31 → 70 of 74) by mirroring each live birth trigger's
TG_ARGV: 7column(apr_action_types=action_code; checkpoint_instances, checkpoint_type_overrides, comments, table_proposals, trigger_registry, workflow_categories = code) + 32synthetic_id(collection::id). This makes backfill entity_codes byte-identical to the realtime path → zero duplicate risk, idempotent. Classification is acollection_registry.birth_code_*metadata UPDATE, invisible to the live gateway (it does not readbirth_code_*). - 4 NEEDS_OWNER (left unclassified, action-packed): apr_request_types, binding_registry, nrm_doc_type_config (no
idcolumn + no-arg live trigger → would computecollection::NULL, violating entity_code NOT NULL → 0 births; classifying without reconciling the trigger is realtime-divergent), and nrm_approval_rules (composite PK, no single natural key). Owner must pick the identity key AND reconcile the realtime trigger arg. - 2 no-table REQUIRED (iu_staging_payload, iu_staging_record): identity classified but no PG table → not backfillable; create-or-reclassify is owner/QT-003R scope.
- Full dry-run over 39 eligible: 137 expected new births across 5 governed collections (dot_domain_rules 67, apr_approvals 42, normative_relations 18, apr_action_types 6, field_type_equivalences 4); 34 others already covered or empty.
- Apply rehearsed in BEGIN..ROLLBACK: applied_delta=137, rerun_delta=0 (idempotent), ROLLBACK clean — committed nothing.
- Plan/apply DOT source authored (
fn_dot_birth_qt001_planread-only;sp_dot_birth_qt001_applygated/fail-closed) but NOT deployed live; olddot-birth-backfill/dot-birth-trigger-setupstay frozen. - 25 guard/inventory/decision views live (all green). Rollback staged
99_rollback_stage2.sql.
Next macro: T2_REVIEW_STAGE2_BEFORE_APPLY → BIRTH_STAGE2_QT001_APPLY_IF_READY; parallel BIRTH_STAGE2_METADATA_REPAIR_CONTINUE (4 needs-owner + 2 no-table). See report dir birth-stage2-qt001-identity-metadata-backfill-repair-2026-06-06.