KB-BCB6

P3D Pack 1 Phase 3 — Hash, Planner, Compatibility Design

6 min read Revision 1
p3dpack1phase3hashplannercompatibilitydesign

P3D Pack 1 Phase 3 — Hash, Planner, Compatibility Design

Date: 2026-05-11 | Author: Opus 4.7 | Mode: DESIGN ONLY


§A. Phase 2 Accepted State

10 columns added (3 IU + 7 UV), all NULL, no defaults/FK/index/trigger. Gateway enforced. Rows unchanged (12 IU, 19 UV). Two blockers discovered.

§B. Hash Divergence Problem

IU content_hash = sha256(body::bytea) (confirmed 5/5 match). TAC content_hash = 64-char hex but ≠ md5(body) AND ≠ sha256(body::bytea). 86/86 mismatch.

Hypothesis: P5 design §5.2 specifies "content_hash bao gồm body + title + description + content_profile". TAC may hash a composite payload (body+title+description+profile) while IU hashes body alone.

§C. Hash Investigation Plan

Agent must inspect:

  1. TAC hash origin: Which trigger/function computes tac_unit_version.content_hash? Search trg_tac_uv_compute_derived source and any function it calls.
  2. IU hash origin: Which function computes unit_version.content_hash? Likely inside fn_iu_create.
  3. Composite hash test: sha256((body || title || description || coalesce(content_profile::text, ''))::bytea) — does this match TAC?
  4. Normalization test: sha256(trim(body)::bytea), sha256(regexp_replace(body, '\s+', ' ', 'g')::bytea) — normalized variants.

§D. Hash Migration Policy Options

Option Description Pro Con
D1: Recompute under IU rule After migration, compute sha256(body::bytea) for all rows Uniform hash across all IU rows Breaks link to TAC hash history; drift check vs TAC originals becomes two-step
D2: Preserve TAC hash Copy TAC content_hash as-is into IU rows Preserves audit trail IU will have mixed hash rules; drift detection inconsistent
D3: Dual hash Store content_hash (IU rule) + source_hash (original TAC) Best of both; can verify against either Extra column; complexity
D4: Normalize both Align both sides to same composite hash rule True unification Requires backfill ALL existing IU rows + change fn_iu_create

Preliminary recommendation: D3 (dual hash) — safest, reversible, no existing data mutation. Final decision after investigation confirms TAC hash rule.

§E. Planner unit_kind Resolution Problem

fn_iu_create_plan('...', 'law_unit', ...) returned resolved_unit_kind=design_doc_section. Possible causes:

  1. Vocab/config fallback: law_unit not in seed vocab → planner falls back to design_doc_section (the only active seed).
  2. Alias mapping: dot_config has unit_kind.alias.law_unit → design_doc_section.
  3. Bug: Resolution logic ignores caller input and returns default.

§F. Planner Investigation Plan

Agent must inspect:

  1. fn_iu_create source: Find the unit_kind resolution logic. What does it do with the unit_kind parameter?
  2. dot_config keys: SELECT key, value FROM dot_config WHERE key LIKE '%unit_kind%' OR key LIKE '%kind%';
  3. Vocab tables: Any table storing allowed unit_kind values? tac_section_type_vocab? Custom vocab?
  4. fn_iu_create_plan helper functions: Does it call a resolver function?

§G. Compatibility/Read-Side Design

After EVOLVE migration (Phase 4+), TAC reader pipeline (/knowledge/laws) must still work. Options:

Option Description
G1: View Create v_tac_logical_unit as SELECT from information_unit WHERE unit_kind='law_unit' with column aliases
G2: Adapt CTE Modify Nuxt reader CTE to query information_unit directly with WHERE clause
G3: Both View for backward compat + adapted CTE for new code

Preliminary recommendation: G1 (view) for Phase 4, G2 for eventual Nuxt cleanup in Pack 8.

Publication membership: tac_publication_member FK points to tac_logical_unit.id. After migration, same UUIDs in information_unit.id → FK still valid IF we preserve UUIDs.

§H. Phase 4 Migration Gates

Before moving 86 TAC rows, ALL must be true:

# Gate Verification
H1 TAC hash algorithm identified Investigation report
H2 Hash migration policy decided (D1/D2/D3/D4) GPT approve
H3 law_unit resolves correctly in planner Fix confirmed OR migration bypasses planner
H4 Compatibility view designed Design approved
H5 Pilot migration (1 doc, ~27-36 rows) succeeds Pilot report
H6 Round-trip 0 drift after pilot Same method P10A/P10B
H7 Publication membership preserved render_order intact
H8 Gateway protects migrated rows Test INSERT blocked without marker
H9 Birth registry fires for migrated rows Birth record exists
H10 Rollback tested (pilot revert) Clean revert, no orphans

§I. Risks and Rollback

Risk Mitigation
TAC hash rule is complex/undocumented Investigation prompt covers 4+ hypothesis tests
Planner issue blocks migration Can bypass planner for migration (direct INSERT with gateway marker)
View doesn't cover all TAC reader queries Verify TAC CTE against view output
Migration creates orphan publication_member Preserve UUIDs; FK still valid

Rollback model: Phase 3 is read-only → no rollback needed. Phase 4 migration rollback = DELETE migrated IU rows + verify TAC rows untouched.

§J. Recommendation

  1. Dispatch investigation prompt → agent discovers hash rule + planner logic
  2. GPT reviews findings → decides hash policy + planner fix
  3. Design compatibility view
  4. Phase 4 = pilot migration (1 doc) with all H1-H10 gates

Phase 3 Design | 2026-05-11 | Opus 4.7

Back to Knowledge Hub knowledge/dev/laws/dieu44-trien-khai/design/p3d-pack1-phase3-hash-planner-compatibility-design.md