Hi team — sharing this because we've had a handful of Neo subscribers report the same confusing experience on the macOS desktop app over the last day, and I think a small follow-up to #7496 would resolve it.
What users see
After opening the desktop app, the Plan and Usage page shows three things together:
- A banner at the top: "Trial Ended — Upgrade to keep unlimited access" with a "View Plans" button.
- A usage card reading "30 / 30 — Chat questions on Free plan — Resets in N days", blocking chat at the basic 30/month cap.
- (Lower on the same page, correctly) "Neo — Your paid plan is active. Access ends on ".
To a user, "your paid Neo plan is active" + "Trial Ended" + "you're on the Free plan, 30/30 used" together reads as a bug, even though it's the intentional output of the new desktop-entitlement policy.
Why it happens (working as currently coded)
backend/utils/subscription.py:
DESKTOP_ENTITLED_PLAN_TYPES = {PlanType.operator, PlanType.architect}
def plan_grants_desktop(plan: PlanType) -> bool:
return plan in DESKTOP_ENTITLED_PLAN_TYPES
Since Neo (unlimited) isn't in that set, a Neo subscriber on desktop now goes through the same code path as a basic user past trial:
/v1/users/me/trial → trial_expired: true → desktop renders the "Trial Ended" banner (SettingsPage.swift:1784).
/v1/users/me/usage-quota (desktop) → forged plan: "Free", used: 30, limit: 30, allowed: false from the trial-paywalled branch in subscription.py:458.
The mobile plans sheet got a per-tier "Neo: No desktop access" indicator in the same PR — but the desktop client itself wasn't updated to explain the new policy, so it falls back to the existing trial-expired UI.
Two small follow-ups that would resolve this
1. Grandfather existing Neo subscribers until their current paid period ends
Most of the complaints are from users who bought Neo through the desktop app before the policy changed and were using it on desktop without issue. Pulling that access mid-billing-cycle is what's surprising them.
One option: keep desktop entitlement for any Neo subscription created before #7496's merge timestamp, until its current_period_end. Something like:
NEO_DESKTOP_GRANDFATHER_BEFORE = int(os.getenv("NEO_DESKTOP_GRANDFATHER_BEFORE", "<#7496 merge ts>"))
def plan_grants_desktop(plan: PlanType, subscription: Optional[Subscription] = None) -> bool:
if plan in DESKTOP_ENTITLED_PLAN_TYPES:
return True
if (
plan == PlanType.unlimited
and subscription
and subscription.stripe_subscription_id
and (subscription.created_at or 0) < NEO_DESKTOP_GRANDFATHER_BEFORE
and subscription.current_period_end
and subscription.current_period_end >= int(time.time())
):
return True
return False
(Or a desktop_grandfathered_until field on the Firestore subscription, set during a one-time backfill of currently-active Neo subs created before the cutoff.) When the window expires at the next renewal after the cutoff, those users fall through to the new policy.
2. Update the desktop UI copy so the new policy is explained instead of looking like a trial expiry
Independent of grandfathering — when trialMetadata.trialExpired is true AND the user has a paid non-desktop plan (e.g. Neo), SettingsPage.swift:1784 should show plan-specific copy rather than the generic trial-ended banner. Suggested wording:
Neo is available on mobile and web.
Desktop access requires Operator or Architect. [Upgrade] [Keep on mobile]
Same idea for the chat usage card: instead of forging "30/30 on Free plan", show the user's real Neo usage with a note that those questions live on mobile and web. This is the right fix regardless of grandfathering — it prevents future Neo signups from getting the same first-launch confusion on desktop.
Acceptance criteria
Happy to help with any of this — let me know what'd be most useful.
Refs: #7496
Posted by Caleb (AI agent) on behalf of Mohsin.
Hi team — sharing this because we've had a handful of Neo subscribers report the same confusing experience on the macOS desktop app over the last day, and I think a small follow-up to #7496 would resolve it.
What users see
After opening the desktop app, the Plan and Usage page shows three things together:
To a user, "your paid Neo plan is active" + "Trial Ended" + "you're on the Free plan, 30/30 used" together reads as a bug, even though it's the intentional output of the new desktop-entitlement policy.
Why it happens (working as currently coded)
backend/utils/subscription.py:Since Neo (
unlimited) isn't in that set, a Neo subscriber on desktop now goes through the same code path as a basic user past trial:/v1/users/me/trial→trial_expired: true→ desktop renders the "Trial Ended" banner (SettingsPage.swift:1784)./v1/users/me/usage-quota(desktop) → forgedplan: "Free", used: 30, limit: 30, allowed: falsefrom the trial-paywalled branch insubscription.py:458.The mobile plans sheet got a per-tier "Neo: No desktop access" indicator in the same PR — but the desktop client itself wasn't updated to explain the new policy, so it falls back to the existing trial-expired UI.
Two small follow-ups that would resolve this
1. Grandfather existing Neo subscribers until their current paid period ends
Most of the complaints are from users who bought Neo through the desktop app before the policy changed and were using it on desktop without issue. Pulling that access mid-billing-cycle is what's surprising them.
One option: keep desktop entitlement for any Neo subscription created before #7496's merge timestamp, until its
current_period_end. Something like:(Or a
desktop_grandfathered_untilfield on the Firestore subscription, set during a one-time backfill of currently-active Neo subs created before the cutoff.) When the window expires at the next renewal after the cutoff, those users fall through to the new policy.2. Update the desktop UI copy so the new policy is explained instead of looking like a trial expiry
Independent of grandfathering — when
trialMetadata.trialExpiredis true AND the user has a paid non-desktop plan (e.g. Neo),SettingsPage.swift:1784should show plan-specific copy rather than the generic trial-ended banner. Suggested wording:Same idea for the chat usage card: instead of forging "30/30 on Free plan", show the user's real Neo usage with a note that those questions live on mobile and web. This is the right fix regardless of grandfathering — it prevents future Neo signups from getting the same first-launch confusion on desktop.
Acceptance criteria
current_period_end.Happy to help with any of this — let me know what'd be most useful.
Refs: #7496
Posted by Caleb (AI agent) on behalf of Mohsin.