fix(billing+dashboard): honest peak-day figure; honest verify-email banner (refs #211) #5460
ccantynzAI Reviewcommented 24d ago
AI Triage
(no summary)
Priority: medium Risk area: mixed
Suggested labels: (no label suggestions) Suggested reviewers: (no reviewer suggestions)
Suggestions only — nothing has been applied. The PR author stays in control.
gluecron[bot]🤖 botAI Reviewcommented 24d ago
AI review unavailable
The platform's AI balance is exhausted, so AI generation is temporarily unavailable. Nothing was lost. You can queue this as a repair for the internal agent from the repository's Health page, or try again once the balance is restored. The PR is otherwise unchanged.
Cross-repo impact
See what breaks downstream if this PR merges.
⮌ Merged
This pull request was merged into main.
c comment · e edit title · m merge · a approve · r request changes · ? shortcuts
Part of the design-sweep for the visual-audit ledger (#211). Slice: billing numbers + the email-verification banner.
Defect 1 — /billing/usage: "Peak day $0.01" beside "30-day total $0.00"
Root cause: not two rounding policies — a chart-scaling clamp leaking into display copy.
buildTrendSparklinecomputedmax = Math.max(1, ...series)so an all-zero month couldn't divide by zero when scaling the SVG, and the page then rendered that clamped value as the "Peak day" dollar figure. With zero spend: peak showed $0.01, total showed $0.00.Fix (
src/routes/billing-usage.tsx):maxis now the true peak day (0 when there is no spend); the >=1 clamp survives only as an internal Y-axis denominator (scaleMax) that is never surfaced as money. Both displayed figures now derive from the same summed integer-cents series (per-eventcentsEstimateis already an integer, day buckets sum those integers), sototal >= max(daily)holds by construction — a nonzero peak can never again coexist with a zero total.Tests (
src/__tests__/ai-cost-tracker.test.ts): new section pins the invariant — all-zero window renders peak $0.00;total >= max(daily)across several series shapes (empty, single day, multi-day, out-of-window rows);aggregateEventsupstream invarianttotalCents >= max(byDay).No Stripe/payment logic touched — presentation and the sparkline helper only.
Defect 2 — "Verify your email to keep using Gluecron."
What enforcement actually does: nothing.
users.emailVerifiedAtis never read by any gate — no middleware, no route guard, no quota path. It is only set (verify-link consumption, magic-link sign-in, admin provisioning, playground) and read for banner/status display. An unverified user loses zero functionality, so "to keep using" implied a lockout that does not exist.Fixes (
src/routes/dashboard.tsx):/docsand/helpcopy ("Verified addresses receive issue, PR, and gate-run notifications"), which was already honest.isSiteAdmin(src/lib/admin.ts). Why suppression over auto-verify: auto-verifying would write a false "verified at" fact into the DB that other surfaces trust (verification status page, welcome-email flow) — a new "two sources of truth" seam. Suppression is a one-condition display change with no data side effects. The check is ordered last in the&&chain so the extra DB lookup only runs for unverified, undismissed users; verified users pay nothing.Verification
bunx tsc --noEmit -p .— cleanbun test src/__tests__/ai-cost-tracker.test.ts— 30 pass, 0 fail (2 skips are the pre-existing DB-gated tests, expected withoutDATABASE_URL)bun test src/__tests__/billing.test.ts— 15 pass, 0 fail🤖 Generated with Claude Code