Files
PiCloud/crates/manager-core/migrations/0058_template_suppressions.sql
MechaCat02 18ac9f5afa feat(suppress): template_suppressions marker for per-app opt-out (§11 tail S1)
A group TRIGGER/ROUTE template inherits to every descendant app; until now
a descendant could shadow one but not decline it. This marker records that
an app opts OUT of a specific inherited template — coarse by REFERENCE (a
handler script name for triggers, a path for routes), not row id (template
ids churn on re-apply, references are stable so re-apply is a NoOp).

App-only (a group would just not declare the template) → app_id NOT NULL,
no polymorphic owner; pure app config → ON DELETE CASCADE. A target_kind
discriminator ('trigger'|'route') keeps it one table, one reconcile loop.

Schema blessed at 58 migrations.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 07:20:46 +02:00

37 lines
1.9 KiB
SQL

-- §11 tail (v1.2 Hierarchies): per-app opt-out of inherited group templates.
--
-- A group TRIGGER or ROUTE template inherits to every descendant app. Until now
-- a descendant could SHADOW a template (declare its own identical binding) but
-- not DECLINE one. This marker records that a specific app opts OUT of a
-- specific inherited template — the template then stops resolving for that app
-- (and only that app; a sibling subtree is unaffected).
--
-- Coarse by REFERENCE (not row id — template ids churn on re-apply): a
-- suppression names a handler SCRIPT NAME (target_kind='trigger') or a PATH
-- (target_kind='route'). A reference may decline more than one inherited
-- template (a group that bound several to the same script/path). The dispatch
-- filters gate to group-owned rows, so an app can only decline what it
-- INHERITS — never its own trigger/route, never a sibling's.
--
-- App-only: only an app suppresses (a group would just not declare the
-- template). So `app_id NOT NULL` — no polymorphic owner. It is pure app config
-- (like `extension_points`), so ON DELETE CASCADE (not the code-owner RESTRICT).
CREATE TABLE template_suppressions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
app_id UUID NOT NULL REFERENCES apps(id) ON DELETE CASCADE,
target_kind TEXT NOT NULL CHECK (target_kind IN ('trigger', 'route')),
-- A handler script name (trigger) or a path (route). Matched
-- case-insensitively for triggers (as script-name resolution is
-- elsewhere) and exactly for routes; stored as authored.
reference TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- One marker per (app, kind, reference) — re-apply is a NoOp.
CREATE UNIQUE INDEX template_suppressions_uidx
ON template_suppressions (app_id, target_kind, reference);
-- The trigger anti-join / route rebuild both look up by app_id.
CREATE INDEX template_suppressions_app_idx ON template_suppressions (app_id);