Skip to content

feat: gate reset passes on cycle usage, refunds - #3119

Closed
steebchen wants to merge 2 commits into
mainfrom
claude/weekly-reset-limit-restriction-yc2kdk
Closed

steebchen wants to merge 2 commits into
mainfrom
claude/weekly-reset-limit-restriction-yc2kdk

Conversation

@steebchen

@steebchen steebchen commented Jul 18, 2026 •

Copy link
Copy Markdown
Member

Summary

A Reset Pass lifts the weekly premium cap, but the unlocked spend still draws from the plan's monthly credit pool — so near the end of the pool a pass delivers almost nothing, which only confuses (purchase) or frustrates (redeem) users. This PR adds cycle-usage gates around Reset Passes and a self-refund path for unused passes.

Cycle-usage gates

  • Purchase (POST /dev-plans/reset-pass/purchase) is rejected with a 400 once more than 95% of the monthly cycle credit allowance is used — the card is never charged.
  • Redeem (POST /dev-plans/reset-pass/redeem) is rejected once more than 90% of the cycle allowance is used, so a pass can't be burned against an empty pool; the pass keeps until the credits renew.
  • Thresholds and the getDevPlanCycleUsageFraction helper live in @llmgateway/shared so the DevPass dashboard mirrors the server gates (disabled buttons with explanatory tooltips on the Reset Pass card).

Transaction tracking

Reset Pass purchases were already recorded in the transaction table (type: dev_plan_reset_pass with the Stripe payment intent id) — verified, no change needed.

Self-refund of unused passes (7 days)

  • dev_plan_reset_pass is now a self-refundable transaction type with a 7-day window (vs. 14 days for plan payments).
  • Eligible only while the tier-bound purchased inventory still holds a pass; a redeemed pass returns pass_already_used. The tier is recovered from the charged amount, which fulfilment validated against the tier's fixed price.
  • The refund flows through the existing charge.refunded webhook bookkeeping, which claws back the pass and leaves the DevPass subscription untouched; refund also works after the plan ended, since purchased passes survive cancellation.
  • DevPass billing history now offers the refund on eligible pass rows with pass-specific dialog copy; docs updated accordingly.

Testing

  • vitest run on packages/shared/src/dev-plans.spec.ts, apps/api/src/lib/self-refund.spec.ts, apps/api/src/routes/dev-plans-reset-passes.spec.ts (69 tests) plus the full apps/api + packages/shared unit suites (598 passed).
  • pnpm build (all 17 tasks) and pnpm format pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_01E18J9zTY3MiR6SedFgY4aN


Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • Added self-service refunds for unused DevPass Reset Passes purchased within 7 days.
    • Refund eligibility now explains when a pass has expired, was redeemed, or was already refunded.
    • Reset Pass purchases are blocked after more than 95% of the billing-cycle allowance is used.
    • Reset Pass redemption is blocked after more than 90% usage to help prevent wasted passes.
    • Updated dashboard refund dialogs, confirmations, tooltips, and purchase/redeem controls.
  • Documentation

    • Documented Reset Pass refund terms and usage-based purchase and redemption safeguards.

Block buying a Reset Pass above 95% of the monthly cycle credit
allowance and redeeming one above 90%, since a pass restores a
weekly cap with nothing left to spend against. Purchases were
already tracked in the transaction table; unused passes can now
be self-refunded within 7 days of purchase (tier-bound inventory
must still hold the pass), leaving the DevPass plan untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E18J9zTY3MiR6SedFgY4aN
Copilot AI review requested due to automatic review settings July 18, 2026 12:14
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jul 18, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: daf71a5d-3929-418c-883b-ca5b4710f50f

📥 Commits

Reviewing files that changed from the base of the PR and between 9108329 and 30b901a.

📒 Files selected for processing (14)
  • apps/api/src/lib/self-refund.spec.ts
  • apps/api/src/lib/self-refund.ts
  • apps/api/src/routes/dev-plans-reset-passes.spec.ts
  • apps/api/src/routes/dev-plans.ts
  • apps/api/src/routes/organization.ts
  • apps/code/src/app/dashboard/components/DevPassInvoices.tsx
  • apps/code/src/app/dashboard/components/ResetPassCard.tsx
  • apps/code/src/app/dashboard/components/UsageOverview.tsx
  • apps/docs/content/learn/reset-passes.mdx
  • apps/ui/src/app/dashboard/[orgId]/org/transactions/page.tsx
  • apps/ui/src/components/billing/transactions-client.tsx
  • packages/shared/src/dev-plans.spec.ts
  • packages/shared/src/dev-plans.ts
  • packages/shared/src/index.ts

Walkthrough

Reset Passes now have cycle-usage safeguards for purchase and redemption, seven-day self-refund eligibility with tier and usage validation, expanded API reason types, updated dashboard messaging, tests, and documentation.

Changes

Reset Pass safeguards and refunds

Layer / File(s) Summary
Cycle usage threshold contract
packages/shared/src/dev-plans.ts, packages/shared/src/index.ts, packages/shared/src/dev-plans.spec.ts
Defines and exports cycle-usage thresholds and a helper for calculating usage fractions, with coverage for invalid inputs and threshold relationships.
Purchase and redemption cycle gates
apps/api/src/routes/dev-plans.ts, apps/api/src/routes/dev-plans-reset-passes.spec.ts
Blocks Reset Pass purchases above 95% cycle usage and redemptions above 90%, with boundary tests for rejected and accepted requests.
Reset Pass self-refund eligibility
apps/api/src/lib/self-refund.ts, apps/api/src/lib/self-refund.spec.ts, apps/api/src/routes/organization.ts, apps/api/src/routes/dev-plans.ts
Adds seven-day Reset Pass refunds, tier-bound inventory checks, pass_already_used, and related schema and endpoint documentation updates.
Dashboard controls and messaging
apps/code/src/app/dashboard/components/ResetPassCard.tsx, apps/code/src/app/dashboard/components/UsageOverview.tsx, apps/code/src/app/dashboard/components/DevPassInvoices.tsx, apps/ui/src/..., apps/docs/content/learn/reset-passes.mdx
Disables gated purchase and redemption actions, updates refund copy and dialogs, adds the new reason type, and documents the safeguards and refund policy.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Dashboard
  participant purchaseResetPass
  participant getDevPlanCycleUsageFraction
  Dashboard->>purchaseResetPass: request Reset Pass purchase
  purchaseResetPass->>getDevPlanCycleUsageFraction: calculate cycle usage
  getDevPlanCycleUsageFraction-->>purchaseResetPass: return usage fraction
  purchaseResetPass-->>Dashboard: allow purchase or return 95% usage error
Loading

Possibly related PRs

Suggested reviewers: copilot, smakosh

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: Reset Pass cycle-usage gating and refund support.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/weekly-reset-limit-restriction-yc2kdk

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@steebchen steebchen closed this Jul 18, 2026
@steebchen
steebchen deleted the claude/weekly-reset-limit-restriction-yc2kdk branch July 18, 2026 15:56
pull Bot pushed a commit to soitun/llmgateway that referenced this pull request Jul 18, 2026
## What

Combines two related Reset Pass safeguards (this PR now includes theopenco#3119):

A Reset Pass lifts the weekly premium cap, but the unlocked spend still
draws from the plan's **monthly credit pool** — so near or at the end of
the pool a pass delivers little or nothing. This PR gates
purchase/redeem on cycle usage, replaces the pass card with an
upgrade/PAYG promo once the pool is fully exhausted, and adds a
self-refund path for unused passes.

## Cycle-usage gates (server + mirrored in UI)

- **Purchase** rejected with 400 above **95%** cycle usage — the card is
never charged. Buy button disabled with an explanatory tooltip.
- **Redeem** rejected above **90%** cycle usage so a pass can't be
burned against an empty pool; the pass keeps until credits renew. Redeem
button disabled with tooltip.
- Thresholds + `getDevPlanCycleUsageFraction` live in
`@llmgateway/shared`, shared by API and dashboard.
- The gated card is not a dead end: once redeeming is blocked (>90%), it
shows a visible explanation and a primary CTA — upgrade to the next tier
(Lite/Pro) or PAYG credits on llmgateway.io (Max) — matching the 100%
promo. PostHog event `devpass_reset_gate_upgrade_clicked`.

## 100% exhausted → promo instead of passes

When the monthly allowance is fully used ($87 Lite / $237 Pro / $537
Max), the Reset Pass card is hidden entirely and replaced with a
passport-style promo:

- **Lite/Pro** → upgrade CTA to the next tier (`/dashboard/billing`),
highlighting that upgrading starts a fresh billing cycle immediately
with the full new allowance.
- **Max** → PAYG CTA to llmgateway.io, highlighting it works with the
same coding agents — just swap the API key and buy credits.
- Usage-bar and weekly-meter copy adjusted per state; PostHog events
`devpass_allowance_exhausted_viewed` / `..._promo_clicked`.

## Self-refund of unused passes (7 days)

- `dev_plan_reset_pass` is now self-refundable with a **7-day** window
(vs 14 for plan payments), only while the tier-bound inventory still
holds a pass; a redeemed pass returns `pass_already_used`.
- Refund flows through the existing `charge.refunded` webhook
bookkeeping (claws back the pass, leaves the DevPass subscription
untouched); works after plan cancellation since purchased passes survive
it.
- DevPass billing history offers the refund on eligible rows with
pass-specific dialog copy; ineligible rows explain why (redeemed / 7-day
window expired / already refunded). Docs updated.

## Testing

- `dev-plans-reset-passes.spec.ts` (32), `self-refund.spec.ts` (30),
`packages/shared/dev-plans.spec.ts` (8) — 70/70 passing.
- Full `pnpm build` (17 tasks) + `pnpm format` pass.
- All dashboard states verified live; demo videos in session (promo
cases + refund cases).

https://claude.ai/code/session_011UftFFQDksranqTiWPNMBb

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added an “allowance reached” card and updated dashboard usage
messaging/CTAs when monthly credits are exhausted.
- Added cycle-usage boundary gating for Reset Pass purchase/redemption
(redeem ~90%, purchase ~95%); buttons/copy adjust accordingly.
- **Bug Fixes**
- Blocked Reset Pass purchase/redemption when monthly usage is above the
configured thresholds, with clearer boundary behavior.
- Improved self-refund eligibility to reject already-used passes and
updated refund UI/tooltips accordingly.
- **Documentation**
- Refreshed Reset Pass docs to describe the new monthly threshold
behavior and refund timing.
- **Tests**
- Expanded coverage for cycle-usage gates and self-refund eligibility
reasons.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants