Files
vyndr/specs
builtbykev e970ab1ef3 report: Build 2 Review Zero — G1-G6 + DB verified; two order expectations wrong
No build, no migration, no Stripe object touched. Awaiting Kev on Q1-Q3.

TWO EXPECTATIONS IN THE ORDER ARE WRONG:

1. G5 — users.founder_status is LIVE, not dead. Written by the webhook
   (stripeService.js:163), read and served by routes/stripe.js:95 as is_founder,
   and present in middleware/auth.js:24 PROFILE_COLUMNS so it loads on EVERY
   authenticated request. The guardrail says don't write it unless G5 proves it
   live — G5 proves it live, so A5 must NOT drop it.

2. THE TWO FOUNDER FLAGS ALREADY DISAGREE IN PROD: user_profiles.founder_pricing
   is true on 1 of 3 profiles while users.founder_status is true on 0 of 3. The
   webhook writes both from the same isFounder, so this is a dual-write that has
   already drifted. The build must pick one canonical flag and derive or retire
   the other; two independently-writable founder flags is how a founder loses
   their rate on one code path.

GREPS: G1 founder_pricing has exactly one writer (the webhook mirror) and four
readers (partners MRR attribution, the profile API, the profile badge). G2 the
promo-code bypass is the ONLY founder gate today — getPriceId(tier, founderCode)
against VALID_FOUNDER_CODES, stamped into metadata.is_founder, which the webhook
then trusts, so a code alone mints a founder at any seat number. G3 the webhook
DOES set tier + subscription_status=active + founder_pricing (closing an earlier
CANNOT DETERMINE: a paid sub does flip the Build-1 gate) but stores NO
stripe_subscription_id, confirming A1. G4 nexapay has ZERO code references and
the column is empty, so A5's drop is evidence-supported as its own migration.
G6 price selection is getPriceId -> line_items.

DB VERIFIED: user_profiles has nexapay_customer_id and NO stripe_customer_id /
stripe_subscription_id (A1 needed); users already carries stripe_customer_id;
founder_pricing_seats is a VIEW; 3 profiles, 1 flagged founder.

CANNOT DETERMINE: the four Stripe price IDs — no STRIPE_SECRET_KEY or
STRIPE_PRICE_* in this environment, so I could not independently re-verify that
the IDs in the order are what prod will charge. Since A3 would hardcode them, a
typo becomes a permanent mis-charge; recommend reading them from env (already the
pattern) with a boot assertion that all four resolve.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QJs13VsyiSKYQP6rj3NNmc
2026-07-31 17:07:54 -04:00
..