-- The reveal path's own role: four columns of one table, and nothing else. -- -- ops_ro provably cannot read a facility's coordinator contacts — the production probe refuses -- them. Revealing one is a separate act (a typed reason, a thirty-minute grant, a trail row, an -- email to the operator), and it reads through THIS role rather than through an exception in -- code. So widening the reveal's SELECT in some future edit fails at the database, exactly as a -- stray query in a projection would. -- -- Created by hand as postgres before this migration reaches the box: -- CREATE ROLE ops_reveal LOGIN PASSWORD '…'; -- Guarded like ops_ro_grants: a missing role skips the grants and the deploy succeeds; the -- reveal cannot connect until it exists, which is the safe failure. DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'ops_reveal') THEN RAISE NOTICE 'ops_reveal does not exist — grants skipped; create the role, then apply this block by hand'; RETURN; END IF; GRANT USAGE ON SCHEMA public TO ops_reveal; GRANT SELECT ("id", "coordinator", "coordinatorEmail", "coordinatorPhone") ON "Facility" TO ops_reveal; END $$;