Introduce Solo plan: rename Starter → Solo in inspector UI#1996
Introduce Solo plan: rename Starter → Solo in inspector UI#1996chelojimenez merged 2 commits intomainfrom
Conversation
Widens all OrganizationPlan type unions to include "solo" alongside
"starter" so the inspector tolerates backend responses from both the
current backend (plan: "starter") and the incoming backend PR that
normalizes everything to "solo".
Key changes:
- formatPlanName("starter" | "solo") → "Solo" so trial users and
subscription holders see the correct display name regardless of which
value the backend currently returns.
- getAnnualDiscountPercent reads plans.solo ?? plans.starter so it
works against both catalog shapes.
- All plan-tier type signatures (CheckoutPlanTier, PLAN_RANK, hook
params, component props) expanded to accept "solo".
- Downgrade confirmation flow now sets targetPlan: "solo" (canonical)
and passes it dynamically instead of hardcoding "starter".
- Stale pricing copy ("$61×12 vs $588", "Starter subscription in
place", "unused Starter time") updated to Solo.
- All 3401 tests updated and passing.
This PR is safe to deploy before the backend Solo PR; it continues to
work against the current catalog (plans.starter only). The cleanup
PR dropping the plans.starter alias and "starter" literals from the
backend schema should follow after both PRs are live and the
migrateStarterToSolo migration has run.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
Internal previewPreview URL: https://mcp-inspector-pr-1996.up.railway.app |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6bf72f96d2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (isHigherTier && entry.isSelfServe) { | ||
| if (plan !== "starter" && plan !== "team") { | ||
| if (plan !== "starter" && plan !== "solo" && plan !== "team") { | ||
| return { label: "Unavailable", disabled: true, variant: "outline" }; |
There was a problem hiding this comment.
Add Solo to plan-rank ordering before enabling Solo plan state
Now that OrganizationPlan includes "solo", billing states can carry currentPlan === "solo", but OrganizationBillingSection still derives rank from PLAN_ORDER that does not include solo, so getPlanRank("solo") becomes -1. That makes the CTA logic in this branch classify the Starter/Solo column as an upgrade instead of current/equivalent, which breaks compare-table actions and messaging once backend billing status starts returning solo.
Useful? React with 👍 / 👎.
| setPendingDowngradeConfirmation({ | ||
| targetPlan: "starter", | ||
| targetPlan: "solo", | ||
| targetBillingInterval, |
There was a problem hiding this comment.
Preserve starter downgrade target until backend accepts solo
This forces Team downgrades to set targetPlan: "solo" regardless of which low-tier alias was selected. In the rollout state where inspector ships before the backend solo mutation support, this path sends solo to startPlanChange and can fail instead of scheduling a downgrade. Keep sending starter (or runtime-map based on backend capability) until the server-side mutation accepts both tiers.
Useful? React with 👍 / 👎.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (2)
WalkthroughThis pull request adds a new "solo" billing tier across the client: UI text/display names change from "Starter" to "Solo"; type unions (plans, checkout tiers, scheduled-plan snapshots) and component props are expanded to include "solo"; plan-ranking, pricing, and seat-limit logic treat "solo" as equivalent to "starter"; billing flows (upgrades, downgrades, confirmations, cancellation handling) and related dialogs now accept and reference "solo"; tests and mocked plan catalogs are updated to use the "Solo" display name. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.Comment |
- getPlanRank: normalize "solo" → "starter" so currentPlan "solo" maps to rank 1 instead of -1; fixes "Current plan" CTA once backend starts returning plan: "solo". - isCurrentPlan: treat "solo" and "starter" as equivalent so the Solo column shows "Current plan" rather than "Upgrade" for solo subscribers. - Downgrade targetPlan/API call: revert from "solo" back to "starter" so the scheduled downgrade request works on the current backend (which only accepts "starter" until backend PR #182 lands). formatPlanName still renders it as "Solo" in the dialog. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d40d4c3445
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| if ( | ||
| (currentPlan !== "starter" && currentPlan !== "team") || | ||
| (currentPlan !== "starter" && currentPlan !== "solo" && currentPlan !== "team") || |
There was a problem hiding this comment.
Normalize starter/solo before scheduled-change comparisons
By allowing currentPlan === "solo" into getScheduledBillingChangeCancellationState, this path now runs during the starter→solo migration, but the later checks still compare raw identifiers (scheduledPlan === currentPlan). If billing data mixes aliases (e.g., plan: "solo" with stripeScheduledPlan: "starter" for the same tier), the UI incorrectly treats it as a real plan change and shows a cancellation CTA/message for a non-change. Normalize starter/solo to one canonical value before equality checks in this helper.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit d40d4c3. Configure here.
| }; | ||
|
|
||
| export type CheckoutPlanTier = "starter" | "team"; | ||
| export type CheckoutPlanTier = "starter" | "solo" | "team"; |
There was a problem hiding this comment.
Checkout guard doesn't treat solo and starter as equivalent
Medium Severity
The guardCheckoutIntentAgainstBillingStatus function uses strict equality (effectivePlan === requestedTier) for the "already_on" check. With solo: 1 and starter: 1 now both in PLAN_RANK, a user whose effectivePlan is "solo" requesting "starter" (or vice versa) bypasses both the equality check and the > rank check, returning proceed: true. This allows an unnecessary checkout flow for an equivalent plan via deep link (e.g. ?plan=solo when already on "starter").
Additional Locations (1)
Reviewed by Cursor Bugbot for commit d40d4c3. Configure here.
| if ( | ||
| currentPlan === "team" && | ||
| targetPlan === "starter" && | ||
| (targetPlan === "starter" || targetPlan === "solo") && |
There was a problem hiding this comment.
Downgrade flow hardcodes "starter" instead of preserving targetPlan
Medium Severity
The condition at line 799 was widened to accept targetPlan === "solo", but line 803 still hardcodes targetPlan: "starter" into the pending confirmation state. This silently discards an incoming "solo" value. Additionally, line 861 uses as "starter" type assertion on the supposedly-dynamic pendingDowngradeConfirmation.targetPlan, masking any future type mismatch. The PendingDowngradeConfirmation interface also wasn't updated to include "solo" in its targetPlan union.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit d40d4c3. Configure here.


Summary
OrganizationPlantype unions to include\"solo\"alongside\"starter\"so the inspector handles both the current backend (returning\"starter\") and the incoming backend PR that normalizes everything to\"solo\".formatPlanName(\"starter\" | \"solo\")→\"Solo\"so trial users and subscribers see the correct display name regardless of which value the backend currently returns.getAnnualDiscountPercentreadsplans.solo ?? plans.starterto work against both catalog shapes (pre and post backend deploy).CheckoutPlanTier,PLAN_RANK, hook params, component props) expanded to accept\"solo\".targetPlan: \"solo\"(canonical) and passes it dynamically instead of the hardcoded\"starter\".\"$61×12 vs $588\",\"Starter subscription in place\",\"unused Starter time\") updated to Solo.Why
Backend PR MCPJam/mcpjam-backend#182 introduces
soloas the canonical replacement forstarter. The rollout order is:\"starter\"and\"solo\"from any backend.\"solo\"(normalized), keepsplans.starteralias in catalog.migrateStarterToSolomigration against dev then prod (rewrites 2,255trialPlan: \"starter\"rows).\"starter\"literals from backend schema/validators and remove theplans.starteralias.Reviewer notes
PLAN_ORDERinOrganizationBillingSection.tsxintentionally stays as[\"free\", \"starter\", \"team\", \"enterprise\"]for now — the backend creates aplans.starteralias that mirrorsplans.solo, so the compare table continues to readplanCatalog.plans.starterthrough the transition.formatPlanName(\"starter\")now returns\"Solo\"(not\"Starter\"). This is intentional — they are the same product.Test plan
plans.starteralias)?plan=soloare accepted (new) and?plan=starterstill work (backward compat)🤖 Generated with Claude Code
Note
Medium Risk
Touches billing plan-selection and confirmation flows to accept a new
solotier; mistakes could mis-route upgrades/downgrades or display incorrect plan state, but changes are mostly type/copy and guard logic updates.Overview
Updates billing-related UI and types to treat Starter → Solo as the same tier, adding
soloacrossOrganizationPlan/checkout unions, rank/compare-table logic, and deep-link validation while keeping backward compatibility withstarter.Adjusts plan-change behavior and messaging: upgrade confirmation now triggers for
starter/solo→ Team, scheduled-change/downgrade dialogs render dynamic Solo copy, and discount/price formatting readsplans.solo ?? plans.starter. Tests are updated to expect Solo labels throughout.Reviewed by Cursor Bugbot for commit d40d4c3. Bugbot is set up for automated code reviews on this repo. Configure here.