KB-7950

IU Core 500x — 02 Production apply closeout + composer-event lane defect

4 min read Revision 1
dieu44iu-core-mvp500xproduction-applycomposer-eventdelayed-lanev0.62026-05-22

02 — 480x production apply closeout + the composer-event lane defect

1. The apply sequence

All applied to the production directus DB, each file self-transacted:

step file result
1 016_composer_event_wiring.sql 2 functions + 2 views created
2 runtime/260 (corrected) 8 event types + 8 routes, R1/R2 pass
3 sandbox/110 BEGIN…ROLLBACK — 9/9 probes pass
4 runtime/270 durable composed-from-scratch collection
5 runtime/110 DOT scan — 104/104

2. The composer-event lane defect — found and fixed

The 480x package was authored but its sandbox/110 probe was never executed — the 480x session's MCP surface was SELECT-only. Run for the first time this macro, sandbox/110 failed 4 of 9 probes: a 2-piece fn_iu_compose emitted only 1 piece_added_to_collection event, not 2.

Root cause. event_outbox carries a partial unique index

idx_event_outbox_idempotent
  (event_domain, event_type, event_subject_table, event_subject_ref)
  WHERE delivery_lane = 'immediate'

Every composer event uses event_subject_ref = the collection id and the 480x authoring registered the family on the 'immediate' lane. So a collection could hold only one row per (event_type, collection) — every composer delta after the first was silently deduped by ON CONFLICT DO NOTHING. The defect is real on production, not a probe artifact: runtime /270 would have emitted 1 piece_added instead of 2.

Fix (500x). Register the composer family on the 'delayed' lane. event_outbox's delivery_lane CHECK allows {immediate, delayed}; the idempotency index is partial on 'immediate' only, so 'delayed' rows escape it entirely. The route worker is lane-agnostic — it selects by event_domain + a keyset cursor, never by lane — so delivery is unaffected. The composer family is a stream of DELTA events; an append-only lane is the correct model. fn_iu_emit_collection_event sources delivery_lane from the registry, so migration 016 needed no change. runtime/260 + sandbox/110 were corrected; the applied 'immediate' registration was rolled back (runtime/rollback/260) and the corrected file re-applied — zero composer events had been emitted yet, so the swap was clean.

Re-run, sandbox/110 is 9/9E2 collection_created=1 piece_added=2, E3 5 mutation events, E5 7 backlog rows, E6 event_count 7.

3. runtime/270 — durable composed-from-scratch collection

Committed: collection iu_core.composer.scratch-file-001 (kind file, lifecycle draft, source_axis_kind composed, digest_present). 2 pieces minted through the fn_iu_create birth gate inside fn_iu_compose (information_unit 158 → 160). R270_events1 collection_created + 2 piece_added_to_collection + 1 collection_rendered = 4 durable composer events, all on the 'delayed' lane. The delayed-lane fix is verified durably (2 piece_added landed, not deduped). Composer gate closed again at end of transaction.

4. DOT 84 → 104, then → 106

runtime/110 after 016+260+270: 104/104, D8 drift 0. After migration 017 (doc 03): 106/106, function 36 → 38.

5. Worker dry-run delivery evidence

fn_iu_route_worker_run('iu_outbound_default', 200): seen=4, attempts_written=4, dead_lettered=0, skipped=0. Each of the 4 composer events got exactly 1 iu_route_attempt, all status='dry_run', 0 sent. iu_route_dead_letter open = 0. External delivery is structurally impossible — every composer route is enabled=true, dry_run=true and the iu_outbound_route_safe_chk CHECK forbids an enabled+live route.

Back to Knowledge Hub knowledge/dev/laws/dieu44-trien-khai/v0.6-iu-core-500x-dot-one-command-composer-production-closeout-open-goal/02-production-apply-closeout.md