KB-6946 rev 4

Birth Gateway SSOT + QT-001 Repair — Canonical Design (Reconstructed)

15 min read Revision 4
birth-gatewayssotqt-001designcanonical2026-06-06

📋 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-setup is redesigned to trigger-reconcile only: it may DROP/CREATE TRIGGER ... EXECUTE FUNCTION fn_birth_registry_auto(...) to attach the already-released gateway to a collection, but it may never contain or apply a CREATE OR REPLACE FUNCTION for any fn_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 a fn_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-setup and dot-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; strip CREATE OR REPLACE FUNCTION from dot-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 VIEW rollback); any execution-path quarantine has a staged mv-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 a fn_birth* body; OOM/512MB risk on heavy scans.
  • Birth-neutral invariant: birth_registry count 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 (release v1-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) (reads birth_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→idempotent ON 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_ledger created, 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_auto was 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-DOT CREATE OR REPLACE FUNCTION strip are staged for Stage 2 under T2 review. Live gateway norm-md5 c022f849 unchanged; 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: 7 column (apr_action_types=action_code; checkpoint_instances, checkpoint_type_overrides, comments, table_proposals, trigger_registry, workflow_categories = code) + 32 synthetic_id (collection::id). This makes backfill entity_codes byte-identical to the realtime path → zero duplicate risk, idempotent. Classification is a collection_registry.birth_code_* metadata UPDATE, invisible to the live gateway (it does not read birth_code_*).
  • 4 NEEDS_OWNER (left unclassified, action-packed): apr_request_types, binding_registry, nrm_doc_type_config (no id column + no-arg live trigger → would compute collection::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_plan read-only; sp_dot_birth_qt001_apply gated/fail-closed) but NOT deployed live; old dot-birth-backfill/dot-birth-trigger-setup stay frozen.
  • 25 guard/inventory/decision views live (all green). Rollback staged 99_rollback_stage2.sql.

Next macro: T2_REVIEW_STAGE2_BEFORE_APPLYBIRTH_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.