-- Phase 4 (v1.2 Hierarchies): group-owned scripts.
--
-- Until now every script was owned by exactly one app (`app_id NOT NULL`,
-- ON DELETE RESTRICT). Phase 4 lets a script be owned by a GROUP instead, so
-- it is shared by every descendant app — resolved by name, nearest-owner
-- wins (CoW: an app's own script of the same name shadows the inherited one),
-- exactly like `vars`/`secrets` (0048/0049).
--
-- Phase 4-LITE scope: group-owned ENDPOINT scripts only. Group modules and
-- the origin-aware (lexical) import resolver are deferred to Phase 4b, so a
-- group-owned script must be self-contained (enforced in the service layer).
--
-- Reshape (mirrors vars/secrets, but RESTRICT not CASCADE — code is not data,
-- a group can't be deleted out from under the scripts it owns, matching the
-- existing app_id RESTRICT and the §5.6 delete=RESTRICT rule):
--   * `group_id` — nullable FK→groups, ON DELETE RESTRICT.
--   * `app_id`   — made nullable (was NOT NULL); the exactly-one CHECK now
--     enforces "owned by an app XOR a group".
--   * the per-app unique name index becomes two partial indexes, one per owner.

ALTER TABLE scripts
    ADD COLUMN group_id UUID REFERENCES groups(id) ON DELETE RESTRICT;

ALTER TABLE scripts
    ALTER COLUMN app_id DROP NOT NULL;

ALTER TABLE scripts
    ADD CONSTRAINT scripts_owner_exactly_one
        CHECK ((group_id IS NULL) <> (app_id IS NULL));

-- Per-owner, case-insensitive name uniqueness. Partial so each owner column
-- only constrains its own rows; existing app rows (group_id NULL) keep the
-- exact same (app_id, LOWER(name)) uniqueness they had under the old index.
DROP INDEX scripts_name_uidx;
CREATE UNIQUE INDEX scripts_app_name_uidx
    ON scripts (app_id, LOWER(name)) WHERE app_id IS NOT NULL;
CREATE UNIQUE INDEX scripts_group_name_uidx
    ON scripts (group_id, LOWER(name)) WHERE group_id IS NOT NULL;

CREATE INDEX scripts_group_id_idx ON scripts (group_id) WHERE group_id IS NOT NULL;
