IU Core 500x — 02 Production apply closeout + composer-event lane defect
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/9 — E2 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_events — 1 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.