Step 7 of docs/operations/annual-plan-migration.md — the only part of the ADR 029 cutover that cannot be done yet, because it has to wait for the last subscriber to renew onto annual.
Do not action before 2026-09-23
The three migrated subscriptions move at their own renewals:
| Subscription |
Schedule |
First $9 invoice |
sub_1U3hA6Rvqrfm74B26iV9dfrN |
sub_sched_1UCLMfRvqrfm74B29mPzbcEq |
2026-09-11 |
sub_1TuHCpRvqrfm74B21mBOZMsa |
sub_sched_1UCLMgRvqrfm74B2roUpcp9Y |
2026-09-16 |
sub_1TlLkeRvqrfm74B29TPzpacJ |
sub_sched_1UCLMhRvqrfm74B2WHYEfHVz |
2026-09-23 |
Archiving the monthly price before the last one renews would break that subscription's renewal.
Checklist
Confirm everyone has moved first. The dry run is the check — when it reports zero to migrate and no already-scheduled skips, every schedule has completed its first phase. Needs a short-lived restricted key (Subscriptions: Write, Subscription Schedules: Write), not vercel env pull — Vercel redacts sensitive values and STRIPE_SECRET_KEY comes back empty:
STRIPE_SECRET_KEY=rk_live_... VITE_PRICE_PERSONAL_YEARLY=price_1UCKSrRvqrfm74B2ZVK37lv2 \
npx tsx scripts/migrate-to-annual-plan.ts
Independent of the schedule — can be done any time
These have zero subscriptions and nothing points at them:
Archiving is reversible in all cases.
Step 7 of
docs/operations/annual-plan-migration.md— the only part of the ADR 029 cutover that cannot be done yet, because it has to wait for the last subscriber to renew onto annual.Do not action before 2026-09-23
The three migrated subscriptions move at their own renewals:
sub_1U3hA6Rvqrfm74B26iV9dfrNsub_sched_1UCLMfRvqrfm74B29mPzbcEqsub_1TuHCpRvqrfm74B21mBOZMsasub_sched_1UCLMgRvqrfm74B2roUpcp9Ysub_1TlLkeRvqrfm74B29TPzpacJsub_sched_1UCLMhRvqrfm74B2WHYEfHVzArchiving the monthly price before the last one renews would break that subscription's renewal.
Checklist
Confirm everyone has moved first. The dry run is the check — when it reports zero to migrate and no
already-scheduledskips, every schedule has completed its first phase. Needs a short-lived restricted key (Subscriptions: Write, Subscription Schedules: Write), notvercel env pull— Vercel redacts sensitive values andSTRIPE_SECRET_KEYcomes back empty:STRIPE_ALLOWED_PRICES=price_1UCKSrRvqrfm74B2ZVK37lv2price_1TVVy6Rvqrfm74B2DZ2Qa9NE($5/month) in Stripepersonal-monthlykey fromsrc/core/billing/deeplink.ts, its tests, and any landing links. ADR 029 calls it "a lie by name" — kept only so old links keep sellingPOST /api/checkout/create-sessionwith the annual price returns 200Independent of the schedule — can be done any time
These have zero subscriptions and nothing points at them:
price_1TVW0nRvqrfm74B2BtFlcf6D($50/year)price_1TVW0DRvqrfm74B2L2dItBhZ($19/month Pro) andprice_1TVW0DRvqrfm74B2rNLLRprR($199/year Pro), andprod_UUV0RkTZnBloZC(FeedZero Pro) — retired by ADR 029, unreachable through checkout because the allowlist excludes them, but still selectable in the Dashboard for a manual invoice or Payment LinkArchiving is reversible in all cases.