-- Trigger `name` (§4.5): an explicit per-app identifier that becomes the -- manifest merge/upsert key (Step B switches the apply diff to key on it). -- Until now triggers were identified only by their per-kind semantic tuple, -- so the declarative tool could only Create/Delete them, never Update. -- -- Backfill existing rows with `{kind}-{n}` (n = per-(app,kind) sequence by -- creation order) — the spec-sanctioned fallback when there's no cleaner -- entity token. Then enforce NOT NULL + UNIQUE(app_id, name). -- A `gen_random_uuid()` default keeps existing INSERTs (which don't yet -- supply a name) valid and unique — the manager-core write paths start -- providing meaningful names in the follow-up; new rows until then get a -- harmless unique placeholder. ALTER TABLE triggers ADD COLUMN name TEXT NOT NULL DEFAULT gen_random_uuid()::text; -- Rewrite the just-defaulted existing rows to the readable `{kind}-{n}` form. UPDATE triggers t SET name = sub.nm FROM ( SELECT id, kind || '-' || row_number() OVER ( PARTITION BY app_id, kind ORDER BY created_at, id ) AS nm FROM triggers ) sub WHERE t.id = sub.id; CREATE UNIQUE INDEX triggers_app_name_uniq ON triggers (app_id, name);