feat(balances): measure usage alerts per basis and fire on usage limits - #3248
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
f1e5758 to
8886845
Compare
8886845 to
4b28aad
Compare
4b28aad to
3629496
Compare
There was a problem hiding this comment.
All reported issues were addressed
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
3629496 to
474aac6
Compare
474aac6 to
47304e5
Compare
47304e5 to
d9a52c1
Compare
d9a52c1 to
a21c8fa
Compare
a21c8fa to
3c3af43
Compare
204541d to
b8228d4
Compare
There was a problem hiding this comment.
All reported issues were addressed across 6 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
329902c to
b273ae7
Compare
There was a problem hiding this comment.
All reported issues were addressed across 5 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
7751383 to
85248f1
Compare
ee008e9 to
845177c
Compare
845177c to
a166e1c
Compare
There was a problem hiding this comment.
All reported issues were addressed across 23 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
checkUsageAlerts becomes resolve → measure → wasThresholdCrossed → send,
one decision per file under usageAlerts/check. A measurer per basis
turns the tracked subjects into { usage, denominator, remaining }:
balance bases read the breakdown, usage_limit reads the window counter
of the cap sharing the alert's feature and filter, both sides at the
request clock so a rolled window reads 0 before the event.
The webhook is a typed union on usage_alert.basis carrying a balance or
usage_limit block; the idempotency key adds basis, filter and window
start. Entity subjects keep customer-scope window rows after deduction
so an inherited cap can fire on an entity track.
…e-aware alert tests and dashboard scenario
e23f808 to
e26c006
Compare
Layer 4 of 6 (firing). Base: #3259, the pure move; this diff is the logic change on the moved file.
checkUsageAlertsmoves tobalances/usageAlerts/check/as resolve → measure →wasThresholdCrossed→ send.denominator: null(unlimited, included = 0, limit 0) skips percentage thresholds.usage_limitreads both subjects' window counters at onenow, so a rolled window measures 0 before the event and never fires a falseremainingalert; it re-fires each window.usage_alert.basis,usage_alert.filter, and abalanceorusage_limitblock. Idempotency key adds basis, filter key and window start.usage_limitalerts log and skip there.applyUsageWindowUpdatesToFullSubjectdropped customer-scope rows from entity subjects, so a cap inherited from the customer could never fire on an entity track.apiBalanceV1ToIncludedGrant,apiBalanceV1ToRecurringGrant(one-off grants reportreset.interval: "one_off", not null, so recurring excludes that interval).Tests:
usage-alert-basis.test.ts(green locally),usage-alert-usage-limit.test.ts(13 cases; not yet run clean, see below), unit tests for the crossing check.Local runs of the usage-limit file were blocked by the dev API resolving its secret-key cache through the shared cloud Dragonfly, where another stack on a different DB branch had cached the test org's feature ids; every product create then failed on
entitlements_internal_feature_id_fkey. That is dev infra, not this change.Summary by cubic
Usage alerts now measure against the configured basis—
balance,included,recurring, orusage_limit—instead of always the aggregate balance, so windowed caps can trigger and re-fire alerts each window. The webhook payload carries the basis plus exactly one matchingbalanceorusage_limitblock, built as a typed union so consumers can narrow safely.usage_limitalerts match the enforced cap by feature and filter, stay dormant when the cap is missing, disabled, unlimited, or zero, and measure both window counters at the request timestamp so a rolled window never fires a false remaining alert.recurringdenominators, and deduction paths without full subjects skipusage_limitalerts.Written for commit e26c006. Summary will update on new commits.
Greptile Summary
The PR restructures usage-alert processing into scope resolution, basis-specific measurement, threshold evaluation, and webhook delivery.
Confidence Score: 4/5
The PR is not yet safe to merge because customer- or plan-scoped alerts can be silently skipped when an entity-owned cap gates the tracked event.
The usage-limit lookup filters customer and plan alerts to customer-scoped counters even though entity tracking can be gated by an entity-scoped cap, leaving no measurement and therefore no webhook when that cap crosses the configured threshold.
Files Needing Attention: server/src/internal/balances/usageAlerts/check/measure/findUsageWindowLimitForAlert.ts
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart LR T[Track usage] --> R[Resolve alert scopes] R --> M[Measure configured basis] M --> C[Check threshold crossing] C -->|crossed| W[Build and send webhook] C -->|not crossed| S[Skip]Prompt To Fix All With AI
Reviews (17): Last reviewed commit: "refactor(balances): basis default and ba..." | Re-trigger Greptile
Context used: