Phase 3 — Carry-forward + next-phase recommendations
Phase 3 — Carry-forward + next-phase recommendations
Cleared by this pilot
- Pre-Phase-3 ambiguity around the write channel (HARD GATE 0 now proven).
- First durable Điều 37 MARK + CUT (17 IUs) via the queue substrate. Reconstruct by source_ref returns 17.
- First demonstration that
job_queuecan drive a real MARK/CUT workflow end-to-end with all gates safe at exit. - D30/D31 protections honored under live MARK + CUT (not just BEGIN/ROLLBACK proofs).
Not closed by this pilot — explicit carry-forward
CF1 — fn_iu_create internal vocab is narrower than tac_section_type_vocab
fn_iu_create enforces a hardcoded 13-item section_type list:
appendix, article, changelog, checklist, definition, governance_process, heading,
instruction_block, paragraph, principle, process, section, technical_spec
tac_section_type_vocab (live, lifecycle_status='active') has 17 codes — the four extra
codes invariant_list, matrix, open_decision_list, rationale, reference_mapping are
not accepted by fn_iu_create.
The pilot worked around the gap by mapping matrix → technical_spec, reference_mapping → section,
open_decision_list → section on the fly. This is fine for a single law but distorts axis B
(section_type no longer carries the most precise vocab).
Next-phase decision needed:
- Option A: widen
fn_iu_createinternal list to mirrortac_section_type_vocab. Low risk; preserves authoring intent. - Option B: deprecate the 4 extra codes in
tac_section_type_vocab(setlifecycle_status='deprecated'). Lower-risk operationally but loses semantic granularity. - Option C: keep both; document
fn_iu_createas the source of truth and add a CHECK attac_section_type_vocabinsert time.
Default recommendation: Option A — widen fn_iu_create to 17 codes in the next migration
pack. This also lets us re-cut Điều 37 with the precise codes for §7 (matrix),
§9 (reference_mapping), §11 (open_decision_list) — currently those carry the less precise
codes.
CF2 — iu_outbound_default legacy stale executor (Điều 45 §15.5)
queue_heartbeat.iu_outbound_default.last_tick_at = 2026-05-22 11:31:41+00. Age now > 4 days.
The pilot surfaces the gap (fn_queue_stale_check returns it; v_queue_health.executors_stale=1)
but does not close it durably. Phase 2 already chose to leave this as a Phase 3 task.
Next-phase decision needed: wire a real heartbeat caller. Two options carry-forward from Phase 2 doc 08:
- Option A (preferred, low-risk): external operator/Hermes pings
fn_queue_heartbeat_tick( 'iu_outbound_default','PG_worker','ok',…)on eachiu_outboundpoll. Updates a real liveness signal. - Option B (higher-fidelity, higher-risk): modify
fn_iu_route_worker_runto tick heartbeat inside. Couples worker code to heartbeat surface.
CF3 — Codex's earlier 06a2fc30 pending_review staging
A staging row created at 2026-05-26 04:06:19+00 by codex-gpt5-20260526 is still
lifecycle_status='pending_review' with idempotency_key='op-mark-dieu37-full-v3.3-20260526-mark-only'.
Its manifest pieces use the older 13-code intent but with several invalid piece_role values
(root, context) and invalid section_type values (title, note, summary, workflow,
reference, roadmap, verification). It cannot be cut as-is.
Next-phase decision needed:
- Option A: reject (
lifecycle_status='rejected') via averify_mark(approve=false)follow-up. - Option B: patch its
cut_manifestpayload to the same valid vocab the pilot used, then approve + cut. But this would create a second durable Điều 37 cut, duplicating the 17 IUs already produced by258c715c…/a64340fe….
Default recommendation: Option A — reject the older staging.
CF4 — fn_iu_create Birth-gate L1 warnings (P-pub1 / P-pub2)
The cut emitted ~60 warnings:
WARNING: Birth gate L1 PILOT-ONLY: P-pub1 missing — production sẽ BLOCK
WARNING: Birth gate L1 PILOT-ONLY: P-pub2 missing — production sẽ BLOCK
These are Điều 0-G publication-gate placeholders. Non-blocking in pilot mode. Production
mode would BLOCK. Wiring real P-pub1/P-pub2 publication is an Điều 0-G item, not a Phase 3
prerequisite.
CF5 — Substrate gate flip semantics
The pilot temporarily flipped queue.job_substrate.enabled from false → true → false. This
is correct for a one-shot pilot but isn't a sustainable pattern. The next migration should
either:
- decide a durable on-policy for
queue.job_substrate.enabled, or - introduce a "pilot scope" mechanism that does not need to flip the global gate (e.g. per-actor allowlist).
CF6 — iu_piece_membership empty for the cut output
The 17 DIEU-37 IUs created via this cut have 0 rows in iu_piece_membership. Children are
linked to the title piece by information_unit.parent_or_container_ref (axis C verified).
Other historical cuts in the database (223 existing rows) carry iu_piece_membership rows
with a collection_id. Whether MARK→CUT should populate iu_piece_membership is a design
question.
Default recommendation: confirm with Council that parent_or_container_ref-only linking is
the correct shape for law cuts (no collection context), and that iu_piece_membership is
reserved for collection memberships (a different semantic level).
Suggested next pack name
DIEU45_PHASE_3B_FN_IU_CREATE_VOCAB_WIDEN_AND_HEARTBEAT_CALLER — bundles CF1 (vocab widen) +
CF2 (real heartbeat caller for iu_outbound_default). Both are migration-shaped and low risk.
Phase 4+ then proceeds with:
- Lease reaper enabled (real, not dry-run).
- DLQ replay enabled (with apply path).
- Worker daemon wiring.
Or, depending on Council priority, return to MOT / customer / email runtime — those remain deferred per Điều 45 v1.0 §13 design-seam.