11000x · 03 — Migration 030: event_outbox.event_domain CHECK += 'piece' (10000x defect fix)
11000x · 03 — Migration 030 (10000x defect fix, LIVE applied)
Defect surfaced
During Phase B of the bounded BEGIN/ROLLBACK proof:
ERROR: new row for relation "event_outbox" violates check constraint "event_outbox_event_domain_check"
DETAIL: Failing row contains (... piece, superseded, update, immediate, ...)
The pre-existing CHECK constraint:
CHECK (event_domain = ANY (ARRAY[
'iu', 'birth_registry', 'governance', 'tac',
'kg', 'system', 'dot', 'health']))
Did not include 'piece', even though the 10000x 01-piece-event-type-seed.sql happily registered 6 piece.* event types in event_type_registry with event_domain='piece'.
This was a dormant defect: the registry insert and the outbox insert had different validation paths (registry insert had no FK to a domain enum; outbox insert is gated by both a trigger validator AND this column CHECK). Because 10000x never actually emitted a piece event, the defect lay invisible until 11000x's bounded proof.
Fix
Migration 030 drops + recreates the CHECK as a strict superset:
ALTER TABLE public.event_outbox DROP CONSTRAINT event_outbox_event_domain_check;
ALTER TABLE public.event_outbox ADD CONSTRAINT event_outbox_event_domain_check
CHECK (event_domain = ANY (ARRAY[
'iu','birth_registry','governance','tac',
'kg','system','dot','health',
'piece']));
Plus a DO $$ ... RAISE EXCEPTION post-apply that re-reads pg_get_constraintdef and aborts if 'piece' isn't present.
Live apply transcript
BEGIN
ALTER TABLE
ALTER TABLE
DO
COMMIT
Existing 121,289 event_outbox rows were re-validated against the new CHECK (PostgreSQL default behaviour without NOT VALID). All passed — the new constraint is a strict superset.
D9 inventory impact
None. ALTER CONSTRAINT changes no row in pg_class / pg_proc / pg_trigger / dot_config / event_type_registry / outbound_route / iu_sql_event_route. The D9 scan inventory is unchanged.
Rollback caveat
rollback/030_event_outbox_event_domain_add_piece.rollback.sql will fail if any event_outbox row has event_domain='piece' (PostgreSQL revalidates rows when ADD CONSTRAINT runs). Inspect first:
SELECT count(*) FROM public.event_outbox WHERE event_domain='piece';
At the time of this report: 0 piece rows persisted (the bounded proof rolled back; gates remain closed; no live emission has happened).
Lesson written to memory
[[feedback-event-outbox-check-vs-registry-drift]]:
Registering an event_domain in event_type_registry is necessary but NOT sufficient. The event_outbox.event_domain CHECK constraint must also accept the new domain. Before declaring an event-type seed "done", attempt one BEGIN/INSERT/ROLLBACK against event_outbox to confirm the column constraint allows it.
Why: 10000x ran its
04-author-mode-verification.sqlagainstevent_type_registryonly and reported PASS. The CHECK on event_outbox was not in the verification set. 11000x's bounded proof attempted a real INSERT (still under BEGIN/ROLLBACK) and surfaced the defect immediately.How to apply: any future macro that adds a new event_domain or event_stream value should include — in its verification pack — at least one BEGIN…INSERT…ROLLBACK round-trip into the actual outbox table.