Skip to content

Commit 032e7cc

Browse files
committed
fix(billing): drop the unreachable card-read deadline from the usage upgrade card
Every exceeded verdict that reaches update-cost now carries its payer, so the deadline-bounded actor subscription lookup could no longer run. Remove the parameter, its call-site argument, the stale TSDoc, and the test that passed without exercising it.
1 parent 9afa8f6 commit 032e7cc

3 files changed

Lines changed: 6 additions & 29 deletions

File tree

‎apps/sim/app/api/billing/update-cost/route.test.ts‎

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1073,23 +1073,6 @@ describe('POST /api/billing/update-cost — mid-run usage gate', () => {
10731073

10741074
expect(body.usageExceeded).toBe(false)
10751075
})
1076-
1077-
it('keeps the exceeded verdict with the plan-upgrade card when the card read outlasts the callback budget', async () => {
1078-
billingPlanMockFns.mockGetHighestPrioritySubscription.mockImplementation(async () => {
1079-
await sleep(1500)
1080-
return { plan: 'pro' }
1081-
})
1082-
const startedAt = Date.now()
1083-
1084-
const body = await (await POST(directCallback())).json()
1085-
1086-
expect(body).toMatchObject({
1087-
success: true,
1088-
usageExceeded: true,
1089-
usageUpgrade: { action: 'upgrade_plan' },
1090-
})
1091-
expect(Date.now() - startedAt).toBeLessThan(1400)
1092-
})
10931076
})
10941077

10951078
describe('a run that outlives its billing period', () => {

‎apps/sim/app/api/billing/update-cost/route.ts‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ function invalidBillingProtocolResponse(requestId: string, span: Span): NextResp
8686
* already recorded when this runs; a gate that cannot answer reports not-exceeded and leaves the
8787
* refusal to the next step or re-check rather than ending a paying run on a database blip,
8888
* and so does a verdict read that outlasts {@link USAGE_STANDING_TIMEOUT_MS}. An exceeded
89-
* verdict always pauses the run; a card read past that budget falls back to the plan-upgrade card.
89+
* verdict always pauses the run.
9090
*/
9191
async function readUsageStanding(
9292
userId: string,
@@ -99,10 +99,9 @@ async function readUsageStanding(
9999
? () => readMidRunAccountUsageVerdict(accountDecision)
100100
: null
101101
if (!isHosted || !readVerdict) return { usageExceeded: false }
102-
const deadlineAt = Date.now() + USAGE_STANDING_TIMEOUT_MS
103102
let verdict: MidRunUsageVerdict
104103
try {
105-
verdict = await withinDeadline(readVerdict, deadlineAt)
104+
verdict = await withinDeadline(readVerdict, Date.now() + USAGE_STANDING_TIMEOUT_MS)
106105
} catch {
107106
logger.warn('Usage standing read outlasted the callback budget; answering not exceeded')
108107
return { usageExceeded: false }
@@ -115,8 +114,7 @@ async function readUsageStanding(
115114
usageUpgrade: await resolveUsageUpgradePayload(
116115
userId,
117116
billingAttribution ?? verdict.payer,
118-
verdict.scope,
119-
deadlineAt
117+
verdict.scope
120118
),
121119
}
122120
}

‎apps/sim/lib/billing/usage-upgrade.ts‎

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { getHighestPrioritySubscription } from '@/lib/billing/core/plan'
66
import type { BillingEntity } from '@/lib/billing/core/usage-log'
77
import { isEnterprise, isPaid } from '@/lib/billing/plan-helpers'
88
import { isOrgScopedSubscription } from '@/lib/billing/subscriptions/utils'
9-
import { withinDeadline } from '@/lib/core/utils/deadline'
109

1110
const logger = createLogger('UsageUpgrade')
1211

@@ -30,13 +29,12 @@ export interface UsageUpgradePayer {
3029
* increase for a paid one, with copy naming who can raise an organization's limit. A member
3130
* over the cap their organization set gets copy naming who can raise that cap. A known payer
3231
* decides the card without a query; otherwise the actor's current subscription decides, and a
33-
* lookup that fails or outlasts `deadlineAt` falls back to the plan-upgrade card.
32+
* lookup that fails falls back to the plan-upgrade card.
3433
*/
3534
export async function resolveUsageUpgradePayload(
3635
userId: string,
3736
payer?: UsageUpgradePayer,
38-
scope?: AttributedUsageLimitsResult['scope'],
39-
deadlineAt?: number
37+
scope?: AttributedUsageLimitsResult['scope']
4038
): Promise<UsageUpgradePayload> {
4139
if (scope === 'member') {
4240
return { reason: 'usage_limit', action: 'increase_limit', message: MEMBER_CAP_MESSAGE }
@@ -48,9 +46,7 @@ export async function resolveUsageUpgradePayload(
4846
plan = payer.payerSubscription?.plan
4947
orgScoped = payer.billingEntity.type === 'organization'
5048
} else {
51-
const subscription = await (deadlineAt === undefined
52-
? getHighestPrioritySubscription(userId)
53-
: withinDeadline(() => getHighestPrioritySubscription(userId), deadlineAt))
49+
const subscription = await getHighestPrioritySubscription(userId)
5450
plan = subscription?.plan
5551
orgScoped = isOrgScopedSubscription(subscription, userId)
5652
}

0 commit comments

Comments
 (0)