Skip to content

Neo subscribers see 'Trial Ended' / 'Free plan' on desktop after #7496 — consider grandfathering and clearer UX copy #7508

@mdmohsin7

Description

@mdmohsin7

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:

  1. A banner at the top: "Trial Ended — Upgrade to keep unlimited access" with a "View Plans" button.
  2. A usage card reading "30 / 30 — Chat questions on Free plan — Resets in N days", blocking chat at the basic 30/month cap.
  3. (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/trialtrial_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

  • Neo subscriptions created before Enforce Neo = no desktop; fix stale-subscription plan clobber #7496 retain desktop trial-paywall exemption and the correct Neo chat quota on desktop until their current_period_end.
  • Desktop Plan and Usage never shows "Trial Ended" + "30/30 on Free plan" alongside an active paid plan card. For non-desktop-entitled paid plans, show plan-specific copy.
  • Equivalent copy fix on any mobile surface that has the same gap.
  • Unit tests covering: pre-cutoff Neo on desktop (grandfathered), post-cutoff Neo on desktop (paywalled), Operator/Architect on desktop (entitled), basic on desktop (paywalled).

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions