-- §3 M3 (hermetic gate): persist the per-env approval policy server-side. -- -- Before this table the policy lived ONLY in the apply request -- (`ProjectDecl.environments`), so a hand-crafted request that omitted it was -- ungated — the server had nothing authoritative to check against. This makes -- the gate hermetic: the confirm-required set is stored per project and the -- server enforces against `persisted ∪ declared` (an env is gated if EITHER the -- stored row OR the request says so), so an omitted or flipped-to-false policy -- can no longer bypass a gate a prior apply established. -- -- One owner (the project), a single boolean policy per environment name — no -- polymorphic owner and no environment_scope (unlike `vars`/`secrets`, which -- are data the apply targets; this is metadata ABOUT the apply). CASCADE on the -- project mirrors 0066's philosophy: un-claiming/deleting a project drops its -- policy, it does not linger to gate a tree the project no longer owns. CREATE TABLE project_environments ( project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE, -- The environment name as declared in `[project.environments]` (e.g. -- "production"); matched against the apply's `--env`. env_name TEXT NOT NULL, -- TRUE => applying to this env is gated (needs `--approve ` + admin). confirm BOOLEAN NOT NULL, PRIMARY KEY (project_id, env_name) );