P3D Pack 1 Phase 3 — Hash, Planner, Compatibility Design
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:
- TAC hash origin: Which trigger/function computes
tac_unit_version.content_hash? Searchtrg_tac_uv_compute_derivedsource and any function it calls. - IU hash origin: Which function computes
unit_version.content_hash? Likely insidefn_iu_create. - Composite hash test:
sha256((body || title || description || coalesce(content_profile::text, ''))::bytea)— does this match TAC? - 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:
- Vocab/config fallback:
law_unitnot in seed vocab → planner falls back todesign_doc_section(the only active seed). - Alias mapping: dot_config has
unit_kind.alias.law_unit → design_doc_section. - Bug: Resolution logic ignores caller input and returns default.
§F. Planner Investigation Plan
Agent must inspect:
- fn_iu_create source: Find the unit_kind resolution logic. What does it do with the
unit_kindparameter? - dot_config keys:
SELECT key, value FROM dot_config WHERE key LIKE '%unit_kind%' OR key LIKE '%kind%'; - Vocab tables: Any table storing allowed unit_kind values?
tac_section_type_vocab? Custom vocab? - 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
- Dispatch investigation prompt → agent discovers hash rule + planner logic
- GPT reviews findings → decides hash policy + planner fix
- Design compatibility view
- Phase 4 = pilot migration (1 doc) with all H1-H10 gates
Phase 3 Design | 2026-05-11 | Opus 4.7