fix(platform): show NO_TIER in admin rate-limit display + aggregate reconciliation alerting into one Discord alert - #13291
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds a NO_TIER subscription state and multiplier-driven labels to the rate-limit admin UI (wired from subscription status and covered by tests). Backend Stripe reconciliation stops per-user Discord alerts for lazy reconciles, logs discrepancies at INFO, reformats sweep alerts into untruncated per-user bullets at WARNING, and updates tests. ChangesNO_TIER tier state support
Stripe reconciliation alerting and logging
Sequence Diagram(s)sequenceDiagram
participant Reconcile as reconcile_stripe_tier_for_user
participant Logger as log_tier_reconciliation_discrepancy
participant Sweep as _alert_sweep_discrepancies
participant Chunker as SendDiscordMessageBlock
participant Alert as alert_tier_reconciliation_discrepancy
Reconcile->>Logger: record discrepancy (INFO, via="lazy-reconcile")
Note right of Reconcile: lazy reconcile paths do not await per-user Alert
Reconcile--xAlert: no per-user alert for lazy reconcile
Sweep->>Chunker: build header + bullets (user_id, previous→new, direction)
Chunker->>Alert: send WARNING message part i/N
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## dev #13291 +/- ##
==========================================
+ Coverage 72.69% 72.71% +0.01%
==========================================
Files 2355 2358 +3
Lines 175563 175736 +173
Branches 17760 17779 +19
==========================================
+ Hits 127624 127778 +154
- Misses 44166 44180 +14
- Partials 3773 3778 +5
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
… system alert Replace per-user Sentry events with a single Discord (PLATFORM) system alert per sweep that lists the affected user IDs and a 'reconciled N accounts (X upgraded, Y downgraded)' summary. Per-discrepancy logging drops from ERROR (one Sentry event per user) to INFO + PostHog metric; the lazy on-access path no longer pings ops per-user. Steady state stays silent.
|
Added a second commit (per request, consolidating from the now-closed #13292):
Follow-up to the merged reconciliation work (#13284). The sweep previously emitted a per-user Tests: sweep asserts the aggregate message + user-id list; lazy/steady-state assert no per-user ping. 329 backend tests green;
|
🔍 PR Overlap DetectionThis check compares your PR against all other open PRs targeting the same branch to detect potential merge conflicts early. 🟢 Low Risk — File Overlap OnlyThese PRs touch the same files but different sections (click to expand)
Summary: 0 conflict(s), 0 medium risk, 5 low risk (out of 5 PRs with file overlap) Auto-generated on push. Ignores: |
…lert Discord-only system alert (WARNING log, no Sentry): count header up front (reconciled N: X upgraded, Y downgraded), then the FULL affected-user list at the end — each line 'user_id from_tier -> to_tier (direction)' — chunked across messages to respect Discord's 2000-char limit instead of truncating at 25.
…t failures - Admin rate-limit page shows live LD/config-driven multipliers (e.g. MAX 42.66x) read from /credits/subscription tier_multipliers, instead of hardcoded numbers; NO_TIER shows 'no access (paywalled)', missing tiers fall back gracefully. - Reconciliation Discord-alert failures now log at ERROR (-> Sentry) with the FULL alert content (count + user list + tier changes), so a broken bot token / gateway timeout surfaces loudly with the payload instead of failing silently.
…Block splits SendDiscordMessageBlock.chunk_message already splits any >2000-char message, so the custom _chunk_alert was redundant — and worse: looping the alert helper per chunk opened a new bot login/gateway connection per chunk. Send one full message (header + complete affected-user list) and let the block split it once.
… map (incl ENTERPRISE) The admin User Rate Limits page showed the generic "tier limits" label for ENTERPRISE (and any tier without a Stripe price) because the multiplier data came from /credits/subscription tier_multipliers, which the backend filters to priceable/priced tiers only. Surface the full per-tier multiplier map on the admin /rate_limit response via get_tier_multipliers() and read it on the admin page instead of the subscription endpoint, so admin-managed tiers (ENTERPRISE, etc.) render their real multiplier.
Why / What / How
Why: The admin "User Rate Limits" page rendered
NO_TIERusers as BASIC.NO_TIERwas not part of the component's known tier list, so the unknown-tier fallback masked it asBASIC. During the payments launch this is actively misleading — a paywalled / no-access user appears to have BASIC access. Concretely, aNO_TIERtester showed up in the admin UI asBASIC, hiding the fact that they had no access.What: Handle
NO_TIERas a first-class tier inRateLimitDisplay(badge, dropdown option, label, color) and make it the safe fallback for unknown/missing tiers instead ofBASIC.How:
NO_TIERas the first entry of theTIERStuple.NO_TIER: "no access (paywalled)"toTIER_MULTIPLIERSandNO_TIER: "bg-red-100 text-red-700"toTIER_COLORS."BASIC"to"NO_TIER"— an unknown/missing tier is effectively no-tier, not BASIC.NO_TIERis a validSubscriptionTierenum value in the OpenAPI spec, andSetUserTierRequest.tieraccepts it, so the dropdown can now also SETNO_TIERto revoke access (the backendset_user_rate_limit_tier/set_user_tieralready accepts it). No other spot in theadmin/rate-limitsfeature hardcodes the tier list or assumes BASIC as default —useRateLimitManager.tspasses the tier through as a string.Changes 🏗️
RateLimitDisplay.tsx: addNO_TIERtoTIERS,TIER_MULTIPLIERS,TIER_COLORS; fall back toNO_TIER(notBASIC) for unknown tiers.RateLimitDisplay.test.tsx: assertNO_TIERrenders as its own badge + "no access (paywalled)" label + selected dropdown value (not BASIC); update unknown-tier fallback test to expectNO_TIER; bump dropdown option count to 6.Checklist 📋
For code changes:
pnpm format,pnpm lint,pnpm typespasspnpm test:unit RateLimitDisplay— 21 tests pass (including new NO_TIER cases)pnpm test:unit RateLimitManager— 19 tests pass (no regression)