KB-7CF6

Phase 3 — Carry-forward + next-phase recommendations

6 min read Revision 1
dieu45phase3carry-forwardnext-phaseopen-questionsfn-iu-create-vocabsilent-gap06a2fc302026-05-26

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_queue can 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_create internal list to mirror tac_section_type_vocab. Low risk; preserves authoring intent.
  • Option B: deprecate the 4 extra codes in tac_section_type_vocab (set lifecycle_status='deprecated'). Lower-risk operationally but loses semantic granularity.
  • Option C: keep both; document fn_iu_create as the source of truth and add a CHECK at tac_section_type_vocab insert 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 each iu_outbound poll. Updates a real liveness signal.
  • Option B (higher-fidelity, higher-risk): modify fn_iu_route_worker_run to 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 a verify_mark(approve=false) follow-up.
  • Option B: patch its cut_manifest payload 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 by 258c715c…/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.

Back to Knowledge Hub knowledge/dev/laws/dieu44-trien-khai/v0.6-dieu45-phase-3-mark-cut-queue-pilot-dieu37-write-channel/09-carry-forward.md