Rename the field
blast radiusRename User.plan to User.subscriptionTier
`plan` is ambiguous — we now have billing plans, onboarding plans, and capacity plans, and three of last quarter's incidents traced back to somebody reading the wrong one.
Rename the field on the User model to `subscriptionTier`. Values are unchanged: still `free`, `pro`, `scale`.
The rename is correct. It was done with the refactoring tool, all 41 in-repo call sites moved with it, the type check is clean and the full suite is green. Nothing in this diff is wrong, and you will not find a defect in it.
Your job is the other question: given the rest of the system below, what does this break, what needs a migration alongside it, and what is genuinely untouched? Marking everything as broken is not caution — it is the same as knowing nothing, and it is scored that way.
-model User {- id String @id @default(cuid())- email String @unique- plan String @default("free")- createdAt DateTime @default(now())-}+model User {+ id String @id @default(cuid())+ email String @unique+ subscriptionTier String @default("free")+ createdAt DateTime @default(now())+} // 41 call sites updated by the rename tool across 12 files.// Type check clean. 340 tests green. No behavioural change:// the stored values ("free" | "pro" | "scale") are untouched.export async function upgrade(userId: string, tier: Tier) { const user = await db.user.update({ where: { id: userId }, data: { subscriptionTier: tier }, }); await audit.record("billing.upgraded", { userId, tier }); return user;}const KEY = (userId: string) => `ent:v1:${userId}`; export async function getEntitlements(userId: string) { const cached = await redis.get(KEY(userId)); if (cached) return JSON.parse(cached) as Entitlements; const user = await db.user.findUniqueOrThrow({ where: { id: userId } }); const ent = buildEntitlements(user.subscriptionTier); await redis.setex(KEY(userId), 86_400, JSON.stringify(ent)); return ent;}-- No migration file was generated for this change.---- The Prisma model now declares: subscriptionTier String-- The database column is still: plan text -- Deploy order in this repo: containers roll first, migrations run after.SELECT properties ->> 'plan' AS tier, date_trunc('day', ts) AS day, count(*) AS eventsFROM analytics.eventsWHERE name = 'subscription.changed'GROUP BY 1, 2ORDER BY 2 DESC;export async function emitSubscriptionChanged(user: User) { await deliver("subscription.changed", { user_id: user.id, email: user.email, plan: user.subscriptionTier, changed_at: new Date().toISOString(), });}type User { id: ID! email: String! plan: SubscriptionTier! # resolver: (user) => user.subscriptionTier createdAt: DateTime!}{ "plan_v2_pricing": { "enabled": true, "rollout": 1.0 }, "annual_billing": { "enabled": false, "rollout": 0.0 }, "seat_based_trial": { "enabled": true, "rollout": 0.25 }}it("upgrades a free user to pro", async () => { const user = await factory.user({ subscriptionTier: "free" }); await upgrade(user.id, "pro"); const updated = await db.user.findUniqueOrThrow({ where: { id: user.id } }); expect(updated.subscriptionTier).toBe("pro");});