-- §11 tail (v1.2 Hierarchies): GROUP-level template suppression. -- -- 0058 let an APP decline an inherited group template (for that app only). A -- group operator often wants the same opt-out for a whole subtree: "no -- descendant of this group runs the ancestor's `audit` template." Until now -- only an app could suppress; a group could not. -- -- Reshape `template_suppressions` to a POLYMORPHIC owner, exactly like the -- group triggers/routes reshape (0056/0057) and the config markers (0051/0052): -- * `group_id` — nullable FK→groups, ON DELETE CASCADE (config, not code). -- * `app_id` — made nullable; the exactly-one CHECK enforces app XOR group. -- * the per-app unique index becomes per-owner partials. -- -- A GROUP suppression declines a template the group INHERITS from a higher -- ancestor, for the group's whole subtree. Inheritance-only still holds: the -- dispatch filters gate to group-owned rows, and a suppression only matches on -- the suppressing owner's ancestor chain — a group can decline what it -- inherits, never a sibling subtree's, never its own descendants' own rows. ALTER TABLE template_suppressions ADD COLUMN group_id UUID REFERENCES groups(id) ON DELETE CASCADE; ALTER TABLE template_suppressions ALTER COLUMN app_id DROP NOT NULL; ALTER TABLE template_suppressions ADD CONSTRAINT template_suppressions_owner_exactly_one CHECK ((group_id IS NULL) <> (app_id IS NULL)); DROP INDEX template_suppressions_uidx; CREATE UNIQUE INDEX template_suppressions_app_uidx ON template_suppressions (app_id, target_kind, reference) WHERE app_id IS NOT NULL; CREATE UNIQUE INDEX template_suppressions_group_uidx ON template_suppressions (group_id, target_kind, reference) WHERE group_id IS NOT NULL; -- The trigger anti-join / route rebuild look up by both owners now. CREATE INDEX template_suppressions_group_idx ON template_suppressions (group_id) WHERE group_id IS NOT NULL;