fix(billing): enforce the plan usage limit mid-run and bill runs that outlive their period - #8461
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
All reported issues were addressed across 26 files
Tip: instead of fixing issues one by one fix them all with cubic
Re-trigger cubic
|
|
@cubic-dev-ai review this PR |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
All reported issues were addressed across 27 files
Reply with feedback, questions, or to request a fix.
Fix all with cubic | Re-trigger cubic
|
@cubic-dev-ai review this PR |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
All reported issues were addressed across 28 files
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.
Fix all with cubic | Re-trigger cubic
|
@cubic-dev-ai review this PR |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
No issues found across 28 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.
Re-trigger cubic
|
@cubic-dev-ai review this PR |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
No issues found across 28 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.
Re-trigger cubic
c51ff3e to
0972f66
Compare
|
@cubic-dev-ai review this PR |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
All reported issues were addressed across 32 files
You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.
Fix all with cubic | Re-trigger cubic
…and in A reporting-window or default-period payer's charges never roll forward, so after its admitted window ends the mid-run verdict judged an empty new window and under-enforced the limit. Both the attributed and direct-v1 verdicts now judge the current period only for a Stripe payer, matching the cost callback's rollover gate, and the admitted period otherwise, even after it ends. Stripe payers keep being judged against their current period.
|
@cubic-dev-ai review this PR |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
No issues found across 32 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.
Re-trigger cubic
…ck calls - The account block, continuation delegation, cache, billing-off and rollover tests assert the verdict or HTTP response. Where behaviour depends on an input, the fake answers by that input, as the real ledger and settlement do. - Pins against real PostgreSQL that a reporting run's top-ups after its window ends are counted in that window, where its request was first charged, and a later run's charges in the next.
|
@cubic-dev-ai review this PR |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
There was a problem hiding this comment.
All reported issues were addressed across 32 files
You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.
Fix all with cubic | Re-trigger cubic
…retry, and make the reporting-window test deterministic - A new turn's 402 is empty again and the stream no longer parses 402 bodies: the worker replaces any validation 402 body with its own message and only polls continuation, so the new-turn codes, USAGE_UNAVAILABLE and the server-side refusal reasons had no consumer. - The mid-run verdict reads its current period once; a period that ends during the read is left to the next callback. - The cumulative-usage '@' check left the ledger; the cost callback already refuses such keys. - The reporting-window integration test derives its boundary from the first row's created_at and waits on the database clock.
|
@cubic-dev-ai review this PR |
@waleedlatif1 I have started the AI code review. It will take a few minutes to complete. |
Comments Outside DiffThese findings could not be posted inline.
|
There was a problem hiding this comment.
No issues found across 31 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
You've manually re-run cubic several times on this PR. Each manual re-review checks the full PR again and counts toward your usage quota. To preserve your usage limits, we recommend letting cubic automatically review new commits.
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.
Re-trigger cubic
|
Re: the outside-diff P1 "Blocked accounts get upgrade cards" ( This is not a change introduced by this PR, and no producer of a
Showing a distinct blocked-account message on this path needs the worker and gateway to pass Sim's refusal code through. That is a separate cross-repo change, tracked as a follow-up. The continuation path this PR adds does send and consume |
Summary
Chat runs are moving off a fixed wall-clock deadline, so spend has to be bounded by the plan's usage limit while a run is in progress, not only when it starts. This PR adds Sim's side of mid-run enforcement and makes sure a run that outlives its billing period is still invoiced exactly once.
Mid-run usage verdict
POST /api/billing/update-costnow returnsusageExceeded(and, when true, ausageUpgradecard payload) at the top level of every answer: the 200 and the duplicate 409. The verdict is read through the cached execution usage gate, so a run under its limit pays no extra ledger read on most steps. Older workers ignore the fields.update-costanswers for direct-v1 runs too, judging the payer saved in the run's account decision. The verdict read is bounded to 1 s, well inside the worker's 5 s callback timeout, and answers not-exceeded past it.POST /api/copilot/api-keys/validate,purpose: "continuation") also reads the original payer's spend, for attributed and direct-v1 runs alike, so a worker can poll it on a cadence. An admitted direct-v1 verdict is cached like an attributed one. A continuation 402 carries a body declared in the contract:{ code: "USAGE_LIMIT_EXCEEDED", error, usageUpgrade }{ code: "BILLING_BLOCKED", error }usageUpgradeis present exactly whenusageExceededis true.Card and blocked accounts
Fail-open mid-run, fail-closed at admission
Runs that outlive their billing period
@, so a request's period row keys never collide with another request's.Other
usageExceeded,UsageUpgrade,UsageLimitRefusal).Worker contract
usageExceededandusageUpgradefrom the top level of the update-cost answer.USAGE_LIMIT_EXCEEDED, write<usage_upgrade>{usageUpgrade}</usage_upgrade>as assistant text into the durable log, thencomplete. On a 402 withBILLING_BLOCKED(or no body), do not show the usage card.Test plan
update-cost/route.integration.ts): a direct-v1 run across a Stripe rollover records its later spend in the current period (before this, the callback failed settlement and the spend was lost).bun run test:integration(the PostgreSQL integration job) passes locally.bun run lint,bun run type-check,bun run check:audits(includingcheck:api-validation:strict),bun run mship-contracts:check.