fix(usage,sessions): resolve token/subscription usage integration disparities - #760
Conversation
Audit found several subscription-usage providers emitting confident-looking empty/zero data instead of omitting it: - amp: fetch() returned Ok with no metrics when its $X/$Y display-text scrape didn't match, rendering a bare "Amp" header. Now bails so it's dropped. Also made the byte-offset slicing char-boundary-safe (could panic on multibyte display_text). - copilot, minimax_tokenplan: same empty-metrics guard / skip empty rows. - warp: "Spend" and no-limit "requests" metrics set 0% remaining, rendering a false "exhausted" bar; now read full with the figure kept in the label. Dropped the placeholder "Aggregate API cache" plan string. - zai: a missing percentage was rendered as "100% left"; now skipped. - kimi: include resets_at in the metric dedup key so distinct windows with equal numbers don't collapse. Adds unit tests for the amp and warp behavior changes. Confidence: high Scope-risk: narrow
Cross-parser audit found inconsistent provider attribution and silent data loss: - Provider canonicalization (opencode, micode, kilo, mux, antigravity, jcode): these stored a raw provider field verbatim, so aliases (fireworks, vertex, gemini, azure) split into separate aggregation buckets. Now routed through provider_identity::canonical_provider like the other parsers. - codex: provider defaulted to "openai" when session meta was absent; now infers from the model first, keeping "openai" only as the final fallback. - gjc, pi: dropped messages with valid tokens but no provider field; now recover via model inference (fallback "gjc"/"pi") instead of discarding the spend. - droid: dropped a whole session when its timestamp resolved to 0; now falls back to file mtime. - qwen, mux: had no dedup key (double-count risk on re-parse); now keyed stably. - utils: seconds->ms conversion uses saturating_mul; kiro/goose timestamp paths hardened against overflow. - kiro (estimated tokens), goose (heuristic reasoning), crush (cost-only, zero tokens): documented these source limitations so 0/estimated values aren't mistaken for bugs. Updates tests that encoded the OLD behavior: fireworks->fireworks_ai canonicalization, and gjc now keeping a previously-dropped record. Confidence: high Scope-risk: moderate Directive: roocode/cline/kilocode intentionally preserve raw apiProtocol — do NOT canonicalize them
Pre-existing clippy useless-vec warnings in report.rs test helpers, swept to keep the clippy gate clean.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fbd2bd6070
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // "0% used / 100% left" from a missing field. | ||
| let pct = match limit.percentage { | ||
| Some(p) => p.clamp(0.0, 100.0), | ||
| None => continue, |
There was a problem hiding this comment.
Drop Z.ai output when all quota rows are skipped
When Z.ai returns limits that omit percentage (the exact case handled here), every row can be skipped but fetch() still returns Ok(UsageOutput { metrics: vec![] }), so fetch_all() includes it and the renderer shows a bare Z.ai card instead of failing soft like the Amp/Copilot/MiniMax guards added in this commit. Add an empty-metrics bail after assembling metrics (or compute from other fields) so unparseable quota responses are dropped rather than rendered as an empty provider.
Useful? React with 👍 / 👎.
…parities (junhoyeo#760) * fix(usage): make subscription providers fail-soft Audit found several subscription-usage providers emitting confident-looking empty/zero data instead of omitting it: - amp: fetch() returned Ok with no metrics when its $X/$Y display-text scrape didn't match, rendering a bare "Amp" header. Now bails so it's dropped. Also made the byte-offset slicing char-boundary-safe (could panic on multibyte display_text). - copilot, minimax_tokenplan: same empty-metrics guard / skip empty rows. - warp: "Spend" and no-limit "requests" metrics set 0% remaining, rendering a false "exhausted" bar; now read full with the figure kept in the label. Dropped the placeholder "Aggregate API cache" plan string. - zai: a missing percentage was rendered as "100% left"; now skipped. - kimi: include resets_at in the metric dedup key so distinct windows with equal numbers don't collapse. Adds unit tests for the amp and warp behavior changes. Confidence: high Scope-risk: narrow * fix(sessions): canonicalize providers and harden token parsers Cross-parser audit found inconsistent provider attribution and silent data loss: - Provider canonicalization (opencode, micode, kilo, mux, antigravity, jcode): these stored a raw provider field verbatim, so aliases (fireworks, vertex, gemini, azure) split into separate aggregation buckets. Now routed through provider_identity::canonical_provider like the other parsers. - codex: provider defaulted to "openai" when session meta was absent; now infers from the model first, keeping "openai" only as the final fallback. - gjc, pi: dropped messages with valid tokens but no provider field; now recover via model inference (fallback "gjc"/"pi") instead of discarding the spend. - droid: dropped a whole session when its timestamp resolved to 0; now falls back to file mtime. - qwen, mux: had no dedup key (double-count risk on re-parse); now keyed stably. - utils: seconds->ms conversion uses saturating_mul; kiro/goose timestamp paths hardened against overflow. - kiro (estimated tokens), goose (heuristic reasoning), crush (cost-only, zero tokens): documented these source limitations so 0/estimated values aren't mistaken for bugs. Updates tests that encoded the OLD behavior: fireworks->fireworks_ai canonicalization, and gjc now keeping a previously-dropped record. Confidence: high Scope-risk: moderate Directive: roocode/cline/kilocode intentionally preserve raw apiProtocol — do NOT canonicalize them * style(report): drop useless vec! in test helpers Pre-existing clippy useless-vec warnings in report.rs test helpers, swept to keep the clippy gate clean.
ported from upstream junhoyeo#735 ported from upstream junhoyeo#737 ported from upstream junhoyeo#747 ported from upstream junhoyeo#750 ported from upstream junhoyeo#752 ported from upstream junhoyeo#760 ported from upstream junhoyeo#766
ported from upstream junhoyeo#760 ported from upstream junhoyeo#762 ported from upstream junhoyeo#763 ported from upstream junhoyeo#764
ported from upstream junhoyeo#728 ported from upstream junhoyeo#757 ported from upstream junhoyeo#759 ported from upstream junhoyeo#760
…parities (junhoyeo#760) * fix(usage): make subscription providers fail-soft Audit found several subscription-usage providers emitting confident-looking empty/zero data instead of omitting it: - amp: fetch() returned Ok with no metrics when its $X/$Y display-text scrape didn't match, rendering a bare "Amp" header. Now bails so it's dropped. Also made the byte-offset slicing char-boundary-safe (could panic on multibyte display_text). - copilot, minimax_tokenplan: same empty-metrics guard / skip empty rows. - warp: "Spend" and no-limit "requests" metrics set 0% remaining, rendering a false "exhausted" bar; now read full with the figure kept in the label. Dropped the placeholder "Aggregate API cache" plan string. - zai: a missing percentage was rendered as "100% left"; now skipped. - kimi: include resets_at in the metric dedup key so distinct windows with equal numbers don't collapse. Adds unit tests for the amp and warp behavior changes. Confidence: high Scope-risk: narrow * fix(sessions): canonicalize providers and harden token parsers Cross-parser audit found inconsistent provider attribution and silent data loss: - Provider canonicalization (opencode, micode, kilo, mux, antigravity, jcode): these stored a raw provider field verbatim, so aliases (fireworks, vertex, gemini, azure) split into separate aggregation buckets. Now routed through provider_identity::canonical_provider like the other parsers. - codex: provider defaulted to "openai" when session meta was absent; now infers from the model first, keeping "openai" only as the final fallback. - gjc, pi: dropped messages with valid tokens but no provider field; now recover via model inference (fallback "gjc"/"pi") instead of discarding the spend. - droid: dropped a whole session when its timestamp resolved to 0; now falls back to file mtime. - qwen, mux: had no dedup key (double-count risk on re-parse); now keyed stably. - utils: seconds->ms conversion uses saturating_mul; kiro/goose timestamp paths hardened against overflow. - kiro (estimated tokens), goose (heuristic reasoning), crush (cost-only, zero tokens): documented these source limitations so 0/estimated values aren't mistaken for bugs. Updates tests that encoded the OLD behavior: fireworks->fireworks_ai canonicalization, and gjc now keeping a previously-dropped record. Confidence: high Scope-risk: moderate Directive: roocode/cline/kilocode intentionally preserve raw apiProtocol — do NOT canonicalize them * style(report): drop useless vec! in test helpers Pre-existing clippy useless-vec warnings in report.rs test helpers, swept to keep the clippy gate clean.
Summary
Fixes the actionable disparities found in an audit of all token-usage + subscription-usage integrations (11 subscription providers in
usage/*.rs, 34 session parsers insessions/*.rs). The unifying theme: omit or fall back, never fabricate — several integrations emitted confident-looking empty/zero/100% data or silently dropped real records.Subscription-usage providers (
fix(usage))fetch()returnedOkwith no metrics when its$X/$Ydisplay-text scrape didn't match, rendering a bare "Amp" header with no data. Now bails sofetch_alldrops it. Also made the byte-offset slicing char-boundary-safe (it could panic on multibytedisplay_text)."Aggregate API cache"plan string.percentagerendered as "100% left"; now skipped.resets_atso distinct windows with equal numbers don't collapse.Token-usage session parsers (
fix(sessions))fireworks,vertex,gemini,azure) split into separate aggregation buckets and undercounted per-provider totals. Now routed throughprovider_identity::canonical_provider, matching the other parsers."openai"when session meta was absent; now infers from the model first, keeping"openai"only as the final fallback."gjc"/"pi") instead of discarding the spend.saturating_mul; timestamp paths hardened against overflow.0/estimated values aren't mistaken for bugs.Deliberately NOT changed
apiProtocol(has a test) — not canonicalized.Testing
cargo build --workspaceclean;cargo test --workspace1850 passed / 0 failed;cargo clippy --workspace --all-targetsclean;cargo fmt --all -- --checkpasses.fireworks → fireworks_aicanonicalization and gjc now keeping a previously-dropped record.useless-vecwarnings inreport.rstest helpers to keep the gate green (style(report)commit).Summary by cubic
Fixes incorrect or missing usage data across subscription providers and session parsers by failing soft on empty responses, canonicalizing providers, and adding safe fallbacks. This removes empty headers, corrects Warp bars, prevents double counts, and improves per‑provider totals.
Bug Fixes
Refactors
Written for commit fbd2bd6. Summary will update on new commits.