fix(email): restore billing_period_stats cron and fix period calculation#2755
Conversation
…math The billing period stats processor existed but was never added to cron_tasks after the cron refactor, so org:billing_period_stats was not queued. Register the daily 12:00 UTC job, restore service_role execute, and align metrics/credits to the half-open billing cycle. Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 5 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. 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: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughThe billing-period statistics email flow now uses UTC-safe date boundaries, half-open billing windows, an RPC for credit aggregation, updated metadata, anniversary-based cron scheduling, and end-to-end and unit test coverage. ChangesBilling period statistics email
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant CronTask
participant process_billing_period_stats_email
participant cron_email
participant handleBillingPeriodStats
participant get_total_metrics
participant get_org_credits_used_in_period
CronTask->>process_billing_period_stats_email: run billing anniversary check
process_billing_period_stats_email->>cron_email: enqueue billing_period_stats job
cron_email->>handleBillingPeriodStats: process cycle dates
handleBillingPeriodStats->>get_total_metrics: fetch period metrics
handleBillingPeriodStats->>get_org_credits_used_in_period: fetch credits in half-open window
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Comment |
Merging this PR will not alter performance
Comparing Footnotes
|
Align the SQL test with other cron email tests (postgres/pgmq access) and explicitly revoke anon/authenticated execute on the new functions. Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_a28f4540-5afc-4bda-9756-011a3c66853c) |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@supabase/functions/_backend/triggers/cron_email.ts`:
- Around line 483-497: Regenerate the Supabase types with bun types so
get_org_credits_used_in_period is available in the generated Database
definitions, then remove the (supabase.rpc as any) cast and use the typed RPC
call. In the credits lookup branch, do not continue with creditsUsed set to zero
when creditsError occurs; propagate or otherwise abort the billing-email flow so
failed credit retrieval cannot produce a misleading zero-credit report.
In
`@supabase/migrations/20260725112951_register_billing_period_stats_email_cron.sql`:
- Around line 44-63: Update the billing anniversary and previous-cycle
calculations around v_anniversary, v_prev_cycle_start, and v_prev_cycle_end to
handle anchors on the 29th–31st when the current or previous month is shorter,
clamping to that month’s final valid day or restoring the prior CASE rollover
behavior. Ensure February month-end anniversaries are recognized without
shifting the cycle by a month, and add a test covering this case.
In `@supabase/tests/63_test_billing_period_stats_email.sql`:
- Around line 12-15: The test currently verifies only that
get_org_credits_used_in_period exists. Add a functional case that seeds
usage_credit_consumptions at p_start, just before p_end, and exactly at p_end,
then assert the function’s expected sum includes the first two rows and excludes
the p_end row.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 49f8fbc8-ed5b-401b-b4ee-c1579486d637
📒 Files selected for processing (4)
supabase/functions/_backend/triggers/cron_email.tssupabase/migrations/20260725112951_register_billing_period_stats_email_cron.sqlsupabase/tests/63_test_billing_period_stats_email.sqltests/billing-period-stats.unit.test.ts
🔗 Linked repositories identified
CodeRabbit considers these linked repositories for cross-repo context during reviews:
Cap-go/capacitor-updater(manual)
Restore yesterday-based cycle math for month-end anchors, fail the email handler when credit lookup errors, type the new credits RPC, and cover half-open credit bounds in pgTAP. Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_6c382b26-5f72-4005-b0d2-b4717469318b) |
There was a problem hiding this comment.
All reported issues were addressed
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Pass original cycleStart/cycleEnd timestamps into the credits RPC so non-midnight Stripe anchors do not under/over-count credit usage. Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_17d75838-a9d1-457c-a25e-759e7ea4905b) |
Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_e5d26530-a242-43ea-b57b-64fa8927bab4) |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_37837399-67c1-4b6c-9889-057f68f38b2c) |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_d918e308-32a8-4e02-bc9a-159632bb98b7) |
There was a problem hiding this comment.
Stale comment
Risk: medium. Not approving: Cursor Bugbot skipped (usage limit reached), so automated review did not complete, and this billing/cron migration exceeds the low-risk approval threshold. Human review is still needed; reviewers are already assigned.
Sent by Cursor Approval Agent: Pull Request Approver External
Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_e9fb4913-0f43-4cae-99d5-529032236235) |
There was a problem hiding this comment.
Stale comment
Risk: medium. Not approving: Cursor Bugbot skipped (usage limit reached), so automated review did not complete, and this billing/cron migration exceeds the low-risk approval threshold. Human review is still needed; reviewers are already assigned.
Sent by Cursor Approval Agent: Pull Request Approver External
There was a problem hiding this comment.
All reported issues were addressed across 2 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
Preserve day-of-month anniversary detection in UTC, but end periods at UTC midnight so the 12:00 UTC job never reports an unfinished cycle when Stripe anchors are later in the day. Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_bcaaeb52-08c4-426b-955a-166f291ee417) |
There was a problem hiding this comment.
Stale comment
Risk: medium. Not approving: Cursor Bugbot skipped (usage limit reached), so automated review did not complete, and this billing/cron migration exceeds the low-risk approval threshold. Human review is still needed; reviewers are already assigned.
Sent by Cursor Approval Agent: Pull Request Approver External
Add an independent oracle covering every DOM and day across 2024-2026, plus contiguous month-end pgTAP chains, so anniversary skips, overlaps, and metrics off-by-ones are caught before customers see bad numbers. Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_9aa43fc5-28d0-4743-b15a-9954dc4af563) |
There was a problem hiding this comment.
Stale comment
Risk: medium. Not approving: Cursor Bugbot skipped (usage limit reached), so automated review did not complete, and this billing/cron migration exceeds the low-risk approval threshold. Human review is still needed; reviewers are already assigned.
Sent by Cursor Approval Agent: Pull Request Approver External
Co-authored-by: Martin DONADIEU <martindonadieu@gmail.com>
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_c5a4350c-7587-4478-a89f-9dda8c185f70) |
There was a problem hiding this comment.
Risk: medium. Not approving: Cursor Bugbot skipped (usage limit reached), so automated review did not complete, and this billing/cron migration exceeds the low-risk approval threshold. Human review is still needed; reviewers are already assigned.
Sent by Cursor Approval Agent: Pull Request Approver External
|





Summary (AI generated)
process_billing_period_stats_email()existed but was never registered incron_tasksafter the cron refactor, soorg:billing_period_statswas never queued (matches “not sent in last 30 days”).service_roleexecute grant.get_cycle_info_organchor-day logic.[start, end); metrics now use inclusive endend - 1 day(previously included the first day of the next cycle).get_org_credits_used_in_periodRPC (avoids PostgREST 1000-row undercount).Motivation (AI generated)
Billing anniversary stats emails stopped firing after the move to table-driven cron tasks. Customers and Capgo lost the renewal-day usage/upgrade email, and the period bounds used for metrics/credits were inconsistent.
Business Impact (AI generated)
Restores a billed-org engagement/upsell email on each renewal day with more accurate usage numbers, so plan recommendations are based on the completed cycle instead of leaking the next cycle’s first day or truncating credit sums.
Test Plan (AI generated)
tests/billing-period-stats.unit.test.ts)supabase/tests/63_test_billing_period_stats_email.sql(cron registration, anniversary queue, non-anniversary skip, grants)cron_taskshasbilling_period_stats_emailenabled at hour 12cron_emailmessage withtype=billing_period_statsand correctcycleStart/cycleEndorg:billing_period_statswith expected metadataGenerated with AI
Summary by CodeRabbit
New Features
Bug Fixes
Tests