-- §4.5 M5: exactly one materialized copy per (descendant app, source template).
--
-- The materialization reconciler (materialize::rematerialize_stateful_templates)
-- runs on every tree/apply mutation, and two of them can run concurrently (e.g.
-- two apps created in parallel each trigger a full reconcile). Both compute the
-- same "missing" (app, template) pair and both try to insert the copy — without
-- a constraint that races into a DUPLICATE. This partial unique index makes the
-- second insert a no-op (the reconciler uses `ON CONFLICT DO NOTHING`), so a
-- copy is idempotent under concurrency.

CREATE UNIQUE INDEX triggers_materialized_uidx
    ON triggers (app_id, materialized_from) WHERE materialized_from IS NOT NULL;
