P3D — B3-ELD Entity Living DB Placeholder Design
P3D — B3-ELD Entity Living DB Placeholder Design
Date: 2026-05-14 Author: Opus (Claude Code) — DESIGN ONLY Mode: NO PG mutation, NO DDL, NO DML, NO function patch, NO trigger patch. Read-only verification + design doc. Predecessor:
p3d-birth-mainline-resume-completeness-verification-report.mdGPT priority:gpt-review-b3-mainline-resume-completeness-verification-priority-adjusted-2026-05-14.mdSecrets redacted: true
1. Purpose & scope
GPT review accepted B3-MAINLINE-RESUME evidence and adjusted priority so the Entity Living DB (ELD) placeholder layer is the PRIMARY birth-complete blocker. Of the 6 design-named ELD fields, only governance_role lives on birth_registry. The four absent placeholders — canonical_address, owner, jsonb_profile, identity_profile — must be designed before any DDL/DML is authorized.
This document decides per-field placement, birth responsibility, backfill, function impact, contract impact, PG-native pattern, relation-hook alignment, enrichment alignment, options comparison, and a single recommendation. It authorizes nothing. Phase 5C2 remains gated. Wrapper / system_health_checks insert / scheduler repair remain separate workstreams.
Out of scope: trigger function rewrites, vector pipeline, Pivot population, UI cutover, dot-dot-health repair.
2. Live PG evidence (2026-05-14, READ-ONLY)
All SELECTs executed via docker exec postgres psql -U directus -d directus -At. No mutation. Secrets redacted.
2.1 Mandatory existing-pattern detection
Existing columns named like the 5 ELD fields anywhere in public:
| column_name | tables | data_type | notes |
|---|---|---|---|
canonical_address |
event_outbox, event_pending, information_unit, iu_notification_event, tac_logical_unit, unit_edit_draft (6 tables) |
text |
Already a live convention. Sample values look like slug paths: pilot.iu0.test-001. |
identity_profile |
information_unit, tac_logical_unit (2 tables) |
jsonb |
Both NOT NULL DEFAULT '{}'::jsonb. Sample: {"title": "...", "owner_lookup_ref": "agent:p3c4", "primary_section_type_ref": "section"}. |
owner |
agents, collection_registry, dot_tools, help_articles, modules, organizations, os_deals, os_projects, tac_change_set, tac_logical_unit, tac_publication, tac_section_type_vocab, ui_pages (13 tables) |
mostly varchar, some text/character |
Inconsistent shape. Many tables also use distinct owner_ref text (e.g., information_unit). |
jsonb_profile |
NONE | — | Never used as a literal column name. Variants exist: identity_profile, content_profile, publication_profile. jsonb_profile is a category, not a column. |
governance_role |
birth_registry, collection_registry, v_entity_full_classification |
varchar/text |
Already on birth_registry (verified prior). |
2.2 information_unit schema (canonical ELD reference shape)
Verified columns (first 15):
id uuid NOT NULL DEFAULT gen_random_uuid()
canonical_address text NOT NULL
unit_kind text NOT NULL
lifecycle_status text NOT NULL DEFAULT 'draft'
content_anchor_ref text NULL
version_anchor_ref uuid NULL
owner_ref text NOT NULL -- NOTE: owner_ref, not owner
parent_or_container_ref uuid NULL
conformance_status text NOT NULL DEFAULT 'open'
identity_profile jsonb NOT NULL DEFAULT '{}'::jsonb
created_at timestamptz NOT NULL DEFAULT now()
...
Key signals: canonical_address and identity_profile already coexist on the same row in the entity layer, with identity_profile as a JSONB default-{} placeholder. owner is exposed as owner_ref (text reference) — not the bare owner column variant.
2.3 birth_registry schema (verified prior, re-confirmed)
19 columns. Of the 6 ELD targets, only governance_role present:
id, sort, user_created, date_created, user_updated, date_updated,
entity_code, collection_name, species_code, composition_level, dot_origin, born_at,
governance_role, inspect_pen, inspect_stamp, inspect_gate, certified, certified_at, status
2.4 fn_birth_registry_auto body (verified)
Inserts exactly 8 columns: entity_code, collection_name, species_code, composition_level, dot_origin, born_at, governance_role, certified.
The trigger function has NO knowledge of any other column on birth_registry. Any nullable column added to birth_registry defaults to NULL on insert; the function does not need to know it exists. The function is "dumb/fast" by design and stays that way.
ON CONFLICT (entity_code) DO NOTHING on insert.
2.5 Sample birth_registry rows
292599|knowledge_documents::3174|knowledge_documents|ai_support|atom|PG:trg_birth_knowledge_documents|observed|born
Row is a registry stub. It correctly already references the entity by (collection_name, entity_code) — i.e., the universal birth address (B2 §4). It does NOT carry instance-level enrichment yet.
2.6 Profile-like columns across schema
tac_unit_version content_profile jsonb
unit_version content_profile jsonb
information_unit identity_profile jsonb
tac_logical_unit identity_profile jsonb
tac_publication publication_profile jsonb
The pattern is kind-specific JSONB columns, not a single generic jsonb_profile.
2.7 Address tables
Only organization_addresses exists. No general entity_address / address_registry exists. canonical_address is treated as a slug/path string in information_unit, not a normalized FK to an address table.
3. Per-field placement decisions
For each field, choices: A=birth_registry, B=collection_registry, C=per-entity physical table, D=new ELD table, E=JSONB profile store, F=derived-only, G=hybrid.
3.1 canonical_address
- Decision: G (HYBRID) — primary placement A:
birth_registry.canonical_address textas a placeholder; physical-table copies on entities that already have one (information_unit + 5 others) remain authoritative. - Rationale:
- Existing pattern (§2.1) puts
canonical_addresson the entity row, not a central registry. Pattern istextslug-path. - But B2 §4 already declares universal birth address =
(collection_name, entity_code). For 99% of collections there is no native slug; the placeholder must live in one universal place:birth_registry. - For collections that already carry
canonical_addresson the physical table (6 tables), the birth-registry copy is mirrored on enrichment (DERIVED_LATER from physical), not authoritative.
- Existing pattern (§2.1) puts
- Evidence tags: LIVE_PG §2.1, §2.2; KB B2 §4.
- Type:
text NULLonbirth_registry. No default. Backfill via enrichment job — see §5.
3.2 owner
- Decision: A (birth_registry) — placeholder with explicit name
ownertext NULLfor the placeholder slot; enrichment populates via owner-resolution chain (B2 §3). - Rationale:
- Existing
ownercolumns (§2.1, 13 tables) are inconsistent (varchar/text/character) and named ambiguously vsowner_ref(information_unit's pattern). - We choose
owner text NULLonbirth_registryto match B2 §3's owner-resolution result (final resolved string, e.g.agent:p3c4,user:abc,team:legal,UNKNOWN_OWNER). - We do NOT add an
owner_refsecond column on birth_registry — birth_registry stores the resolved owner, not the source pointer. The source pointer remains on the physical table (where applicable).
- Existing
- Evidence tags: LIVE_PG §2.1, §2.2 (
owner_refon information_unit); KB B2 §3 (owner ABSENT per contract). - Type:
text NULL. No default. Backfill: ENRICHED_LATER (UNKNOWN_OWNERsentinel allowed; neverNULLafter enrichment passes).
3.3 jsonb_profile
- Decision: A (birth_registry) —
jsonb_profile jsonb NOT NULL DEFAULT '{}'::jsonbas the generic JSONB store for cross-cutting birth-time hints (description_policy snapshot, classification snapshot, hook references, owner-resolution trace). - Rationale:
- Existing physical-table pattern uses kind-specific JSONB columns (
identity_profile,content_profile,publication_profile) — those stay on physical tables and are NOT collapsed intojsonb_profile. birth_registryis the universal layer; it needs a catch-all JSONB slot so future enrichment (B6) can add keys without DDL. This is the self-expanding pattern.- Default
'{}'::jsonblets the soft gate / full-scan checkjsonb_profile <> '{}'::jsonbfor enrichment readiness without NULL-handling.
- Existing physical-table pattern uses kind-specific JSONB columns (
- Evidence tags: LIVE_PG §2.6 (kind-specific profiles exist, generic profile does NOT exist).
- Type:
jsonb NOT NULL DEFAULT '{}'::jsonb. Backfill: existing 292,599 rows get default{}— safe.
3.4 identity_profile
- Decision: G (HYBRID), but primary placement is C (per-entity physical table) for entities that need it; placeholder column on birth_registry is OPTIONAL and recommended SKIPPED.
- Rationale:
identity_profilealready exists oninformation_unitandtac_logical_unitasjsonb NOT NULL DEFAULT '{}'. The intended semantic is kind-specific identity metadata (title, primary refs, lookup keys for the entity as that entity-kind).- For ~140 collections that have no kind-specific identity profile, putting a per-row
identity_profileonbirth_registrywould duplicatejsonb_profilesemantics (decision 3.3) and create two empty JSONB slots competing for the same data. - Recommendation: DO NOT add
identity_profiletobirth_registry. Treat it as DERIVED_LATER from physical tables when present; otherwise leave absent.jsonb_profile.identityJSONB key onbirth_registrycan carry a snapshot for cross-collection summaries if needed.
- Evidence tags: LIVE_PG §2.1, §2.2, §2.6.
- Type: not added centrally.
3.5 Summary table
| Field | Primary placement | birth_registry column? | Type | Default | Rationale ref |
|---|---|---|---|---|---|
| canonical_address | HYBRID (registry placeholder + physical-table mirror) | YES | text |
NULL | §3.1 |
| owner | birth_registry | YES | text |
NULL | §3.2 |
| jsonb_profile | birth_registry (new universal slot) | YES | jsonb |
'{}'::jsonb NOT NULL |
§3.3 |
| identity_profile | per-entity physical (existing); not on birth_registry | NO | — | — | §3.4 |
Net DDL surface (when authorized): 3 nullable/defaulted ADD COLUMN on birth_registry, no new tables, no FK, no UNIQUE.
4. Birth responsibility matrix
| Field | Classification | Birth trigger writes it? | Enriched by | When |
|---|---|---|---|---|
| canonical_address | PLACEHOLDER_AT_BIRTH (NULL slot) | NO — trigger does not write | enrichment job derived from physical table; otherwise stays NULL | post-birth, idempotent |
| owner | PLACEHOLDER_AT_BIRTH (NULL slot) | NO | B2 §3 owner-resolution chain → agent:*, user:*, team:*, UNKNOWN_OWNER |
post-birth, idempotent |
| jsonb_profile | REQUIRED_AT_BIRTH (default '{}', NOT NULL) |
NO write needed — column default covers it | enrichment job patches JSONB keys | post-birth, idempotent |
| identity_profile | NOT_BIRTH_RESPONSIBILITY (per-entity) | NO | already populated where it exists (default '{}') on physical tables |
n/a |
| governance_role | REQUIRED_AT_BIRTH (already wired) | YES — trigger writes from collection_registry |
— | birth-time |
| description_policy | NOT_BIRTH_RESPONSIBILITY (collection-level) | n/a — lives on collection_registry, fully populated |
— | n/a |
Birth trigger function changes required: NONE — see §6.
5. Backfill plan
Pre-conditions: 292,599 rows in birth_registry (most recent IDs probed).
| Field | Default | Existing rows backfill | Safe? | Required before Phase 5C2? |
|---|---|---|---|---|
| canonical_address | NULL | None at DDL time; enrichment job fills later | YES — adding a nullable column is metadata-only | NO (placeholder OK at 5C2 entry; enrichment can be parallel) |
| owner | NULL | None at DDL time; enrichment job fills later | YES | NO — placeholder acceptable; enrichment closes gap |
| jsonb_profile | '{}'::jsonb (DEFAULT, NOT NULL) |
All existing rows auto-fill '{}' at ADD COLUMN (PG ≥11 fast-path with constant default) |
YES — fast-path; no full rewrite | YES — column must exist before 5C2 if soft gate references it |
| identity_profile | n/a | n/a | n/a | n/a |
No backfill DDL/DML authorized here. This plan is for the future B3-ELD-EXEC pack.
Phase 5C2 readiness: the only strictly required slot before 5C2 is jsonb_profile (because soft gate/full-scan may reference it). canonical_address and owner columns must exist (DDL) but their values may be NULL at 5C2 entry, with enrichment closing the gap in B6.
6. Function impact
| Object | Modification required? | Reason |
|---|---|---|
fn_birth_registry_auto |
NO | Function inserts 8 named columns (§2.4). Adding nullable/defaulted columns is transparent. |
fn_birth_registry_auto_id |
NO | Same reasoning — variants inherit same insert shape. |
fn_collection_onboarding_soft_gate |
OPTIONAL | Currently checks species mapping + classification. Adding a check for jsonb_profile column existence is OPTIONAL hardening for B3-F1d follow-up. |
fn_birth_onboarding_full_scan |
OPTIONAL | Could add a NULL-rate report for canonical_address/owner to surface enrichment gaps. Non-blocking. |
fn_b3f1_log_collection_onboarding_gap |
NO | No signature change. |
Net effect: birth_function_patch_required=false. Trigger layer stays dumb/fast. Enrichment is a separate pass.
7. Contract impact (B2 / B3-F)
7.1 B2 contract (p3d-birth-system-b2-contract-design.md rev2)
B2 rev3 REQUIRED. Required revisions:
- §2 (Birth metadata contract): adjust from "9/10 supported, owner ABSENT" to "9/10 supported; owner present as PLACEHOLDER_AT_BIRTH; canonical_address, jsonb_profile added as PLACEHOLDER/REQUIRED slots; identity_profile remains per-entity-kind (not centralized)".
- §3 (Owner resolution): explicitly mark
birth_registry.owneras the resolved result; physical-tableowner/owner_refcolumns are sources. - §4 (Universal birth address): canonical address is
(collection_name, entity_code)pair AND optionallycanonical_address textfor entities with native slug paths. Birth registry carries a NULL-able mirror. - §5 (8 relation hooks): unchanged — see §9 mapping.
- §6 (Coverage classification): add ELD column-population coverage as a sub-status (e.g.,
ELD_PLACEHOLDER_PRESENT,ELD_ENRICHED,ELD_PENDING).
7.2 B3-F gate updates
| Gate | Update required? | What |
|---|---|---|
Soft gate (fn_collection_onboarding_soft_gate) |
NO for placeholder DDL; OPTIONAL to add ELD column presence check | non-blocking |
Full-scan (fn_birth_onboarding_full_scan) |
NO for DDL; YES (recommended) to add NULL-rate audit columns post-DDL | enrichment visibility |
| Onboarding (new collection) requires ELD fields? | NO — placeholder columns are universal on birth_registry; nothing per-collection is required at onboarding |
self-expanding by design |
7.3 Roadmap impact
- B2 → B2 rev3 (this design's contract revision).
- B3 → unchanged, but a new sub-step B3-ELD-EXEC added between B3 and B4.
- B4 (backfill) → only
canonical_addressandownerenrichment;jsonb_profileis auto-defaulted by DDL.
8. PG-native self-expanding pattern
Design must NOT hardcode collection lists or species lists.
8.1 Anti-hardcode invariants
- ELD placeholder columns live on a universal table (
birth_registry), not per-collection. ✓ - DDL adds 3 columns once; no per-collection migration. ✓
- No list of "ELD-enabled collections" anywhere in code or config. ✓
- New collections inherit
birth_registrycolumns automatically as soon asfn_birth_registry_autofires. ✓
8.2 Self-expansion mechanics
When a new collection is onboarded:
- Row appears in
collection_registrywithgovernance_role(B2 contract guaranteed). - Optional species mapping appears in
species_collection_map. - First INSERT on the new table fires
fn_birth_registry_auto, which writes the 8 known columns. The 3 new ELD placeholder columns default automatically:canonical_address→ NULLowner→ NULLjsonb_profile→'{}'::jsonb
- Enrichment passes pick up the row via
WHERE owner IS NULL/WHERE jsonb_profile = '{}'/WHERE canonical_address IS NULLqueries — no allowlist required.
8.3 Discovery-first contract
Enrichment jobs MUST derive their target set from:
collection_registry(which collections are governed),species_collection_map(per-collection species),birth_registry(which rows exist), and- the new ELD placeholder NULL/empty predicate.
No IN ('table_a', 'table_b', ...) literals allowed.
9. Relation hook alignment matrix (8 hooks × 4 ELD fields)
Cells show what role each field plays for each Điều 21 §III hook.
| Hook | canonical_address | owner | jsonb_profile | identity_profile |
|---|---|---|---|---|
| IDENTITY (T̀ôi là ai) | anchor (universal birth address mirror) | secondary | snapshot key | per-kind identity |
| BELONGS_TO (T̀ôi thuộc về ai) | — | direct support (owner=container) | snapshot key belongs_to_ref |
— |
| CONTAINS (T̀ôi chứa gì) | — | — | snapshot key contains_summary |
— |
| DEPENDS_ON | — | — | snapshot key depends_on_refs |
— |
| USED_BY | — | — | snapshot key used_by_refs |
— |
| TRANSITIVE | indirect (via address graph) | — | snapshot key transitive_seed |
— |
| PEERS | — | — | snapshot key peers_classification |
per-kind identity (feeds peer query) |
| SIMILAR | — | — | snapshot key similar_seed_text |
per-kind identity (feeds vector input) |
Key insight: jsonb_profile is the universal hook-snapshot slot, populated lazily, namespaced by hook name. This eliminates 8 separate columns and gives B6 enrichment freedom to add keys without DDL.
10. Enrichment alignment matrix
How each placeholder supports each enrichment workstream.
| Enrichment | canonical_address | owner | jsonb_profile | identity_profile |
|---|---|---|---|---|
| Vector / Qdrant | — | — | jsonb_profile.similar_seed_text feeds embedding input |
per-kind identity feeds embedding (existing pipeline) |
| Pivot / facet / classification | — | — | jsonb_profile.peers_classification stores pivot snapshot |
— |
| peers | — | — | snapshot from pivot result | per-kind classification basis |
| similar | — | — | seed text + vector hash | per-kind text source |
| transitive | seed for graph BFS | — | edge enumeration cache | — |
| description_policy | — | — | jsonb_profile.description_policy_snapshot (from collection_registry.description_policy) |
— |
| canonical address resolution | primary | — | fallback cache | — |
| owner resolution | — | primary (resolved result) | trace in jsonb_profile.owner_resolution_trace |
— |
11. Options A/B/C/D comparison
Option A — Add 3 nullable/defaulted columns to birth_registry (RECOMMENDED)
Add canonical_address text NULL, owner text NULL, jsonb_profile jsonb NOT NULL DEFAULT '{}'::jsonb. Skip identity_profile (per §3.4).
| Aspect | Detail |
|---|---|
| Pros | Smallest DDL surface; zero trigger-function change; PG ≥11 fast-path ADD COLUMN with constant default; aligns with universal (collection_name, entity_code) address; backwards compatible; self-expanding; rollback = DROP COLUMN |
| Cons | Columns are universal — may force NULLs on collections that semantically have no canonical_address; small storage overhead for 292k+ rows |
| Hardcode risk | LOW — no per-collection logic |
| Scale risk | LOW — birth_registry is one table; columns scale with row count, not collection count |
| Migration complexity | LOW — 3 ADD COLUMNs; fast-path defaults |
| Function impact | NONE |
| Rollback complexity | LOW — DROP COLUMN works as long as no enrichment writes are pending |
| Compatibility with Phase 5C2 | HIGH — jsonb_profile present, soft gate can reference it |
Option B — New entity_living_db table with 1:1 to birth_registry
Create entity_living_db (birth_id FK, canonical_address, owner, jsonb_profile, identity_profile, ...).
| Aspect | Detail |
|---|---|
| Pros | Clean separation of concerns; ELD evolves without touching birth_registry; allows richer ELD schema later (FK to address tables, audit trail) |
| Cons | Requires NEW FK on every birth; trigger function MUST be patched to also insert into ELD table; backfill required for 292k rows; JOIN every read; rollback complex (DROP TABLE + un-patch trigger) |
| Hardcode risk | LOW |
| Scale risk | MEDIUM — extra table doubles birth-time write cost; JOIN on every enrichment read |
| Migration complexity | HIGH — CREATE TABLE + FK + trigger patch + backfill 292k rows |
| Function impact | YES — fn_birth_registry_auto MUST be patched (breaks "dumb/fast" principle) |
| Rollback complexity | HIGH |
| Compatibility with Phase 5C2 | MEDIUM — requires successful trigger patch first |
Option C — Hybrid: minimal columns on birth_registry + entity_living_db_profiles for kind-specific JSONB
Add canonical_address, owner to birth_registry; create a entity_living_db_profiles (birth_id, profile_kind, payload jsonb) table for identity_profile, content_profile, etc.
| Aspect | Detail |
|---|---|
| Pros | Theoretically tidy; kind-specific profiles centralized |
| Cons | Existing physical tables already own kind-specific profiles (information_unit, tac_*); duplicates them; loop-back risk; requires sync; collides with the existing successful pattern |
| Hardcode risk | MEDIUM — profile_kind enum tends to become hardcoded list |
| Scale risk | MEDIUM |
| Migration complexity | MEDIUM-HIGH |
| Function impact | MEDIUM — additional INSERT path |
| Rollback complexity | MEDIUM |
| Compatibility with Phase 5C2 | MEDIUM |
Option D — Derived-only / no storage
Do NOT add any column. Define canonical_address, owner, jsonb_profile, identity_profile as views over birth_registry JOIN collection_registry JOIN per-entity tables.
| Aspect | Detail |
|---|---|
| Pros | Zero DDL; zero migration; pure read-path |
| Cons | Cannot persist owner-resolution result; cannot snapshot description_policy at birth time; soft gate cannot reference a column; performance penalty on every read (multi-table join, sometimes 100+ collections); fragile when underlying tables drop columns |
| Hardcode risk | HIGH — view must enumerate all collections with canonical_address |
| Scale risk | HIGH — JOINs across hundreds of physical tables |
| Migration complexity | LOW (just views) |
| Function impact | NONE |
| Rollback complexity | LOW |
| Compatibility with Phase 5C2 | LOW — soft gate cannot enforce |
12. Recommendation
Option A — Add 3 nullable/defaulted columns to birth_registry.
Justification:
- Smallest blast radius. 3 ADD COLUMNs, all with PG ≥11 fast-path metadata-only default. No trigger function patch. Rollback is 3 DROP COLUMNs.
- Honors "birth is dumb/fast" (B2/architecture v3 principle): the trigger function is untouched.
- Reuses the existing convention detected in §2.1 (
canonical_address text,jsonbfor profile-style data). - PG-native self-expanding (§8): no allowlist, no per-collection migration. New collections inherit placeholders the moment their first row triggers birth.
- Skips
identity_profilebecause it already lives correctly on physical tables (information_unit, tac_logical_unit) — adding it tobirth_registrywould duplicatejsonb_profilesemantics. ownercolumn onbirth_registryis the resolved owner string — the resolution chain (B2 §3) writes this; sources stay on physical tables (information_unit'sowner_ref, collection_registry'sowner, etc.).jsonb_profileis a generic JSONB catch-all that lets B6 enrichment add keys without DDL — the strongest anti-DDL-creep design.
DDL execution NOT authorized here. Subsequent pack B3-ELD-EXEC will:
- Execute
ALTER TABLE birth_registry ADD COLUMN ...× 3 under standard governance review. - Update B2 contract to rev3 (§7.1).
- Optionally update full-scan to surface NULL rates (§6).
13. Open questions / deferred to execution phase
- Should
birth_registry.canonical_addressbetextorvarchar(255)? Recommendtextto matchinformation_unit. Decide at exec time. - Should
jsonb_profilehave a GIN index? Recommend YES if enrichment writes are frequent; defer to exec when query patterns known. - Should
owneraccept NULL or always default to'UNKNOWN_OWNER'? Recommend NULL pre-enrichment, sentinel'UNKNOWN_OWNER'post-enrichment. Decide at exec time. - Should the existing 6 physical-table
canonical_addresscolumns mirror tobirth_registry? Recommend YES via enrichment pass; not a backfill requirement. - Does B3-F1c-g scheduler repair land before or after B3-ELD-EXEC? Per GPT review, parallel; this design imposes no ordering.
description_policysnapshot on birth? Recommend NO —collection_registry.description_policyis authoritative; reading from there at enrichment time is fine.jsonb_profile.description_policy_snapshotis optional, not required.- Should we add a
eld_enrichment_statuscolumn to track enrichment progress? Possible future addition; design intentionally omitted to keep DDL minimal. Status can be derived from NULL predicates on the 3 columns. - Rollback strategy if Phase 5C2 fails post-DDL? DROP COLUMN works only if no enrichment writes happened. Recommend taking a logical snapshot before B3-ELD-EXEC executes.
- Are there
_historyshadow tables onbirth_registry? Not verified in this design pass. If yes, DDL must propagate.
14. Governance status
b3_eld_design_status=PASS
recommended_option=ADD_BIRTH_REGISTRY_COLUMNS
canonical_address_decision=placeholder_at_birth on birth_registry.text NULL; derived later from physical-table mirror or enrichment
owner_decision=placeholder_at_birth on birth_registry.text NULL; enriched_later via B2 §3 owner-resolution chain
jsonb_profile_decision=required_at_birth on birth_registry.jsonb NOT NULL DEFAULT '{}'; catch-all for hook snapshots and policy mirrors
identity_profile_decision=not_birth_responsibility; remain per-entity-kind on physical tables (information_unit, tac_logical_unit); not added centrally
birth_function_patch_required=false
b2_contract_rev3_required=true
b3f_gate_update_required=false (optional hardening only)
backfill_required=partial (jsonb_profile auto-defaults; owner & canonical_address enriched later in B6, not required before 5C2)
ddl_execution_allowed=false
phase5c2_resume_allowed=false
next_recommended_action=GPT_REVIEW_B3_ELD_DESIGN
secrets_redacted=true
B3-ELD Entity Living DB Placeholder Design | DESIGN ONLY | Opus | 2026-05-14