P3D Phase 5C2-R2 — DIEU-32 Retry (Synthesize-Title Policy) Execution Report (PASS)
P3D Phase 5C2-R2 — DIEU-32 Retry (Synthesize-Title Policy) Execution Report
Date (UTC): 2026-05-14T14:46:44Z Author: Claude Opus 4.7 (1M, xhigh) — orchestrator on VPS Authorization:
USER_GO=YES,GPT_FINAL_APPROVAL=YES,DIEU32_SYNTHESIZE_TITLE_POLICY_APPROVED=YES,DIEU32_RETRY_AUTHORIZED=YESControlling prompt:knowledge/dev/laws/dieu44-trien-khai/prompts/agent-phase5c2-dieu32-retry-synthesize-title-policy-2026-05-14.mdOutcome: PASS — 23/23 IU + 23/23 UV + 23/23 birth committed; 19 rows preserved verbatim, 4 rows synthesized from title underPOLICY_SYNTHESIZE_TITLE_FOR_HEADING_NULL_BODY; conditional V-3b' fully verified; V-8..V-10 all PASS; TAC source unchanged; pre-existing 75 IU rows untouched.
0. Hard boundaries — all honored
| Boundary | Honored |
|---|---|
| No DDL / schema / trigger / fn / birth-system changes | ✅ |
No direct INSERT to IU/UV (used fn_iu_create only) |
✅ |
| No TAC writes (V-6 PASS: 3/86/86/86 unchanged) | ✅ |
| No UI / Nuxt / Directus / config / vector / event_outbox work | ✅ |
| Pre-existing 75 IU untouched (V-9 PASS) | ✅ |
| No publications beyond DIEU-32 | ✅ |
| No pattern-matching DELETE | ✅ (no rollback needed; transactional COMMIT) |
| No automatic content repair beyond approved heading-title synthesis | ✅ (only the 4 approved rows used title; non-heading NULL bodies would have aborted) |
1. Stage A — Preflight (PASS)
doc_code=DIEU-32
publication_id=6e08315c-7c70-470a-8a6a-32d7e2ae1b94
publication_version=v1.1
publication_lifecycle=proposed
publication_type=law
member_count=23
render_order: min=0 max=22 distinct=23 count=23 contiguous=true
owner_null_count=0
body_null_count=4
null_body_addrs=[D38-DIEU32-ROOT, D38-DIEU32-S2, D38-DIEU32-S3, D38-DIEU32-S4] <-- exactly the 4 approved synthesize rows
approved_synth_addrs={D38-DIEU32-ROOT, D38-DIEU32-S2, D38-DIEU32-S3, D38-DIEU32-S4}
collision_count=0
section_types_missing_vocab=<none>
pre_iu_count=75 / pre_uv_count=82 / pre_br_iu=75
pre_tac counts: pub=3 lu=86 uv=86 pm=86
gateway_mode=enforced / allowed_markers=fn_iu_create,fn_iu_apply_edit_draft / edit_policy=require_review
fn_iu_create signature OK (9-arg → jsonb)
species_collection_map primary IU: information_unit_atom|information_unit|primary=true
birth_trigger_present=true
All hard preflight gates PASS. The 4 NULL-body rows match exactly the approved synthesize set, and all satisfy section_type='heading' AND children > 0. No source drift since the root-cause investigation.
2. Stage B — Bounded transaction (23 fn_iu_create + per-row conditional patch)
Single BEGIN … COMMIT over one psql session via docker exec -i postgres psql -U directus -d directus -q -A -t -F '|' -v ON_ERROR_STOP=1. Wall-clock for DO block: ~0.6s.
Per-row pattern with conditional body preparation:
IF section_type='heading' AND body IS NULL AND children>0 THEN
iu_body := source.title
body_source := 'synthesized_from_title_due_to_tac_heading_null_body'
src_body_was_null := true
ELSIF body IS NULL THEN
RAISE EXCEPTION 'BLOCKED: non-heading-container NULL body' -- would abort tx
ELSE
iu_body := source.body
body_source := 'preserved_from_tac_unit_version_body'
src_body_was_null := false
ENDIF
Then fn_iu_create(...) (with iu_body, p_actor='agent:p3d-phase5c2-dieu32-retry', p_unit_kind='law_unit', p_publication_type='law', p_parent_ref=NULL), then SET LOCAL "app.canonical_writer" = 'fn_iu_apply_edit_draft' + UPDATE information_unit with identity_profile patch (including body_source + 10-key TAC provenance + hierarchy + authority + rendering), then UPDATE unit_version with content_profile patch (including body_source, src_body_was_null, src_title, src_content_hash, etc.) + provenance='tac:DIEU-32:<src_uv_id>'.
2.1 Per-row classification (captured)
Synthesized (4 rows — body = source.title):
| ro | canonical_address | src section_type | children | iu.body |
|---|---|---|---|---|
| 0 | D38-DIEU32-ROOT |
heading | 10 | ĐIỀU 32: LUẬT PHÊ DUYỆT — v1.1 BAN HÀNH (= source title) |
| 3 | D38-DIEU32-S2 |
heading | 4 | §2. Nguyên tắc (= source title) |
| 8 | D38-DIEU32-S3 |
heading | 5 | §3. Schema approval (= source title) |
| 14 | D38-DIEU32-S4 |
heading | 3 | §4. Quorum approvals (= source title) |
Preserved (19 rows — body = source.body byte-equal): ro=1 (S0/Preamble), ro=2 (S1), ro=4..7 (S2-P1..P4), ro=9..13 (S3-P1..P5), ro=15..17 (S4-P1..P3), ro=18 (S5), ro=19 (S6), ro=20 (S7), ro=21 (S8), ro=22 (S9).
synthesized_rows_count = 4, preserved_rows_count = 19, loop_count = 23.
3. Stage C — Rollback-key dual-write BEFORE COMMIT (PASS)
| Target | Path | Result |
|---|---|---|
| VPS log | /opt/incomex/logs/p3d-phase5c2-dieu32-20260514T144644Z.log |
OK (sync issued; rollback bundle wrapped ###ROLLBACK_KEYS_BEGIN###/###ROLLBACK_KEYS_END###) |
| KB | knowledge/dev/laws/dieu44-trien-khai/reports/p3d-phase5c2-dieu32-rollback-keys-20260514T144644Z.md |
HTTP 200 / status=created / revision 1 |
The KB rollback doc captures all 23 IU+UV+entity-code UUIDs plus the 4 synthesized vs 19 preserved address lists plus the exact-key rollback SQL skeleton.
4. Stage D — V-1..V-7 with conditional V-3b' (all PASS)
| Gate | Spec | Live result | Verdict |
|---|---|---|---|
| V-1 | captured_iu=captured_uv=source_count=23 | 23/23/23 | PASS |
| V-2 | identity_profile render_order multiset = source multiset = {0..22} | captured=0..22; source=0..22 |
PASS |
| V-3a | per UV content_hash = fn_content_hash(body) |
23/23 | PASS |
| V-3b' (preserved) | body_source='preserved_…' ⇒ uv.body = tac_unit_version.body byte-eq |
19/19 byte-equal · 19/19 marked preserved | PASS |
| V-3b' (synthesized) | body_source='synthesized_…' ⇒ uv.body = tuv.title AND tuv.body IS NULL AND tlu.section_type='heading' AND children>0 AND src_body_was_null=true AND src_title=tuv.title |
4/4 satisfy ALL conditions · 4/4 marked synthesized | PASS |
| V-3b' (identity_profile ↔ content_profile match) | identity_profile.body_source = content_profile.body_source for every captured IU |
23/23 | PASS |
| V-3c | content_profile.src_content_hash = tac_unit_version.content_hash (TAC hash provenance) |
23/23 | PASS |
| V-3d (REPORT ONLY) | cross-system hash equality uv.content_hash = tuv.content_hash |
0/23 (expected legacy divergence) | NOT A GATE |
| V-4 | all 23 IU identity_profile.publication_authority_ref = 'incomex_council' |
23/23 | PASS |
| V-5 | 23 birth rows; 0 NULL species; all information_unit_atom / atom |
23 / 0 / 23 / 23 | PASS |
| V-6 | TAC counts unchanged (3/86/86/86) | unchanged | PASS |
| V-7 | fn_iu_verify_invariants all_pass=true per address |
23/23 | PASS |
→ All required gates PASS. COMMIT; issued.
4.1 Note on the validate-SQL fix
A first attempt of this retry hit a SQL error in the validate file (tlu.title referenced; tac_logical_unit has no title column — title lives on tac_unit_version). The migration DO block already used tuv.title correctly via the join alias. The validation file was repaired in-place (one-line fix: tlu.title → tuv.title, two occurrences), then re-run. The first attempt's transaction was aborted automatically when psql exited under ON_ERROR_STOP=1; no data was committed and the DB returned to the pre-retry baseline (75/82/75) — verified before this re-run. The earlier rollback-keys KB doc from the aborted attempt (…rollback-keys-20260514T144335Z.md) is preserved as historical evidence of dual-write working before the validation error.
5. Stage E — Post-COMMIT V-8..V-10 + final counts (all PASS)
| Probe | Result | Verdict |
|---|---|---|
V-8 trg_aa_iu_gateway_write_guard + trg_aa_uv_gateway_write_guard attached; marker clean in fresh session |
true / true / true | PASS |
| V-9 pre-existing 75 IU IDs all present post-COMMIT | 75 / 75 | PASS |
| V-10 KB rollback doc fetchable + VPS log present | true / true | PASS |
Final information_unit count |
98 (= 75 pre + 23 new) | OK |
Final unit_version count |
105 (= 82 pre + 23 new) | OK |
Final birth_registry[information_unit] count |
98 (= 75 pre + 23 new) | OK |
| TAC counts unchanged | pub=3 lu=86 uv=86 pm=86 | OK |
| UI cutover / vector / bulk | false / false / false | OK |
6. Policy extracted for dot-iu-cutter v0.1
The synthesize-title rule applied here is the first governed policy that the future Cắt luật A automated cutter must implement out-of-the-box. Specification for v0.1:
6.1 Body-source classification (per row, deterministic)
classify(source_row) -> body_source:
IF source_row.section_type = 'heading'
AND source_row.body IS NULL
AND source_row.children_count > 0 THEN
-> SYNTHESIZE_TITLE
ELSIF source_row.body IS NULL THEN
-> BLOCK ('hard error; not a container heading')
ELSE
-> PRESERVE
6.2 Body preparation
prepare_body(source_row, body_source):
CASE body_source:
SYNTHESIZE_TITLE -> body := source_row.title
provenance.body_source := 'synthesized_from_title_due_to_tac_heading_null_body'
provenance.src_body_was_null := true
provenance.src_title := source_row.title
PRESERVE -> body := source_row.body
provenance.body_source := 'preserved_from_tac_unit_version_body'
provenance.src_body_was_null := false
Both body_source and provenance fields land on:
information_unit.identity_profile(for IU-side discovery/UI use)unit_version.content_profile(for UV-level integrity / migration audit)
They must match between the two locations for every row (verified by V-3b_ip_cp_body_source_match).
6.3 Conditional V-3b' (the cutter's contract)
for every captured UV uv joined to source tuv (via content_profile.src_unit_version_id) and tlu (via tuv.logical_unit_id):
IF uv.content_profile.body_source = 'preserved_from_tac_unit_version_body' THEN
require uv.body = tuv.body -- byte-equality
ELSIF uv.content_profile.body_source = 'synthesized_from_title_due_to_tac_heading_null_body' THEN
require uv.body = tuv.title -- synthesized body equals source title
require tuv.body IS NULL -- source body confirmed null
require tlu.section_type = 'heading' -- source is heading
require (count children of tlu) > 0 -- source is container
require uv.content_profile.src_body_was_null = true
require uv.content_profile.src_title = tuv.title
ELSE
FAIL — unknown body_source policy
Plus the unconditional integrity gates V-3a (uv.content_hash = fn_content_hash(uv.body) for all rows) and V-3c (uv.content_profile.src_content_hash = tuv.content_hash for all rows). V-3d remains report-only.
6.4 Cutter risk profile
| Risk | Status |
|---|---|
| Hardcode risk | None — rule is parameterless, applies live section_type/children/body |
| Scale risk | None — 4 rows out of 23 in DIEU-32; rule is per-row and stateless |
| Cross-publication compatibility | Verified: D28 headings use '' (no synthesize), D32 headings use NULL (synthesize), D35 has no container heading |
| Reverse migration risk | LOW — synthesized rows are explicitly tagged in body_source; reverse process can detect and restore original body IS NULL state |
| Race / re-run idempotency | Handled by fn_iu_create's canonical_address-keyed idempotent status (exists_complete on re-run) |
| Source defect detection | Maintained — any NULL body that is NOT a heading-container still raises an error (per the BLOCK branch in classify) |
7. Required final response fields
dieu32_retry_status=PASS
synthesize_title_policy_used=true
source_count_live=23
created_iu_count=23
created_uv_count=23
created_birth_count=23
synthesized_rows_count=4
preserved_rows_count=19
synthesized_rows=[D38-DIEU32-ROOT,D38-DIEU32-S2,D38-DIEU32-S3,D38-DIEU32-S4]
pre_existing_iu_untouched=true
tac_source_untouched=true
v3b_conditional_policy_pass=true
birth_coverage_pass=true
gateway_integrity_pass=true
ui_cutover_performed=false
vector_work_performed=false
bulk_migration_performed=false
rollback_keys_report_path=knowledge/dev/laws/dieu44-trien-khai/reports/p3d-phase5c2-dieu32-rollback-keys-20260514T144644Z.md
execution_report_path=knowledge/dev/laws/dieu44-trien-khai/reports/p3d-phase5c2-r2-dieu32-retry-synthesize-title-execution-report.md
completion_report_path=knowledge/dev/laws/dieu44-trien-khai/reports/p3d-phase5c2-86-units-completion-report.md
next_recommended_action=GPT_REVIEW_DIEU32_RETRY_THEN_START_DOT_IU_CUTTER_DESIGN
P3D Phase 5C2-R2 DIEU-32 Retry | 2026-05-14T14:46:44Z | PASS | Synthesize-title policy applied to 4 heading-container rows | 23/23 committed | Conditional V-3b' verified