Align codexbar cost JSON with provenance, mix, and OpenCodex - #3019
Conversation
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
When OpenCodex logging is enabled but the user has no enabled first-party token-cost provider, providerIDs is empty and this early exit runs before the loader can append the independent OpenCodex input. The opt-in therefore cannot display OpenCodex usage by itself, even with a valid usage.jsonl; treat openCodexUsageLogsEnabled as a loadable source when deciding whether to exit.
ℹ️ 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".
| private var sourceIDs: [String] { | ||
| Array(Set(self.model.groups.flatMap(\.providers).map(\.id))).sorted() |
There was a problem hiding this comment.
Keep hidden sources available in the filter
When a user unchecks a source, the rebuilt model excludes that source via hiddenSourceIDs, and this list is then derived only from the model's remaining providers. The unchecked source's toggle therefore disappears immediately and cannot be re-enabled from the UI; if it was the last source, the entire filter disappears. Build the filter from all loaded/configured source IDs, including hidden ones, rather than only visible provider rows.
Useful? React with 👍 / 👎.
| guard let snapshot = try? store.loadSnapshot( | ||
| logURL: logURL, | ||
| now: request.now, | ||
| historyDays: Self.scanDays, | ||
| calendar: request.configuration.bucketCalendar) |
There was a problem hiding this comment.
Don't treat an empty OpenCodex log as present
When OpenCodex is enabled but usage.jsonl is missing or empty, OpenCodexUsageStore.loadEntries returns an empty array and loadSnapshot still succeeds, so this guard creates an OpenCodex input with no data. If “Hide native Codex when OpenCodex is present” is also enabled, visibleInputs sees that empty input as present and removes all native Codex spend, leaving users with an empty dashboard despite valid native history. Require an existing log with meaningful entries before appending this source.
Useful? React with 👍 / 👎.
| } else if entry.usageStatus == .reported || entry.usageStatus == .estimated { | ||
| day.unpriced += 1 | ||
| if day.priced > 0 { day.priced -= 1 } |
There was a problem hiding this comment.
Count an unpriced estimated request only once
For an .estimated entry whose model cannot be priced, the request has already incremented day.estimated, but this branch also increments day.unpriced and only decrements day.priced. Because the emitted requestCount is the sum of all four buckets, one such request is reported as two requests and its coverage ratio is distorted. Either reclassify it by decrementing estimated or leave it solely in the estimated bucket.
Useful? React with 👍 / 👎.
|
Codex review: needs real behavior proof before merge. Reviewed August 17, 2026, 4:12 PM ET / 20:12 UTC. ClawSweeper reviewWhat this changesThe PR extends cost JSON and the spend dashboard with provenance, token mix, coverage, optional OpenCodex logs, and shared time-bucket settings. Merge readiness⛔ Blocked until real behavior proof is added - 12 items remain Keep open: current main does not contain this feature, but the PR still has three P2 accounting/provenance defects, lacks real behavior proof, and needs product sponsorship for its new CLI and OpenCodex surfaces. Priority: P2 Review scores
Verification
How this fits togetherCodexBar aggregates local and provider usage snapshots into dashboard groups and CLI JSON. This PR adds metadata and an optional OpenCodex log source before those outputs are presented. flowchart LR
A[Provider usage and local logs] --> B[Usage snapshot aggregation]
C[Optional OpenCodex log] --> B
B --> D[Cost provenance and coverage]
D --> E[Spend dashboard]
D --> F[CLI JSON export]
Decision needed
Why: The PR adds persisted settings and externally consumable reporting fields; accepting their long-term compatibility contract requires maintainer intent beyond repairing the present defects. Before merge
Findings
Agent review detailsSecurityNone. Review metrics
Merge-risk optionsMaintainer options:
Technical reviewBest possible solution: Sponsor a narrow, documented JSON and OpenCodex contract, repair the three reporting paths with regressions, then provide redacted real CLI or dashboard proof before landing the stacked work. Do we have a high-confidence way to reproduce the issue? Yes, source inspection gives high-confidence paths for the three reporting defects; runtime execution was not performed in this read-only review. Is this the best way to solve the issue? No: the proposed direction needs sponsorship, and the current implementation must preserve explicit vendor provenance and fail closed for incomplete pricing data. 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>
Co-authored-by: Cursor <cursoragent@cursor.com>
A missing or empty usage.jsonl no longer counts as an OpenCodex source that can hide native Codex totals. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
9da61af to
a888751
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: a888751278
ℹ️ 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".
| if summary.totalCost != nil { | ||
| sawEstimate = true |
There was a problem hiding this comment.
Preserve vendor provenance in dashboard groups
When a source such as OpenAI Admin, Bedrock, Mistral, or Groq has vendor-reported daily costs but no separate meteredCostUSD, summary.totalCost sets sawEstimate and the switch labels the group listPriceEstimate. This ignores each snapshot's explicit .vendorMetered provenance, so the dashboard and exported JSON misrepresent vendor-reported spend as a list-price calculation; derive the group provenance from the included snapshots/window summaries instead of cost presence.
Useful? React with 👍 / 👎.
| let hasTokenData = entry.resolvedTotalTokens != nil | ||
| || usage?.inputTokens != nil | ||
| || usage?.outputTokens != nil | ||
| || usage?.cacheReadTokens != nil | ||
| || usage?.cacheCreationInputTokens != nil |
There was a problem hiding this comment.
Do not price total-only usage as zero
For a reported or estimated OpenCodex row that supplies only totalTokens and no input/output/cache breakdown, this condition accepts the row as priceable; the following nil-coalescing then passes zero for every priced token class and bundled pricing returns $0. Since a total token count cannot be split across differently priced classes, these rows need to remain unpriced rather than silently understating spend and coverage.
Useful? React with 👍 / 👎.
| guard let pricing = self.resolvedCodexPricing( | ||
| model: model, | ||
| modelsDevCatalog: modelsDevCatalog, | ||
| modelsDevCacheRoot: modelsDevCacheRoot) |
There was a problem hiding this comment.
Stop fallback after a matching incomplete overlay
When a custom-pricing entry matches the model but omits a rate needed by the current request—for example, it defines only input pricing while the request also has output tokens—estimatedCodexCostUSD returns nil and this path falls through to models.dev or bundled rates. That contradicts the overlay contract that omitted fields stay unknown and can produce a cost using entirely different rates; distinguish “no matching overlay” from “matching overlay cannot price this request” and return nil for the latter.
Useful? React with 👍 / 👎.
|
Thanks @Yuxin-Qiao — the whole #3015→#3019 stack landed via #3026 (all five now show merged). Two things changed during landing: the architecture-gatekeeper anchors were refreshed (the CI failures were stale-base, not your code), and one real fix — #3018's OpenCodex usage cache was writing |
Summary
codexbar cost --jsonwith token mix, provenance, coverage, and reasoning tokens.Stacked PR 5/5 (Wave E). Depends on #3017.
Review follow-up
daily+sessionsempty) are not treated as a present source, so hide-native cannot drop real Codex.listPriceEstimate;projectsstays empty.Test plan
Fixtures only. No Keychain, no live accounts, no
~/.opencodex.CODEXBAR_SUPPRESS_TEST_KEYCHAIN_ACCESS=1 swift test --filter CLICostTestsprojectsarray stays empty