fix(telemetry): attribute API-key usage events to tier + plan_key (#4572)#4573
Conversation
) The limit-abuse audit (wm_api_usage) couldn't attribute API-key requests to a plan: usage.tier was unset on non-tier-gated routes (emitting tier:0 for paid keys), and Starter/Business share tier 2 so couldn't be told apart. Set usage.tier + usage.planKey from the entitlement the #3199 rate-limit block already resolves (enterprise -> tier 3 / plan_key 'enterprise'), and thread a plan_key field through UsageIdentity -> RequestEvent so the audit can compare each customer's rate to their actual cap with no external Convex lookup. Additive (optional field, no Axiom migration). +3 buildUsageIdentity tests. Claude-Session: https://claude.ai/code/session_01SjVX3GyMBmC2XyFWCHogN1
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Greptile SummaryThis PR fixes
Confidence Score: 5/5Purely additive telemetry change; no rate-limiting decisions, eligibility logic, or response paths are touched. Worst case is a null field in Axiom. The diff is 50 lines, all additive. The new plan_key field is nullable throughout, so missing entitlements degrade gracefully to null. The gateway enrichment happens after the existing getEntitlements call, so no new async work is introduced. Enterprise tier is hardcoded to 3 (consistent with the existing ENTERPRISE_API_RATE_LIMIT pattern), and the enterprise plan string fallback is covered by a dedicated test. TypeScript strict mode and three targeted vitest cases validate the wiring end-to-end. No files require special attention. Important Files Changed
Reviews (1): Last reviewed commit: "fix(telemetry): attribute API-key usage ..." | Re-trigger Greptile |
Closes #4572. Follow-up to #3199 / #4563, surfaced while running the shadow-mode limit-abuse audit.
Problem
The audit against Axiom
wm_api_usagecouldn't attribute an API-key request to its plan/caps:usage.tierwas only set on tier-gated routes, so API-key traffic on public routes emittedtier: 0(56,988user_api_keyevents at tier 0 vs 9,452 at tier 2 — the field was unreliable, even though everyuser_api_keyholder is paid tier 2+).tier: 2, so even with tier fixed they're indistinguishable — the audit needed an external Convex/Dodo lookup per customer.Fix
In the #3199 gateway rate-limit block (where
getEntitlements(sessionUserId)is already resolved):usage.tier = ent.features.tier+usage.planKey = ent.planKey(recorded even for downgraded keys); enterprise env keys →tier 3/plan_key 'enterprise'.plan_keyfield throughUsageIdentity→RequestEvent→buildRequestEvent, mirroringauth_kind/customer_id.Additive optional field — no Axiom schema migration. The audit can now group by
customer_id+plan_keyand compare each customer's peak rpm/day to their cap with zero external lookups.Verification
buildUsageIdentityplan_keycases + existing gateway-wiring + entitlement suites unchanged).tsc --noEmit,typecheck:api, biome lint all clean.Risk
Telemetry-only. Worst case a field is null on some path (handled —
plan_keyis nullable). No request-flow impact.https://claude.ai/code/session_01SjVX3GyMBmC2XyFWCHogN1