-- 036 — THE REAL FOUNDER CAP (A2-A6). One concern: the founder mechanism. -- Applied to prod 2026-07-31 (supabase_migrations 20260731211703). -- -- THE UNIQUE INDEX IS THE LOCK. The claim is a single UPDATE whose target row -- is chosen with FOR UPDATE SKIP LOCKED, so two concurrent claims cannot take -- the same slot. NO count is read in the decision path (the old view was a -- decorative count with no lock). -- -- POOL = GLOBAL 100 (Q1): the slot travels with the user, so analyst->desk -- keeps founder with no second claim and can never be denied. -- CANCEL = RETIRE FOREVER (Q2): cancelled slots stay claimed; the public -- counter only rises toward 100 and can never decrease. -- PRICE IDS ARE NOT IN SQL — the function returns a price KEY and the Node -- layer maps it to STRIPE_PRICE_* env with a boot assertion. A hardcoded id -- here would become a permanent silent mis-charge on a typo. CREATE TABLE IF NOT EXISTS founder_slots ( slot_number int PRIMARY KEY, user_id uuid NULL REFERENCES auth.users(id) ON DELETE SET NULL, status text NOT NULL DEFAULT 'free' CHECK (status IN ('free','provisional','claimed')), tier text NULL, claimed_at timestamptz NULL, expires_at timestamptz NULL, stripe_subscription_id text NULL, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now() ); -- ONE LIVE SLOT PER USER (free rows have NULL user_id, so only live rows bind). CREATE UNIQUE INDEX IF NOT EXISTS idx_founder_slots_one_per_user ON founder_slots (user_id) WHERE status <> 'free'; CREATE INDEX IF NOT EXISTS idx_founder_slots_free ON founder_slots (slot_number) WHERE status = 'free'; INSERT INTO founder_slots (slot_number) SELECT gs FROM generate_series(1, 100) gs ON CONFLICT (slot_number) DO NOTHING; ALTER TABLE founder_slots ENABLE ROW LEVEL SECURITY; -- service-role only -- A3 atomic claim / A4 finalize / A5 TTL release / A6 honest counter: -- see the applied migration body (identical to this file) for -- claim_founder_slot(uuid, text) -> (is_founder, price_key, slot_number) -- finalize_founder_slot(uuid, text, text, text) -> boolean -- release_expired_slots() -> int -- VIEW founder_pricing_seats (claimed, total, remaining) -- A7: finalize is the SINGLE writer of both founder flags in ONE txn — -- user_profiles.founder_pricing is canonical and users.founder_status mirrors -- it (it is served by auth PROFILE_COLUMNS + /api/stripe, so it is NOT dropped; -- only the independent write is retired, because the two already drifted 1 vs 0).