Add an all-time range to the spend dashboard - #3009
Conversation
A nil cost on one subscription no longer wipes the currency group header. Co-authored-by: Cursor <cursoragent@cursor.com>
Named models with tokens but no price stay visible as a partial list instead of wiping the whole breakdown. Co-authored-by: Cursor <cursoragent@cursor.com>
Keep 7-day and 30-day windows, and scan local Codex history out to 365 days so cumulative spend is not truncated at a month. Co-authored-by: Cursor <cursoragent@cursor.com>
|
🦞👀 Pull request received. I will update this pull request when review starts. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0b0279c6eb
ℹ️ 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".
| static let scanDays = 30 | ||
| static let activityDays = 365 | ||
| /// Local spend scan window. Matches token-activity depth so 7d / 30d / All share one snapshot. | ||
| static let scanDays = activityDays |
There was a problem hiding this comment.
Load the all-time window for non-Codex providers
When the user keeps the default costUsageHistoryDays of 30 and selects All, only Codex is loaded with scanDays; every non-Codex refresh still builds its snapshot using settings.costUsageHistoryDays, and selectDays merely rebuilds the existing inputs. Consequently providers capable of returning older history remain truncated to 30 days in the new 365-day view. The dashboard request needs to fetch the all-time horizon for those providers as well, or the option must not present their result as All.
Useful? React with 👍 / 👎.
| static func combinedTotalTokens(_ values: [Int?]) -> Int? { | ||
| let known = values.compactMap(\.self) | ||
| guard !known.isEmpty else { return nil } |
There was a problem hiding this comment.
Preserve partial status for shared token totals
When any currency group has unavailable token data, compacting away its nil total produces a lower-bound totalTokens, but ShareStatsPayload carries no corresponding partial flag and the share card renders this number without the dashboard's ~ marker. For example, one valid group plus one unavailable group is shared as an exact tracked-token total. Either retain the previous nil result or propagate partial-token metadata through the payload and card.
Useful? React with 👍 / 👎.
After-fix proofShare Stats renderer on
All-time window is covered by tests ( @clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
Codex review: needs changes before merge. Reviewed August 17, 2026, 9:22 AM ET / 13:22 UTC. ClawSweeper reviewWhat this changesAdds a 7-day, 30-day, and 365-day All range to the Usage & Spend dashboard, with partial-total labeling in the dashboard and Share Stats. Merge readinessKeep open: the native screenshots now prove the visible 7d/30d/All control, but two snapshot-freshness paths can still show a 30-day or stale result for providers using the new independent 365-day snapshot. Priority: P2 Review scores
Verification
How this fits togetherCodexBar collects provider usage into local cost snapshots, then projects those snapshots into the Settings Usage & Spend dashboard and Share Stats. This change introduces a separate 365-day snapshot for the dashboard while keeping the menu bar on its configured cost-history window. flowchart LR
A[Provider usage history] --> B[Menu and dashboard snapshots]
B --> C[7d 30d or All selection]
C --> D[Spend aggregation]
D --> E[Settings Usage and Spend]
D --> F[Share Stats]
Before merge
Findings
Agent review detailsSecurityNone. Review metrics
Merge-risk optionsMaintainer options:
Technical reviewBest possible solution: Treat a missing independent 365-day publication as missing even when a menu snapshot exists, then refresh retained dashboard snapshots with a bounded freshness policy that does not alter the menu snapshot or its configured window. Do we have a high-confidence way to reproduce the issue? Yes—source provides a high-confidence path: open the dashboard with a normal 30-day Claude/Cursor publication but no independent publication, then reopen after the independent snapshot exists and new usage is fetched normally. Is this the best way to solve the issue? No—the range UI and proof are sound, but the separate dashboard cache needs missing-snapshot and retained-snapshot refresh handling before it accurately represents All history. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 14e300389e9e. LabelsLabel changes:
Label justifications:
EvidenceAcceptance criteria:
What I checked:
Likely related people:
Rank-up movesOptional improvements that raise the rating; they are not merge blockers.
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
HistoryReview history (2 earlier review cycles)
|
Keep menu token publications on costUsageHistoryDays, and refresh a separate 365-day spend snapshot slot so All can include days outside Last 30 days. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d6a90ad887
ℹ️ 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".
| return ( | ||
| store.tokenSnapshotPublicationForCurrentProviderConfig(for: provider), | ||
| revision) |
There was a problem hiding this comment.
Refresh when only the shorter menu snapshot exists
When a direct-cost provider such as Claude or Cursor already has its normal 30-day publication but no dashboard publication, this fallback makes refreshMissing treat the source as loaded, so the new 365-day fetch is skipped and selecting All silently reuses the 30-day data until the user manually refreshes. The fresh evidence beyond the earlier comment is that the new fallback returns the regular publication while pairing it with the dashboard revision; only a real dashboard publication should satisfy the initial-load check.
Useful? React with 👍 / 👎.
| if UsageStore.tokenCostRequiresProviderSnapshot(baseline.provider) { | ||
| await store.refreshProvider(baseline.provider) | ||
| } else { | ||
| await store.refreshTokenUsageNow(for: baseline.provider, force: true) | ||
| await store.refreshSpendDashboardTokenUsageNow(for: baseline.provider, force: true) |
There was a problem hiding this comment.
Fetch the All window for provider-derived snapshots
With the default 30-day cost-history setting, OpenAI API, Mistral, and OpenCodeGo enter the tokenCostRequiresProviderSnapshot branch, whose provider refresh still receives settings.costUsageHistoryDays; only the other branch invokes the new 365-day dashboard loader. As a result, even a manual dashboard refresh cannot populate older data for these providers and the All view remains a 30-day result. The fresh evidence beyond the earlier comment is that the new independent loader explicitly excludes these provider-derived snapshot sources, so this branch also needs an all-window fetch/projection.
Useful? React with 👍 / 👎.
Usage & Spend 30d vs All renders show MiniMax-M3 only in All, and the share card prefixes tracked tokens with ~ when a peer is unknown. Co-authored-by: Cursor <cursoragent@cursor.com>
After-fix proof (All range + partial tokens)Claude/Cursor now load a 365-day spend snapshot slot (menu bar still uses Same Usage & Spend section the app draws: 30d — MiniMax-M3 clipped, Cursor spend unavailable: All — MiniMax-M3 $1.20, coverage 365/365: @clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ec998ded0c
ℹ️ 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".
| var lines = ["My AI subscriptions · last \(payload.days) days"] | ||
| if let tokens = payload.totalTokens { | ||
| lines.append("\(self.compactCount(tokens)) tracked tokens") | ||
| let count = self.compactCount(tokens) |
There was a problem hiding this comment.
Label copied all-time stats as All
When the user selects the new All range, ShareStatsExporter.copyText calls this formatter with payload.days == 365, so the copied text still says last 365 days and uses /365 days coverage even though the image labels the same payload ALL and ALL-TIME. Format the period and coverage using the same all-time semantics as the card so the two share outputs describe the selected range consistently.
Useful? React with 👍 / 👎.
Co-authored-by: Cursor <cursoragent@cursor.com>
Native Usage & Spend (this machine, QA bundle)Opened Settings → 用量与支出 and clicked 7天 / 30天 / 全部. Codex catch-up finished (477/478). Claude stays spend unavailable on this head (bare-ID pricing is #3002). 7天 — Codex ~$127.36, coverage 7/7: 30天 — Codex ~$310.40, coverage 30/30, 1/2 subscriptions have spend, tracked tokens 全部 — coverage 365 / 365, same priced Codex subtotal on this account, Claude still unavailable: @clawsweeper re-review |
|
🦞👀 Re-review progress:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8683edd313
ℹ️ 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".
| await store.refreshProvider(baseline.provider) | ||
| } else { | ||
| await store.refreshTokenUsageNow(for: baseline.provider, force: true) | ||
| await store.refreshSpendDashboardTokenUsageNow(for: baseline.provider, force: true) |
There was a problem hiding this comment.
Refresh retained all-time snapshots
After Claude, Cursor, Bedrock, or Vertex AI successfully creates an independent 365-day publication, every later ordinary load—including reopening the dashboard and date-window refreshes—skips this call because .refreshMissing sees that publication as present. This is the only caller of refreshSpendDashboardTokenUsageNow; background token refreshes update only the normal menu publication, while dashboard revisions track the independent publication. Consequently, newly recorded usage never appears in the dashboard until the user explicitly clicks Refresh or changes provider configuration; refresh independent snapshots using an age/revision policy or update them during background refreshes.
Useful? React with 👍 / 👎.
…end to the scan window. Copied text was still saying last 365 days, and Mistral/OpenCode Go All totals were clipped to the menu history setting. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Follow-up for the remaining All-range review notes (
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
🦞👀 Command router queued. I will update this comment with the next step. |
Summary
7d/30d/Allranges to the Usage & Spend dashboard.Alluses up to 365 days of local history.~on the dashboard and Share Stats card when a peer is unknown.Note