Skip to content

Align codexbar cost JSON with provenance, mix, and OpenCodex - #3019

Merged
steipete merged 15 commits into
steipete:mainfrom
Yuxin-Qiao:feat/spend-e-export
Aug 18, 2026
Merged

Align codexbar cost JSON with provenance, mix, and OpenCodex#3019
steipete merged 15 commits into
steipete:mainfrom
Yuxin-Qiao:feat/spend-e-export

Conversation

@Yuxin-Qiao

@Yuxin-Qiao Yuxin-Qiao commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Extend codexbar cost --json with token mix, provenance, coverage, and reasoning tokens.
  • Emit an OpenCodex payload when the opt-in setting is on; do not invent project paths.
  • Reuse dashboard helpers for defaults so CLI and Settings share one schema.

Stacked PR 5/5 (Wave E). Depends on #3017.

Review follow-up

  • Empty OpenCodex snapshots (daily + sessions empty) are not treated as a present source, so hide-native cannot drop real Codex.
  • OpenCodex JSON provenance is always listPriceEstimate; projects stays empty.

Test plan

Fixtures only. No Keychain, no live accounts, no ~/.opencodex.

CODEXBAR_SUPPRESS_TEST_KEYCHAIN_ACCESS=1
make check
# Done linting! Found 0 violations, 0 serious in 1928 files.

CODEXBAR_SUPPRESS_TEST_KEYCHAIN_ACCESS=1 swift test --filter \
  'empty OpenCodex snapshots are not treated as a present source|openCodex JSON payload stays on a separate source'
✔ empty OpenCodex snapshots are not treated as a present source
✔ openCodex JSON payload stays on a separate source and omits invented projects
  • Focused empty-source and CLI JSON tests above
  • CODEXBAR_SUPPRESS_TEST_KEYCHAIN_ACCESS=1 swift test --filter CLICostTests
  • JSON includes provenance/coverage without a third schema
  • OpenCodex projects array stays empty

Co-authored-by: Cursor <cursoragent@cursor.com>
@clawsweeper

clawsweeper Bot commented Aug 17, 2026

Copy link
Copy Markdown

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

guard configuration.costUsageEnabled, !configuration.providerIDs.isEmpty else {

P2 Badge Allow an OpenCodex-only dashboard to load

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".

Comment on lines +915 to +916
private var sourceIDs: [String] {
Array(Set(self.model.groups.flatMap(\.providers).map(\.id))).sorted()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Comment on lines +500 to +504
guard let snapshot = try? store.loadSnapshot(
logURL: logURL,
now: request.now,
historyDays: Self.scanDays,
calendar: request.configuration.bucketCalendar)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Comment on lines +177 to +179
} else if entry.usageStatus == .reported || entry.usageStatus == .estimated {
day.unpriced += 1
if day.priced > 0 { day.priced -= 1 }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

@clawsweeper clawsweeper Bot added merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P2 Normal priority bug or improvement with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Aug 17, 2026
@clawsweeper

clawsweeper Bot commented Aug 17, 2026

Copy link
Copy Markdown

Codex review: needs real behavior proof before merge. Reviewed August 17, 2026, 4:12 PM ET / 20:12 UTC.

ClawSweeper review

What this changes

The 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
Reviewed head: a88875127838560d8705762c409d939cd6aab533
Owner decision: Required. See Decision needed.

Review scores

Measure Result What it means
Overall readiness 🧂 unranked krab (1/6) The branch has useful test work but remains blocked by three correctness defects and missing real behavior proof.
Proof confidence 🧂 unranked krab (1/6) Needs real behavior proof before merge: The PR reports fixture tests only; add redacted after-fix CLI output or an app recording for the opt-in behavior before merge. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Patch quality 🦪 silver shellfish (2/6) 3 actionable review findings remain.

Verification

Check Result Evidence
Real behavior Needs proof Needs real behavior proof before merge: The PR reports fixture tests only; add redacted after-fix CLI output or an app recording for the opt-in behavior before merge. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed 6 items Current main lacks the requested surface: Current main's CLI cost payload construction has no provenance, coverage, or OpenCodex payload handling, so this PR is not redundant.
Dashboard provenance is misclassified: Any included cost sets sawEstimate regardless of the snapshot's explicit provenance, so vendor-metered daily costs without a separate metered total are displayed as list-price estimates.
Total-only OpenCodex rows can become zero-cost rows: A total token count alone passes hasTokenData, then missing token classes are converted to zero before pricing; a known model can therefore be marked priced at $0 despite an unknowable token split.
Findings 3 actionable findings [P2] Preserve explicit vendor provenance in dashboard groups
[P2] Leave total-only OpenCodex rows unpriced
[P2] Stop fallback after a partial custom-price match
Security None None.

How this fits together

CodexBar 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]
Loading

Decision needed

Question Recommendation
Should CodexBar support this new opt-in OpenCodex ingestion path and expanded cost-JSON schema as a maintained public surface? Sponsor the supported surface: Define the compatibility contract, land the dependency, and require the identified fixes and real behavior proof before merge.

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

  • Add real behavior proof - Needs real behavior proof before merge: The PR reports fixture tests only; add redacted after-fix CLI output or an app recording for the opt-in behavior before merge. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
  • Preserve explicit vendor provenance in dashboard groups (P2) - A vendor-metered snapshot with daily cost but no separate meteredCostUSD sets sawEstimate here and is rendered as listPriceEstimate. Derive the group state from each included snapshot or window provenance instead of treating every cost as an estimate.
  • Leave total-only OpenCodex rows unpriced (P2) - A reported row with only totalTokens passes hasTokenData, then prices every token class as zero. Since the total cannot be split across differently priced classes, keep it unpriced rather than exporting or displaying a $0 estimate.
  • Stop fallback after a partial custom-price match (P2) - A matching custom-price entry with a required missing rate returns nil here, then falls through to bundled or models.dev pricing despite the overlay contract saying missing fields stay unknown. Distinguish no match from an incomplete match in both helpers.
  • Resolve merge risk (P1) - Existing strict consumers of codexbar cost --json may reject the expanded output schema.
  • Resolve merge risk (P1) - The branch depends on the still-open Surface token mix, coverage, sessions, and OpenCodex on the spend dashboard #3017, so its final landing order and rebase need confirmation.
  • Resolve merge risk (P1) - Fixture tests do not provide after-fix real CLI or app behavior proof for the opt-in source and exported output.
  • Complete next step (P2) - A maintainer must first sponsor the new public surface; the contributor then needs the three focused repairs and real behavior proof.
  • Improve patch quality - Add regressions for vendor provenance, total-only OpenCodex rows, and partial custom-price overlays.
  • Improve patch quality - Post redacted after-fix terminal output or a recording showing the opt-in source and JSON behavior.
  • Improve patch quality - After adding proof, update the PR body to trigger re-review; a maintainer can comment @clawsweeper re-review if needed.

Findings

  • [P2] Preserve explicit vendor provenance in dashboard groups — Sources/CodexBar/SpendDashboardModel.swift:464-472
  • [P2] Leave total-only OpenCodex rows unpriced — Sources/CodexBarCore/Vendored/OpenCodexUsage/OpenCodexUsageAggregator.swift:271-280
  • [P2] Stop fallback after a partial custom-price match — Sources/CodexBarCore/Vendored/CostUsage/CostUsagePricing+Overlay.swift:14-23
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Changed surface 73 files, +4,188 / -296 lines The stacked branch spans CLI export, persisted settings, dashboard aggregation, local log parsing, and tests.

Merge-risk options

Maintainer options:

  1. Repair reporting classification before merge (recommended)
    Preserve vendor provenance, leave total-only OpenCodex rows unpriced, and stop fallback after a matching incomplete custom-price overlay, each with focused regression coverage.
  2. Defer the public surface
    Pause the branch if maintainers do not want to commit to the new JSON and OpenCodex compatibility contract.

Technical review

Best 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:

  • [P2] Preserve explicit vendor provenance in dashboard groups — Sources/CodexBar/SpendDashboardModel.swift:464-472
    A vendor-metered snapshot with daily cost but no separate meteredCostUSD sets sawEstimate here and is rendered as listPriceEstimate. Derive the group state from each included snapshot or window provenance instead of treating every cost as an estimate.
    Confidence: 0.98
  • [P2] Leave total-only OpenCodex rows unpriced — Sources/CodexBarCore/Vendored/OpenCodexUsage/OpenCodexUsageAggregator.swift:271-280
    A reported row with only totalTokens passes hasTokenData, then prices every token class as zero. Since the total cannot be split across differently priced classes, keep it unpriced rather than exporting or displaying a $0 estimate.
    Confidence: 0.98
  • [P2] Stop fallback after a partial custom-price match — Sources/CodexBarCore/Vendored/CostUsage/CostUsagePricing+Overlay.swift:14-23
    A matching custom-price entry with a required missing rate returns nil here, then falls through to bundled or models.dev pricing despite the overlay contract saying missing fields stay unknown. Distinguish no match from an incomplete match in both helpers.
    Confidence: 0.99

Overall correctness: patch is incorrect
Overall confidence: 0.98

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against f7723d33a169.

Labels

Label justifications:

  • P2: Incorrect cost provenance and zero-cost classification affect reporting accuracy but have bounded blast radius.
  • merge-risk: 🚨 compatibility: The PR expands CLI JSON and persists new reporting preferences that existing consumers and upgrades may depend on.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🦪 silver shellfish.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR reports fixture tests only; add redacted after-fix CLI output or an app recording for the opt-in behavior before merge. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Evidence

What I checked:

Likely related people:

  • Peter Steinberger: Authored the available current-main merge commit; the grafted checkout does not retain earlier file-level ownership history for the affected paths. (role: recent default-branch contributor; confidence: low; commits: f7723d33a169)

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

History

Review history (1 earlier review cycle)
  • reviewed 2026-08-17T18:23:18.172Z sha 9da61af :: needs real behavior proof before merge. :: [P2] Keep hidden sources available in the filter | [P2] Require populated OpenCodex logs before hiding native data | [P2] Classify an unpriced estimated row only once | [P2] Use the pinned bucket calendar for CLI summaries

Yuxin-Qiao and others added 14 commits August 18, 2026 02:53
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>
@Yuxin-Qiao
Yuxin-Qiao force-pushed the feat/spend-e-export branch from 9da61af to a888751 Compare August 17, 2026 19:26
@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Aug 17, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event exact_review_queue).
Result: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

Re-review progress:

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment on lines +464 to +465
if summary.totalCost != nil {
sawEstimate = true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Comment on lines +271 to +275
let hasTokenData = entry.resolvedTotalTokens != nil
|| usage?.inputTokens != nil
|| usage?.outputTokens != nil
|| usage?.cacheReadTokens != nil
|| usage?.cacheCreationInputTokens != nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

Comment on lines +23 to +26
guard let pricing = self.resolvedCodexPricing(
model: model,
modelsDevCatalog: modelsDevCatalog,
modelsDevCacheRoot: modelsDevCacheRoot)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

steipete added a commit that referenced this pull request Aug 18, 2026
@steipete
steipete merged commit bbb5cd7 into steipete:main Aug 18, 2026
7 of 9 checks passed
@steipete

Copy link
Copy Markdown
Owner

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 opencodex-usage.sqlite beneath OPENCODEX_HOME, which violated the read-only contract; the cache now lives in CodexBar's own directory with a regression test. Everything else (provenance/timezone rebuilds, unknown-not-free overlay semantics, opt-in export gating) reviewed clean. The changelog credits you across all five.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P2 Normal priority bug or improvement with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants