Goal: isPro stops being stored and becomes something the app reads from a server row it cannot write. Today signIn() sets the provider, discards the identity and flips isPro: true — *sign-in is the purchase* (useSipStore.ts:111-112), and the paywall CTA routes to that same screen.
The first draft (2026-08-23, "accounts, sync & a real subscription") was written to be argued with, so it got argued with. It framed identity, sync and entitlement as three concerns usually treated as one — correctly — and then bundled all three into seven commits and one migration anyway.
Sync is out. Deferred, and possibly permanently: Apple Health / Google Health may turn out to be the sync layer, at which point a bespoke device-to-device engine never needs to exist.
Cutting it takes the tombstone problem, the prune/pull loop, the outbox, clock skew and five of the nine assertions with it — and leaves the change that was actually urgent: a client can grant itself Pro.
In — one subscriptions table with its RLS policies, a stripe-webhook Edge Function, src/lib/supabase.ts + src/lib/auth.ts (no screen imports the SDK directly), store v3 → v4, real email auth, a restore path, real account deletion, and the copy pass. Six commits.
Out — any SDK bump, any sync, profiles / entries tables, Google and Apple sign-in, store IAP, Focus lock, non-US storefronts, and any new styled component — so for once the native-styling class of bug is genuinely out of scope.
The delivery question finally got an answer: Sip ships as a real end-user product on the App Store and Play, with the portfolio value as a by-product rather than the point. That single answer puts the SDK 54 pin on a clock.
Assumptions closed by reading, per the standing lesson: @supabase/supabase-js is pure JS so nothing here needs a dev build, metro's web-only zustand→CJS redirect branches on startsWith('zustand') only, and .gitignore covers .env*.local — so a committed anon key is a decision (RLS is the protection), not an accident, and every real secret lives in Edge Function env.