Surface token mix, coverage, sessions, and OpenCodex on the spend dashboard - #3017
Conversation
Co-authored-by: Cursor <cursoragent@cursor.com>
|
🦞👀 Pull request received. I will update this pull request when review starts. |
💡 Codex ReviewCodexBar/Sources/CodexBar/SpendDashboardModel.swift Lines 445 to 447 in 2c6d24f For Cursor, CodexBar/Sources/CodexBar/PreferencesSpendDashboardPane.swift Lines 915 to 917 in 2c6d24f When a user unchecks a source, its ID is persisted in CodexBar/Sources/CodexBar/SpendActivityHeatmap.swift Lines 682 to 685 in 2c6d24f When a visible day has ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
|
Codex review: needs real behavior proof before merge. Reviewed August 17, 2026, 4:12 PM ET / 20:12 UTC. ClawSweeper reviewWhat this changesThe PR adds token mix, coverage, sessions, source filtering, a 90-day range, and opt-in OpenCodex usage to CodexBar’s spend dashboard. Merge readiness⛔ Blocked until real behavior proof from a real setup is added - 12 items remain Keep open. The feature is not on current main, but four current-head reporting defects and missing real dashboard proof block merge; the broadened OpenCodex and custom-pricing scope also needs product confirmation. Priority: P2 Review scores
Verification
How this fits togetherThe spend dashboard combines cached provider snapshots with persisted dashboard settings to produce time-windowed totals, rows, charts, and heatmap drill-downs. Those derived values then feed the native SwiftUI preferences pane and its JSON export. flowchart LR
A[Provider usage snapshots] --> C[Dashboard loader]
B[Dashboard settings] --> C
C --> D[Windowed spend model]
D --> E[Totals and breakdowns]
D --> F[Heatmap day selection]
E --> G[Dashboard and export]
F --> G
Decision needed
Why: The branch introduces two durable user-facing data/configuration surfaces in addition to dashboard presentation, so a code-only review cannot establish the intended long-term product boundary. Before merge
Findings
Agent review detailsSecurityNone. Review metrics
Merge-risk optionsMaintainer options:
Technical reviewBest possible solution: Stage the approved dashboard direction into a narrower, consistently scoped reporting implementation, preserve unknown and vendor-reported accounting semantics, and attach redacted real-dashboard proof before merge. Do we have a high-confidence way to reproduce the issue? Yes, from source: a vendor-metered snapshot without Is this the best way to solve the issue? No. The current combined path has inconsistent accounting semantics and needs a maintainer decision on the new persistent OpenCodex and pricing-config surfaces; a staged, tested implementation is safer. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against f7723d33a169. LabelsLabel justifications:
EvidenceWhat I checked:
Likely related people:
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
HistoryReview history (1 earlier review cycle)
|
Pinned calendars now reach cached Codex reads, vendor-reported costs keep their source, and shorter summaries no longer inherit snapshot-wide metered spend. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Cached day totals now honor overlay rates, including explicit free rates, without rereading custom-pricing.json for every usage row. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…imit. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Unreported rows no longer publish zero spend, estimated unpriced requests count once, and duplicate request IDs replace instead of aborting the cache write. Co-authored-by: Cursor <cursoragent@cursor.com>
…hboard. Co-authored-by: Cursor <cursoragent@cursor.com>
Shorter ranges no longer inherit snapshot-wide Cursor meters, uncovered heatmap days cannot drill down, and OpenCodex-only setups still load. Co-authored-by: Cursor <cursoragent@cursor.com>
… suite. Co-authored-by: Cursor <cursoragent@cursor.com>
2c6d24f to
b8a0652
Compare
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b8a0652aad
ℹ️ 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".
| let provenance: CostProvenance = switch (sawMetered, sawEstimate) { | ||
| case (true, true): .mixed | ||
| case (true, false): .vendorMetered | ||
| case (false, true): .listPriceEstimate | ||
| case (false, false): .unknown |
There was a problem hiding this comment.
Preserve vendor-reported provenance in currency groups
When OpenAI Admin, Mistral, or Groq supplies a snapshot marked .vendorMetered, its ordinary daily cost makes sawEstimate true while sawMetered remains false because that flag only checks the separate meteredCostUSD field. The dashboard therefore labels vendor-reported spend as listPriceEstimate, and a group combining that spend with actual estimates is also mislabeled instead of .mixed; derive this result from each snapshot's costProvenance for the selected window.
Useful? React with 👍 / 👎.
| public mutating func merge(_ other: CostUsageTokenMix) { | ||
| self.inputTokens = Self.add(self.inputTokens, other.inputTokens) | ||
| self.outputTokens = Self.add(self.outputTokens, other.outputTokens) | ||
| self.cacheReadTokens = Self.add(self.cacheReadTokens, other.cacheReadTokens) | ||
| self.cacheCreationTokens = Self.add(self.cacheCreationTokens, other.cacheCreationTokens) | ||
| self.reasoningTokens = Self.add(self.reasoningTokens, other.reasoningTokens) |
There was a problem hiding this comment.
Keep incomplete token classes unknown when aggregating
When multiple days or providers are merged and one reports a token class while another leaves that class nil, add treats the missing value as an identity and publishes the known subtotal. This contradicts the type's nil-means-unestablished contract and makes the new dashboard token-mix fields appear complete even though they omit part of the selected usage; aggregation needs to distinguish the initially empty accumulator from an unknown contribution.
Useful? React with 👍 / 👎.
| if let cost = (customPricing ?? self.customPricingOverlay()).estimatedCodexCostUSD( | ||
| model: model, | ||
| inputTokens: inputTokens, | ||
| cachedInputTokens: cachedInputTokens, | ||
| outputTokens: outputTokens, | ||
| cacheWriteInputTokens: cacheWriteInputTokens) | ||
| { | ||
| return cost | ||
| } | ||
| guard let pricing = self.resolvedCodexPricing( |
There was a problem hiding this comment.
Stop falling back after a matching partial pricing override
If custom-pricing.json contains a matching model entry but omits a rate needed by the current row—for example, it specifies only input while the request has output tokens—estimatedCodexCostUSD returns nil and this wrapper silently prices the row with bundled/models.dev rates. That violates the overlay's stated missing-field-is-unknown behavior and can produce costs the user explicitly declined to define; both this path and the analogous aggregate path should only fall back when no override entry matched.
Useful? React with 👍 / 👎.
| let providers = Self.providerRows(summaries) | ||
| let modelSummaries = summaries.filter { summary in | ||
| let scopedSummaries = Self.summaries(summaries, matching: selectedDay) |
There was a problem hiding this comment.
Scope all dashboard totals to the selected day
After a heatmap day is selected, only model rows, token mix, and coverage use scopedSummaries; provider rows are built from the full-window summaries, and those rows subsequently drive the displayed total spend and tracked-token totals. The UI therefore shows a selected date next to day-scoped breakdowns while retaining 7/30/90-day headline and subscription values (and the export carries that inconsistent state), so the selected-day scope should be applied consistently or clearly limited to a separate drill-down.
Useful? React with 👍 / 👎.
Summary
Stacked PR 4/5 (Wave B). Depends on the OpenCodex parser PR; keep 7/30/90/All and the existing 365-day scan window.
Review follow-up
selectedDay == nil && days >= snapshot.historyDays).availableSources).costUsageEnabledandopenCodexUsageLogsEnabledare on, even with emptyproviderIDs.Test plan
Fixtures only. No Keychain, no live accounts, no
~/.opencodex.CODEXBAR_SUPPRESS_TEST_KEYCHAIN_ACCESS=1 swift test --filter SpendDashboardModelTests --filter ShareStatsTests