KB-5D9C

P3D Pack 1 Phase 3 — Hash Planner Birth Alignment Investigation Report

14 min read Revision 1
p3dpack1phase3investigationreportreadonlyhashplannerbirthspeciescomposition2026-05-11

P3D Pack 1 Phase 3 — Hash Planner Birth Alignment Investigation Report

Date: 2026-05-11 Executor: Claude Opus 4.7 (1M) agent Mode: READ-ONLY INVESTIGATION (SET default_transaction_read_only=on confirmed) Source prompt: knowledge/dev/laws/dieu44-trien-khai/prompts/p3d-pack1-phase3-readonly-hash-planner-investigation-prompt.md (rev3) VPS: 38.242.240.89, container=postgres, db=directus Log: /tmp/p3d-phase3-investigation-20260511-062254.log (on VPS)

Final response

phase_status=BLOCKED
mode=READ_ONLY_INVESTIGATION
no_mutation_performed=true
sha256_available=true
hash_algorithm_tac=discovered
hash_algorithm_tac_details=encode(sha256(convert_to(coalesce(title,'') || '|' || coalesce(body,'') || '|' || coalesce(description,'') || '|' || coalesce(content_profile::text,'{}'),'UTF8')),'hex') — composite pipe-delimited, computed by fn_tac_uv_compute_derived BEFORE INSERT/UPDATE on tac_unit_version. Confirmed match on 10/10 sampled rows.
hash_algorithm_iu=sha256_body
hash_match_hypothesis=IU=sha256(body::UTF8) via fn_content_hash; TAC=sha256(title|body|description|content_profile_or_{}::UTF8) via fn_tac_uv_compute_derived. Both 64-char hex SHA-256 but inputs differ — migration MUST recompute.
planner_unit_kind_resolution=fn_iu_create_plan(p_unit_kind:='law_unit') returns status='unresolved_vocab', would_create=false, issue 'unit_kind: Not in vocab. Available: design_doc_section'. Phase-2 'design_doc_section' was an artifact of positional arg shift (Phase-2 passed 'law_unit' as p_title, leaving p_unit_kind=NULL → auto_single to the only vocab entry).
law_unit_status=missing  (vocab.unit_kind only has design_doc_section; no vocab.unit_kind.law_unit row in dot_config)
species_at_birth=absent  (species_collection_map has 0 rows for information_unit; fn_birth_registry_auto registers IU with species_code=NULL, composition_level=NULL — verified on all 12 rows)
composition_at_birth=absent  (identity_profile has only {title, owner_lookup_ref, primary_section_type_ref} — composition_role never set; universal_edges contains 0 rows for information_unit/unit_version)
parent_child_enforcement=stored_only  (information_unit.parent_or_container_ref column exists but is NULL on all 12 rows; no birth-gate enforcement; no edge materialization)
DOT_enrichment_for_IU=registered_only  (collection_registry.governance_role='observed', migration_state='pilot', species_code=NULL; entity_labels has 0 labels for IU/UV; no enrichment fields populated)
birth_registry_for_IU=partial  (12/12 IU rows registered; species_code/composition_level NULL because species_collection_map empty for IU)
vocab_tables_found=tac_section_type_vocab(17), tac_uv_lifecycle_vocab(4), tac_lu_lifecycle_vocab(3), tac_review_state_vocab(5), tac_publication_type_vocab(10), tac_pub_lifecycle_vocab(4), tac_cs_lifecycle_vocab(7); IU vocab via dot_config: vocab.unit_kind.{design_doc_section}, vocab.section_type.{section}, vocab.publication_type.{design_doc}
source_objects_inspected=fn_content_hash, fn_tac_uv_compute_derived, fn_iu_gateway_write_guard, fn_tac_birth_gate_uv, fn_iu_notif_version, fn_iu_create, fn_iu_create_plan, fn_iu_create_preflight, fn_iu_resolve_default, fn_iu_classify_existing, fn_iu_verify_invariants, fn_iu_birth_gate_layer1, fn_iu_birth_gate_layer2, fn_birth_registry_auto, fn_iu_apply_edit_draft, fn_iu_create_edit_draft; tables: information_unit, unit_version, tac_unit_version, tac_logical_unit, dot_config, birth_registry, collection_registry, species_collection_map, entity_species, entity_labels, label_rules, universal_edges, all tac_*_vocab
next_recommended_action=Stay BLOCKED on TAC→IU migration. Before Phase 4 propose: (a) seed dot_config vocab.unit_kind.law_unit + missing section_types from tac_section_type_vocab; (b) seed species_collection_map for information_unit & unit_version (or accept species_code=NULL post-migration); (c) decide composition_role + parent_or_container_ref strategy for nested TAC structure (logical_unit hierarchy) and whether to materialize universal_edges; (d) define hash reconciliation policy — recompute on migrate (preferred) vs preserve (requires schema change to store both); (e) elevate collection_registry.governance_role for IU from 'observed' to 'governed' if migration is to be authoritative.
log_path=/tmp/p3d-phase3-investigation-20260511-062254.log

Critical blocker notes

  1. HASH RECONCILIATION required — TAC and IU hash schemes are both SHA-256/UTF-8/hex but with materially different inputs (composite pipe-delimited vs body-only). A naive TAC→IU body copy will produce a content_hash that does NOT match the TAC source row's content_hash. Migration policy must explicitly choose: recompute (lose hash continuity), or store TAC-hash separately.

  2. VOCAB is the planner blocker, not a planner bug — Opus's claim that the planner "silently resolves law_unit → design_doc_section" was a false positive caused by misreading fn_iu_create_plan's positional signature in the Phase-2 verification call. The planner correctly rejects law_unit as unresolved_vocab. The actual blocker is the empty IU vocab (1 unit_kind, 1 section_type, 1 publication_type vs TAC's 17 section types and 10 publication types).

  3. Native IU birth is Tier-0 onlyfn_iu_birth_gate_layer1 enforces only canonical_address, unit_kind∈vocab, lifecycle_status, owner_ref, conformance_status, and 3 identity_profile keys (title, owner_lookup_ref, primary_section_type_ref∈vocab). pub_authority/pub_type are WARN-only (PILOT). fn_iu_birth_gate_layer2 enforces only anchor consistency. fn_iu_verify_invariants has 5 invariants (i1..i5: IU exists, UV linked, anchors exact, birth_registry row, UV not double-registered). NO species, composition, parent, edge, or label invariants exist at birth.

  4. species/composition pipeline NOT wired for IUspecies_collection_map is empty for information_unit and unit_version. As a result, all 12 IU rows present in birth_registry have species_code=NULL, composition_level=NULL. entity_labels has 0 entries for IU/UV. universal_edges (2199 rows) has 0 IU/UV rows. The semantic-object contract that DOT-119 / downstream enrichment expects is not yet realized for IU.

  5. TAC is fully outside the birth_registry universe — tac_logical_unit, tac_unit_version, tac_publication have 0 rows in birth_registry, collection_registry, species_collection_map. TAC tables carry only trg_tac_birth_gate_* and trg_tac_uv_compute_derived triggers; no fn_birth_registry_auto trigger. Migrating TAC content into IU therefore cannot be a transparent rebadge — it requires explicit registration into the species/composition/label pipeline (or an explicit decision to defer that registration).

  6. collection_registry IU/UV state is "pilot"migration_state='pilot', governance_role='observed' (not governed), description_policy='structured_exempt', species_code=NULL. The IU collection itself has not yet been promoted to a governed, fully-classified collection.

Evidence summary

Phase-2 schema context (C0)

  • information_unit: 12 rows; new columns doc_code, section_type, section_code present, all NULLable, no defaults.
  • unit_version: 19 rows; new columns title, description, review_state, provenance, editor, enacted_at, updated_at present, all NULLable.
  • tac_unit_version: 86 rows.
  • Counts identical to Phase 2 report — no row drift.

Hash algorithms (A1–A5)

Probe Result
sha256 availability ba9c736f… (works)
TAC hash recipe match (10/10 rows) sha256(title | body | description | content_profile_or_{} :: UTF8) matches content_hash
TAC body-only / md5 does NOT match
IU match sha256(body :: UTF8) (10/10) matches
IU match fn_content_hash(body) (10/10) matches
IU md5 does NOT match

Function source confirms:

  • public.fn_content_hash(p_body text) → encode(digest(p_body,'sha256'),'hex') IMMUTABLE.
  • fn_tac_uv_compute_derived trigger sets NEW.content_hash := encode(sha256(convert_to(coalesce(NEW.title,'')||'|'||coalesce(NEW.body,'')||'|'||coalesce(NEW.description,'')||'|'||coalesce(NEW.content_profile::text,'{}'),'UTF8')),'hex').

Planner / vocab (B1–B5)

dot_config vocab keys present:

vocab.publication_type.design_doc        = design_doc
vocab.section_type.section               = section
vocab.unit_kind.design_doc_section       = design_doc_section

No vocab.unit_kind.law_unit. No iu_create.default_unit_kind/default_section_type keys (so fn_iu_resolve_default falls into auto_single because each vocab has exactly one entry).

Planner probes (named args):

input p_unit_kind status resolved_unit_kind would_create
law_unit unresolved_vocab law_unit (echoed input) false
design_doc_section plan_ok design_doc_section true
unknown_kind unresolved_vocab unknown_kind false
(NULL) plan_ok design_doc_section (auto_single) true

Birth gates / invariants (B2–B2c)

fn_iu_create (canonical writer): inserts IU with identity_profile = {title, owner_lookup_ref, primary_section_type_ref [, publication_type_ref]}, then UV with seq=1, then sets anchors, then calls fn_iu_verify_invariants and rolls back on failure.

fn_iu_birth_gate_layer1 (BEFORE INSERT): requires canonical_address, unit_kind∈vocab, lifecycle_status, owner_ref, conformance_status, identity_profile.title, identity_profile.owner_lookup_ref, identity_profile.primary_section_type_ref∈vocab. publication_authority_ref/publication_type_ref are WARN-only (PILOT-ONLY). NO species, composition, parent, edge checks.

fn_iu_birth_gate_layer2 (AFTER INSERT, constraint trigger, deferred): asserts content_anchor_ref non-empty, version_anchor_ref points to a UV of this IU, content_anchor_ref text equals version_anchor_ref::text. NOTHING about species/composition.

fn_iu_verify_invariants: i1_iu_exists, i2_uv_linked, i3_anchors_exact, i4_birth_exists (birth_registry row for information_unit::<id> exists), i5_uv_birth_ok (UV not separately birth-registered when uv strategy='subordinate').

Birth registry / species / labels / edges (D1–D6)

  • identity_profile keys distribution across 12 IU rows: {title:12, owner_lookup_ref:12, primary_section_type_ref:12}. No composition_role, no species.
  • All 12 IU rows: unit_kind=design_doc_section, lifecycle_status=draft, parent_or_container_ref=NULL.
  • universal_edges: 2199 rows total; 0 referencing information_unit or unit_version.
  • birth_registry for information_unit: 12 rows, all with species_code=NULL, composition_level=NULL, governance_role=observed, certified=false, dot_origin='PG:trg_birth_information_unit', status=born.
  • birth_registry for unit_version: 0 rows (UV is subordinate per collection_registry).
  • birth_registry for tac_logical_unit / tac_unit_version / tac_publication: 0 / 0 / 0.
  • species_collection_map: 153 rows total; 0 for information_unit, unit_version, or any tac_*.
  • entity_labels: 91544 rows total; 0 for entity_code starting with information_unit:: or unit_version::.
  • entity_species: 40 rows.
  • collection_registry for information_unit: COL-176, governance_role=observed, source_kind=native, species_code=NULL, birth_code_strategy=synthetic_id, description_policy=structured_exempt, storage_role=primary, migration_state=pilot.
  • collection_registry for unit_version: COL-177, same except birth_code_strategy=subordinate.
  • collection_registry for any tac_*: 0 rows.

Triggers on IU/TAC tables (D6)

  • information_unit: trg_aa_iu_gateway_write_guard (BEFORE INS/UPD), trg_birth_information_unit (fn_birth_registry_auto), trg_iu_birth_gate_layer1 (BEFORE INS), trg_iu_birth_gate_layer2 (AFTER INS, constraint, deferrable), trg_iu_updated_at.
  • unit_version: trg_aa_iu_notif_version (AFTER INS), trg_aa_uv_gateway_write_guard (BEFORE INS/UPD).
  • tac_unit_version: trg_tac_birth_gate_uv, trg_tac_enacted_immut, trg_tac_uv_compute_derived. NO fn_birth_registry_auto.
  • tac_logical_unit: trg_tac_birth_gate_lu. NO fn_birth_registry_auto.
  • tac_publication_member: trg_tac_pm_consistency, trg_tac_pm_enacted_lock. NO fn_birth_registry_auto.

Migration recommendation

Migration should remain BLOCKED. Phase 4 must NOT begin TAC→IU body migration until at minimum:

  1. Hash reconciliation policy decided (recompute vs preserve).
  2. IU vocab seeded for the unit_kind / section_type / publication_type values that the 86 TAC rows actually use (verify against tac_logical_unit.section_type and tac_publication.publication_type distinct values before seeding).
  3. Decision documented on whether species/composition/labels/edges will be (a) enforced at IU birth post-migration, (b) populated by a backfill, or (c) explicitly deferred — and the relevant species_collection_map / label_rules / edge-materialization triggers prepared accordingly.
  4. collection_registry.governance_role for information_unit either remains observed (with explicit statement that IU stays pilot post-migration) or is promoted to governed (in which case missing species_code, missing labels, and birth-gate Tier-0-only become governance gaps that must be closed first).
Back to Knowledge Hub knowledge/dev/laws/dieu44-trien-khai/reports/p3d-pack1-phase3-hash-planner-birth-alignment-investigation-report.md