Summary
src/lib/notification/tasks/cost-alert.ts has two gaps that cause incorrect alert behavior after quota resets and missing alerts for total/daily limits.
Problem 1: costResetAt not considered
The cost alert system queries raw time ranges without clipping by costResetAt:
// current (cost-alert.ts)
const cost5h = await sumKeyCostInTimeRange(keyData.id, range5h.startTime, range5h.endTime);
In contrast, rate-limit-guard.ts and all quota display paths correctly clip the start time:
// rate-limit-guard.ts (correct)
const keyCostResetAt = resolveKeyCostResetAt(key.costResetAt ?? null, user.costResetAt ?? null);
const clipStart = (start: Date) => costResetAt > start ? costResetAt : start;
Impact: After an admin resets a user's or key's quota, the rate limiter correctly counts from zero, but the alert system still fires based on pre-reset usage. Users receive false "approaching quota" notifications.
This affects both user-level costResetAt (existing) and key-level costResetAt (new in feat/key-cost-reset).
Problem 2: limitTotalUsd and limitDailyUsd not checked
The alert query only selects three limit types:
const keysWithLimits = await db.select({
limit5h: keys.limit5hUsd,
limitWeek: keys.limitWeeklyUsd,
limitMonth: keys.limitMonthlyUsd,
// limitTotalUsd - missing
// limitDailyUsd - missing
}).from(keys).where(
sql`${keys.limit5hUsd} > 0 OR ${keys.limitWeeklyUsd} > 0 OR ${keys.limitMonthlyUsd} > 0`
);
Impact: Keys with limitTotalUsd or limitDailyUsd set will never receive approaching-quota alerts for those periods.
Suggested Fix
- Join with
users table to get user.costResetAt, and select key.costResetAt
- Use
resolveKeyCostResetAt() to compute effective reset time per key
- Clip all time range starts with
clipStart() before querying costs
- Add
limitTotalUsd check using sumKeyTotalCost(keyHash, Infinity, resolvedResetAt)
- Add
limitDailyUsd check using sumKeyCostInTimeRange with daily time range (respecting dailyResetTime and dailyResetMode)
Affected Files
src/lib/notification/tasks/cost-alert.ts
Summary
src/lib/notification/tasks/cost-alert.tshas two gaps that cause incorrect alert behavior after quota resets and missing alerts for total/daily limits.Problem 1: costResetAt not considered
The cost alert system queries raw time ranges without clipping by
costResetAt:In contrast,
rate-limit-guard.tsand all quota display paths correctly clip the start time:Impact: After an admin resets a user's or key's quota, the rate limiter correctly counts from zero, but the alert system still fires based on pre-reset usage. Users receive false "approaching quota" notifications.
This affects both user-level
costResetAt(existing) and key-levelcostResetAt(new in feat/key-cost-reset).Problem 2: limitTotalUsd and limitDailyUsd not checked
The alert query only selects three limit types:
Impact: Keys with
limitTotalUsdorlimitDailyUsdset will never receive approaching-quota alerts for those periods.Suggested Fix
userstable to getuser.costResetAt, and selectkey.costResetAtresolveKeyCostResetAt()to compute effective reset time per keyclipStart()before querying costslimitTotalUsdcheck usingsumKeyTotalCost(keyHash, Infinity, resolvedResetAt)limitDailyUsdcheck usingsumKeyCostInTimeRangewith daily time range (respectingdailyResetTimeanddailyResetMode)Affected Files
src/lib/notification/tasks/cost-alert.ts