chore(credits): retire getGrantExpiresAt and the expires_at it feeds - #838
Conversation
getGrantExpiresAt existed only to tell an admin when the monthly reset would destroy a grant, and carried 20 lines of month-clamping comment explaining which direction it errs in. Now that the refill is a floor and cannot reduce a balance (recoupable/chat#1960), the value it computes describes an event that no longer happens, and leaving it in place tells admins to re-grant credits they do not need to re-grant. - Deleted lib/credits/getGrantExpiresAt.ts and its test. - POST /api/admins/credits no longer returns expires_at. Its JSDoc now says the grant holds until it is spent. Breaking for admin callers reading expires_at, which is an internal, admin-only surface. Must merge AFTER the refill-is-a-floor fix; until that ships a refill still reduces balances and a grant genuinely does expire.
|
Warning Review limit reached
Next review available in: 11 minutes Limit details: You’ve used all 1 included review currently available under your plan. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (2)
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. Comment |
There was a problem hiding this comment.
No issues found across 4 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Architecture diagram
sequenceDiagram
participant Admin as Admin Client
participant API as POST /api/admins/credits
participant Handler as postAdminCreditsHandler
participant Validate as validateGrantCreditsRequest
participant Audit as grantCreditsWithAudit
participant DB as Supabase
Note over Admin,DB: Admin Grant Credits Flow (current state)
Admin->>API: POST /api/admins/credits
API->>Handler: Forward request
Handler->>Validate: Validate grant payload
Validate-->>Handler: Validated grant data
Handler->>Audit: grantCreditsWithAudit(validated)
Audit->>DB: Atomic write + audit record
DB-->>Audit: Grant record (created_at, reason, granted_by)
Audit-->>Handler: Grant result
Handler-->>API: 200 with grant fields (no expires_at)
API-->>Admin: {status, grant_id, account_id, remaining_credits, previous_credits, reason, granted_by, granted_at}
Note over Handler,Admin: Admin grant holds until balance is spent<br/>No expiry reported - refill is a floor
Requires human review: This PR removes the expires_at field from the admin credits API response, a breaking contract change requiring human sign-off for coordination with consumers and the associated docs update.
Re-trigger cubic
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
There was a problem hiding this comment.
0 issues found across 2 files (changes from recent commits).
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Requires human review: Removes expires_at from the admin grant API response — a breaking contract change for callers. The decision also depends on the unverified claim in #837 that the refill is a floor; this diff can't confirm that behavior, so a human should sign off.
Re-trigger cubic
Preview verificationTested the PR-head preview ( Documented vs actual
Prod contrast, and why this should merge promptlyThe identical grant against prod (old code) returns 9 fields including Ready to merge — the last PR in chat#1960's matrix. |
Follow-on cleanup for recoupable/chat#1960. Row 6 of that issue's PR matrix.
getGrantExpiresAt.tsexists only to tell an admin when the monthly reset will destroy a grant. It is 14 lines of code under 20 lines of comment explaining which direction its month-clamping errs in, all of it reasoning about an overwrite that no longer happens once the refill is a floor. Worse than dead: it tells admins to re-grant credits that do not need re-granting.What changes
Deleted:
lib/credits/getGrantExpiresAt.tsandlib/credits/__tests__/getGrantExpiresAt.test.ts.POST /api/admins/creditsno longer returnsexpires_at. Response goes from 9 fields to 8:{ "status": "success", "grant_id": "...", "account_id": "...", "remaining_credits": 9999, "previous_credits": 12, "reason": "Trial headroom for the Aug 12 label demo", "granted_by": "...", "granted_at": "2026-08-06T23:00:00.000Z" }Breaking for admin callers reading
expires_at. This is an internal, admin-only surface. ThepostAdminCreditsHandlerJSDoc now states that the grant holds until it is spent, replacing the "including when it expires" line.Verification
TDD, red before green. Added
it("no longer reports an expires_at, because a grant cannot be reduced by a refill")and removedexpires_atfrom the documented-response-shape assertion. Ran it: RED, 2 failed (expected { status: 'success', …(8) } to not have property "expires_at", and the shape test showing+ "expires_at": "2026-09-06T23:00:00.000Z"). Implemented, then GREEN.vitest run lib/admins/credits lib/creditseslint lib/admins lib/creditstsc --noEmitgrep -rn getGrantExpiresAt lib appThe remaining 6 tests in
postAdminCreditsHandler.test.ts(atomic write pass-through, nullprevious_credits, 401/403/400 pass-through, 404 unknown account, 500 on write failure, no error-message leak) pass unmodified.Not yet done: hitting
POST /api/admins/creditson the preview to confirm the live response carries 8 fields and noexpires_at. Flagging rather than implying it.Merge order
api#837 → this PR → docs#300, which removes
expires_atfromAdminGrantCreditsResponseand rewrites the grant-expiry paragraph. The docs PR is the one surface that must not land before both api PRs are on prod.Summary by cubic
Removes grant-expiry logic and stops returning
expires_atfromPOST /api/admins/credits, because the monthly refill is now a floor. Previously the endpoint returnedexpires_atand implied grants expire; now the field is omitted and grants persist until spent.lib/credits/getGrantExpiresAt.tsand its test; removes its usage and updatespostAdminCreditsHandlerJSDoc to the present-tense grant contract.expires_at.api#837(refill-is-a-floor).expires_atfromPOST /api/admins/credits.Written for commit 62fbe8e. Summary will update on new commits.