Cross-provider API-value aggregate backend (SOU-265 pass 3a) - #57
Conversation
Backend foundation for the total API-value card: a command that aggregates each capable provider's local usage into Today / Yesterday / 30 Days, using the same canonical scanner aggregates as provider detail and the CLI. - chart.rs: `LocalApiValuePeriod` (estimated API value USD, processed tokens, priced/total model tokens for pricing coverage, has_data) and `LocalApiValueProvider` across the three periods. `api_value_period` derives coverage from unknown_models (unpriced tokens counted but not priced, no fabricated dollars). New `get_local_api_value_totals` command scans codex + claude once each (30-day report + an exact local-day "yesterday" window) and omits providers with no source data in any period. - Yesterday uses local calendar boundaries via `local_midnight_utc` (DST-safe: handles skipped/ambiguous local midnights) and `local_yesterday_window_utc`. - Registered in main.rs + permissions/commands.toml. bridge.ts types + `getLocalApiValueTotals` wrapper wire it to the frontend boundary (the donut card UI lands in pass 3b). Tests: partial pricing coverage, fully priced, empty (no data), and the yesterday window spanning one local day (23-25h across DST). Desktop 381 / frontend green; fmt + tsc clean.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
ceiling | ca3865b | Commit Preview URL Branch Preview URL |
Jul 18 2026, 09:42 PM |
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 16 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAdds local API-value totals for codex and claude across today, yesterday, and thirty days, including token pricing coverage and DST-safe date windows. The new Tauri command is registered, permitted, and exposed through typed TypeScript bridge definitions. ChangesLocal API value totals
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant Bridge as getLocalApiValueTotals
participant Command as get_local_api_value_totals
participant Report as get_cost_usage_report_with_windows
Bridge->>Command: Invoke API-value totals command
Command->>Report: Request provider period windows
Report-->>Command: Return CostSummary data
Command-->>Bridge: Return LocalApiValueProvider[]
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/desktop-tauri/src-tauri/src/commands/chart.rs`:
- Around line 493-500: Update get_local_api_value_totals to return a friendly
Result error when spawn_blocking fails instead of substituting Vec::new().
Preserve the existing structured tracing::warn! call, and use the project’s
established anyhow/thiserror error pattern so worker panic or cancellation is
surfaced clearly to the frontend.
- Around line 472-482: The local_midnight_utc function must not fall back to
interpreting the naive timestamp as UTC when LocalResult::None occurs. Search
forward from the skipped midnight until the first valid local instant, or
propagate an error, and preserve the earliest choice for Ambiguous results. Add
deterministic tests covering both None and Ambiguous outcomes instead of relying
on Local::now().
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 38717975-5707-44ad-9e43-d717e17967d5
📒 Files selected for processing (5)
apps/desktop-tauri/src-tauri/permissions/commands.tomlapps/desktop-tauri/src-tauri/src/commands/chart.rsapps/desktop-tauri/src-tauri/src/main.rsapps/desktop-tauri/src/lib/tauri.tsapps/desktop-tauri/src/types/bridge.ts
Build the test CostSummary via a struct literal with ..Default::default() instead of assigning scalar fields after default(), which tripped clippy::field_reassign_with_default under -D warnings in CI.
Two fixes on the API-value aggregate: - local_midnight_utc: on a skipped (spring-forward) local midnight, advance minute by minute to the first instant that actually exists instead of the old "+1h then treat naive as UTC" fallback, which gave a wrong boundary if more than one hour was skipped. Extracted a generic `local_midnight_in_tz` so the DST edges are deterministically testable, and added a chrono-tz dev-dependency + a test that finds real skipped/ambiguous midnights across several midnight-transition zones (replacing the Local::now() test that could never hit either edge). - get_local_api_value_totals now returns Result<_, String>: a panicked or cancelled worker surfaces as an error, not an empty Vec, so the card can tell "unavailable" apart from genuine "No data". clippy (-D warnings), desktop 382, fmt, and tsc all clean.
## What The aggregate "estimated API value" card from SOU-265, consuming the pass-3a backend (#57). Completes the SOU-262 dollar-analytics epic's UI. ## Changes - **lib/apiValueCard.ts** - pure, unit-tested model + ring geometry. `buildApiValueCard` omits providers with no data (never counts zero), computes per-provider shares and pricing coverage; `ringSegments` turns shares into stroke-dasharray donut segments. - **components/TotalApiValueCard.tsx** - period switcher (Today / Yesterday / 30 days) + metric switcher (API value / Tokens), an SVG donut coloured by provider brand colors, a ranked legend (share + value), and transparency copy: an estimate marker plus "N% of tokens priced (unpriced models in ...)" whenever coverage is below 100%. Empty periods show **No data**; a failed command shows an unavailable state. `role="img"` on the ring carries an a11y summary of metric, period, total, and providers. - Mounted at the top of **ChartsPanel**; styling is responsive and theme-aware, reusing existing design tokens. ## Terminology (per SOU-265) Dollars are labelled **Estimated API value**, never a bill or subscription spend. Providers with no source data are omitted; coverage is surfaced whenever any tokens are unpriced. ## Tests - 8 pure-logic cases: single / multiple / tiny-share / missing-data / partial-pricing / all-unpriced, plus ring geometry. - 3 render cases: aggregate total + ranked legend + coverage note, "No data" on switching to an empty period, unavailable state on command failure. Frontend 258 / `tsc` clean. **Note:** the donut was verified via the geometry unit tests and the standard stroke-dasharray technique - the in-app browser preview was unavailable for a live screenshot this session, so a visual pass on the rendered ring is worth a glance before release. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added an API value card to the charts panel, always shown at the top. * Lets you switch between periods (today, yesterday, past 30 days) and metrics (API value vs tokens). * Visualizes provider contributions with a ring breakdown and legend, including token-pricing coverage where available. * Shows clear “no data” and “unavailable right now” states. * **Tests** * Added UI and calculation test coverage, including pricing coverage, empty-period behavior, and error handling. * **Style** * Added responsive styling for the API value card (including small-screen layout). <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: tsouth89 <tsouth89@users.noreply.github.com>
What
Backend foundation for SOU-265's total API-value card. A command aggregates each capable provider's local usage into Today / Yesterday / 30 Days, using the same canonical scanner aggregates as provider detail and the CLI (no new accounting path).
SOU-265 is large (donut card + period/metric switchers + transparency + responsive across tray/dashboard/pop-out), so it's split: this is pass 3a (backend + command + tests); the donut UI is pass 3b.
Changes
LocalApiValuePeriod(estimated API value USD, processed tokens, priced/total model tokens for pricing coverage,hasData) andLocalApiValueProvideracross the three periods.api_value_periodderives coverage fromunknown_models(unpriced tokens are counted but not priced - no fabricated dollars).get_local_api_value_totalscommand: scans codex + claude once each (30-day report + an exact local-day "yesterday" window) and omits providers with no source data in any period.local_midnight_utc(DST-safe: handles skipped/ambiguous local midnights) andlocal_yesterday_window_utc.getLocalApiValueTotalswrapper wire it to the frontend boundary.Terminology (per SOU-265)
Dollars are token-derived estimated API value, never billed spend. Unpriced models contribute tokens but no dollars;
pricedTokens / totalTokensgives the coverage the UI will surface ("N% of tokens priced").Tests
api_value_period_reports_partial_pricing_coverage,_fully_priced_has_full_coverage,_empty_summary_has_no_data.local_yesterday_window_spans_one_local_day(23-25h across DST).Desktop 381 / frontend green;
cargo fmt --all --check+tscclean.Summary by CodeRabbit