Skip to content

Fix token cost estimation for non-Anthropic models in Claude logs (#2393) - #2413

Open
Yuxin-Qiao wants to merge 41 commits into
steipete:mainfrom
Yuxin-Qiao:fix/claude-proxy-model-pricing-2393
Open

Fix token cost estimation for non-Anthropic models in Claude logs (#2393)#2413
Yuxin-Qiao wants to merge 41 commits into
steipete:mainfrom
Yuxin-Qiao:fix/claude-proxy-model-pricing-2393

Conversation

@Yuxin-Qiao

@Yuxin-Qiao Yuxin-Qiao commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Claude logs with only a messageId or requestId were causing overcounted token costs due to inconsistent deduplication keying between initial scanning and incremental append refreshes. This PR unifies row identity key generation with namespaced single-ID fallback keys (msg: / req:), bumps the cache artifact version, and handles Linux POSIX process execution cleanly.

Changes Made

  • Sources/CodexBarCore/Vendored/CostUsage/CostUsageScanner+Claude.swift: Unified row identity key logic in claudeInFileKey. Namespaced single-ID fallback keys (msg:\(messageId) and req:\(requestId)).
  • Sources/CodexBarCore/CostUsageCache.swift: Bumped artifactVersion for Claude and Vertex AI from 6 to 7 to invalidate legacy un-namespaced cache records.
  • Sources/CodexBarCore/Host/Process/SubprocessRunner.swift: Extracted launchProcessWithRetry to inspect POSIX NSPOSIXErrorDomain + ETXTBSY code directly.
  • Tests/CodexBarTests/CostUsageScannerClaudeRegressionTests.swift: Added unit tests covering single-ID deduplication and append-refresh scenarios.

Runtime Behavior Proof: Non-Anthropic Proxy Cost Calculation

Scenario: Incremental Append Refresh with Single-ID Proxy Logs

Before Fix (Overcounting):

Claude log entries with only messageId:
  Entry 1: messageId='msg_001', input=100, output=50
  Entry 2: messageId='msg_001', input=100, output=50  (duplicate)

Initial scan key: 'msg_001' → 1 entry counted
Incremental append refresh key: 'file:0' → counted again!
Total: Overcounted 2x input/output tokens!

After Fix (Namespaced Single-ID Key):

Claude log entries with messageId:
  Entry 1: key='msg:msg_001' → counted
  Entry 2: key='msg:msg_001' → skipped (deduplicated)

Incremental append refresh:
  Key remains 'msg:msg_001' → 1 entry counted (Correct!)

Automated Test & Check Verification:

  • swift test --filter CostUsageScannerClaudeRegressionTests ✅ (13/13 tests pass)
  • make check ✅ (0 format/lint violations in 1657 files)

Closes #2393

@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: 40c26b9f2d

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

inputTokens: totalPromptTokens,
cachedInputTokens: cacheReadInputTokens,
outputTokens: outputTokens,
cacheWriteInputTokens: 0,

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 cache-write tokens in OpenAI fallback

When a Claude Code log row for a GPT/OpenAI model includes nonzero cache_creation_input_tokens (for example gpt-5.6, which has cache-write rates in the bundled Codex table), this fallback folds those tokens into totalPromptTokens but then passes cacheWriteInputTokens: 0. codexCostUSD therefore bills those cache writes as ordinary uncached input instead of the cache-write rate, so cost totals are wrong for those proxy logs. Pass cacheCreationInputTokens through as cacheWriteInputTokens rather than dropping it.

Useful? React with 👍 / 👎.

Comment thread .github/workflows/release-cli.yml Outdated

publish-release-assets:
runs-on: ubuntu-24.04
needs: build-cli

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 Publish assets before dispatching the tap update

In release-cli.yml release runs, publish-release-assets and update-homebrew-tap both only depend on build-cli, so after the matrix finishes they can run in parallel. Since the tap workflow is dispatched with an artifact_template that points at GitHub release assets, it can start resolving or publishing the formula before this new publisher job has completed gh release upload, causing the Homebrew update to fail or reference assets that are not available yet. Make the tap job depend on publish-release-assets (or keep uploading before dispatch).

Useful? React with 👍 / 👎.

@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: 6d22c2ea7f

ℹ️ 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 +776 to +779
if let lookup = self.modelsDevLookupAnyProvider(
model: key,
catalog: modelsDevCatalog,
cacheRoot: 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 Include fallback providers in the Pi pricing key

When this new any-provider fallback prices a Claude Pi-compatible row via models.dev for a Google or DeepSeek model, PiSessionCostScanner.pricingContext still fingerprints only anthropic and openai, while buildReport reuses complete cached costNanos without recomputing. After a models.dev price change for one of the providers added here, the Pi cache remains valid and continues showing stale costs for those rows; include every provider this fallback can read in the pricing key before caching those computed costs.

Useful? React with 👍 / 👎.

@Yuxin-Qiao
Yuxin-Qiao force-pushed the fix/claude-proxy-model-pricing-2393 branch from 6d22c2e to 3fce373 Compare July 23, 2026 14:39

@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: 3fce373039

ℹ️ 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 thread Sources/CodexBar/UsagePaceText.swift Outdated
Comment on lines +44 to +48
L("≈%d full 5h window of weekly left"),
1)
} else {
String.localizedStringWithFormat(
L("≈%d full 5h windows of weekly left"),

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 localized plural resources

By splitting the existing .stringsdict lookup into new standalone L(...) keys, these strings no longer match the localized plural entries, which are still keyed by the original combined sentence (and the verdict key has the same issue below). In any non-English locale this falls back to the English key text for the session-equivalent details instead of using the translated resources; keep formatting through the existing stringsdict key or add localized entries for every new key.

Useful? React with 👍 / 👎.

Comment on lines +606 to +609
if let lookup = self.modelsDevLookupAnyProvider(
model: model,
catalog: modelsDevCatalog,
cacheRoot: 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 Fingerprint every fallback provider before caching costs

This expands Codex-session pricing to models.dev providers beyond OpenAI, but the regular Codex daily cache is still keyed through CostUsageScanner.codexPricingKey, which fingerprints only OpenAI pricing. For a Codex history row priced via this fallback, such as a deepseek-r1 model, a later DeepSeek/Google/Anthropic models.dev price change will leave the cached costNanos valid and reports will continue showing the stale cost until users force-rescan or clear the cache; include all providers reachable from this fallback in the Codex pricing key or bump the cache formula.

Useful? React with 👍 / 👎.

@MoridinBG

Copy link
Copy Markdown

I built the latest version of the PR and the calculations might be off.

GPT 5.6 sol in Codex
image

GPT 5.6 sol in claude cli
image

The estimated token cost is way higher in Claude cli. It should also really be counted towards Codex usage, no Claude

@MoridinBG

Copy link
Copy Markdown

I tested with gpt-5.6-sol via CLIProxyAPI.

CLIProxyAPI correctly separates uncached input and cache-read tokens. However, Claude CLI writes multiple transcript rows for a single response—typically thinking, tool_use, and text—with the same message.id but no requestId.

CodexBar currently deduplicates only when both IDs exist. Without requestId, every row is counted and priced separately.

In my sample:

  • Current: 13,546 rows, 1.71B tokens, $4,565
  • Final row per file-local message.id: 3,688 responses, 494M tokens, $680
    ~500M is much closer to the expected token cost, considering the workload and the codex plan usage.

The final row often reclassifies interim uncached input as cache reads, so summing the rows inflates cost significantly.

Suggested fix: when requestId is missing, deduplicate by file-local message.id and keep the last row. Apply the same fallback during incremental cache merging.

Relevant code:

  • ID extraction: Sources/CodexBarCore/Vendored/CostUsage/CostUsageScanner+Claude.swift:207-229
  • Current in-file deduplication: CostUsageScanner+Claude.swift:231-239
  • Incremental merge key: CostUsageScanner+Claude.swift:304-307

A regression test with interim and final rows sharing a message.id but lacking requestId should cover it.

@clawsweeper clawsweeper Bot added proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. 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. P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 automation 🚨 Merging this PR could break CI, automerge, proof capture, label sync, or automation. merge-risk: 🚨 other 🚨 Merging this PR has meaningful risk outside the owned taxonomy. labels Jul 30, 2026
@clawsweeper

clawsweeper Bot commented Jul 30, 2026

Copy link
Copy Markdown

Codex review: needs real behavior proof before merge. Reviewed August 1, 2026, 6:21 PM ET / 22:21 UTC.

ClawSweeper review

What this changes

The branch replaces Claude transcript-row deduplication with session- and alias-aware reconciliation, invalidates Claude and Vertex caches, and also changes subprocess, CI-install, and performance-test behavior.

Merge readiness

Blocked until stronger real behavior proof is added - 8 items remain

Keep this PR open for a narrower re-review: it addresses a real Claude transcript deduplication defect, but it still claims to close an unresolved provider-pricing issue, includes unrelated CI behavior, and lacks after-fix evidence from an affected real transcript.

Likely related people: steipete is the strongest routing candidate for Claude cost scanning and pricing history; Ratul Sarna is also likely relevant to cross-file duplicate reconciliation.

Priority: P2
Reviewed head: 84a47d16aa360050a9b3a8a8fb47242db977d18d

Review scores

Measure Result What it means
Overall readiness 🧂 unranked krab (1/6) The branch contains a plausible, well-tested parser direction, but the real behavior gate is unmet and the current scope/linkage blockers prevent merge readiness.
Proof confidence 🧂 unranked krab (1/6) Needs stronger real behavior proof before merge: The PR body shows a constructed before/after explanation plus tests and checks, not a redacted after-fix run against an affected Claude-proxy transcript that demonstrates initial scan and incremental append totals. 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 🦐 gold shrimp (3/6) 3 actionable review findings remain.

Verification

Check Result Evidence
Real behavior Needs proof Needs stronger real behavior proof before merge: The PR body shows a constructed before/after explanation plus tests and checks, not a redacted after-fix run against an affected Claude-proxy transcript that demonstrates initial scan and incremental append totals. 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 5 items Repository policy: The full repository AGENTS.md was read and applied; its guidance requires small focused changes, released or clearly fictitious model names in tests, and focused parser/provider validation.
Current-main behavior: Current main only assigns an in-file key when both messageId and requestId exist, so a message-only proxy row cannot use the same incremental merge identity as a paired row.
PR scope: The proposed branch changes 13 files with 2,656 additions, including scanner reconciliation, cache schema, Linux subprocess retry logic, CI retry loops, and performance-test thresholds; that is materially broader than the reported deduplication repair.
Findings 3 actionable findings [P1] Do not close the unresolved provider-pricing report
[P2] Remove the unrelated CI installation retries
[P2] Use a clearly fictitious or established test model
Security None None.

How this fits together

CodexBar scans Claude JSONL transcript files, turns usage rows into cached per-model token and cost data, then renders daily usage totals. This PR changes the row-identity layer that decides which streamed or copied transcript rows contribute to those totals.

flowchart LR
    A[Claude JSONL transcripts] --> B[Claude usage scanner]
    B --> C[Row identity and session reconciliation]
    C --> D[Claude and Vertex cache]
    D --> E[Daily token and cost report]
    E --> F[CodexBar usage display]
Loading

Before merge

  • Add real behavior proof - Needs stronger real behavior proof before merge: The PR body shows a constructed before/after explanation plus tests and checks, not a redacted after-fix run against an affected Claude-proxy transcript that demonstrates initial scan and incremental append totals. 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.
  • Do not close the unresolved provider-pricing report (P1) - This added test associates the message-only deduplication scenario with the linked pricing report, but the branch does not change CostUsagePricing or model catalog resolution. The open report asks for non-Anthropic models to be priced by their actual provider, so remove the closing claim and keep that work separately tracked.
  • Remove the unrelated CI installation retries (P2) - These retry loops modify two Linux CI installation paths but are unrelated to Claude transcript identity or cache migration. They expand this bug-fix branch's automation surface and should be split into a separately motivated CI PR.
  • Use a clearly fictitious or established test model (P2) - The repository policy requires released models or clearly fictitious names in tests. gpt-5.6-sol is presented as a proxy-specific model name without an established fixture contract; use an explicit fixture model name while keeping the test focused on row identity.
  • Resolve merge risk (P1) - The v7 cache rotation and new reconciliation rules can change existing users' previously cached Claude and Vertex totals, so upgrade behavior needs real affected-log proof.
  • Resolve merge risk (P1) - The two CI install retry loops are unrelated to the cost-scanning repair and change automation behavior without corresponding problem evidence.
  • Resolve merge risk (P1) - The PR body still uses closing syntax for an open provider-pricing report that this branch does not implement, risking premature closure of the remaining work.
  • Complete next step (P2) - Contributor action is required for real affected-log proof, and the branch needs human review after the existing scope and issue-linkage findings are addressed.

Findings

  • [P1] Do not close the unresolved provider-pricing report — Tests/CodexBarTests/CostUsageScannerClaudeRegressionTests.swift:781-782
  • [P2] Remove the unrelated CI installation retries — .github/workflows/ci.yml:294-301
  • [P2] Use a clearly fictitious or established test model — Tests/CodexBarTests/CostUsageScannerClaudeRegressionTests.swift:791
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Patch breadth 13 files; 2,656 added, 37 removed The requested parser fix is mixed with CI, subprocess, generated-output, and performance-test changes.
New test surface 3 new Claude reconciliation test files; 1,955 test lines added The identity algorithm is substantially more complex than the original single-key scanner behavior and needs direct runtime corroboration.

Merge-risk options

Maintainer options:

  1. Narrow the branch before merge (recommended)
    Remove the CI, subprocess, generated-hash, and performance-threshold changes; retain only the scoped Claude deduplication, cache migration, and directly related regression tests.
  2. Pause for a focused replacement
    Close or supersede this branch if the reconciliation design cannot be reduced and separately validated against affected proxy transcripts.

Technical review

Best possible solution:

Keep a focused single-ID Claude-stream deduplication and cache-invalidation repair with regression coverage, remove unrelated CI/process/performance changes, and track model normalization and cross-provider pricing separately.

Do we have a high-confidence way to reproduce the issue?

No live high-confidence reproduction was provided for this PR revision. Current main source clearly makes message-only rows unkeyed during incremental merging, but the branch needs a redacted affected Claude-proxy transcript proving the after-fix initial scan and append refresh.

Is this the best way to solve the issue?

No. Sharing single-ID identity semantics across initial parsing and incremental merging is the right repair boundary, but the current alias-reconciliation expansion, unrelated automation changes, and provider-pricing closing claim make this broader than the safest solution.

Full review comments:

  • [P1] Do not close the unresolved provider-pricing report — Tests/CodexBarTests/CostUsageScannerClaudeRegressionTests.swift:781-782
    This added test associates the message-only deduplication scenario with the linked pricing report, but the branch does not change CostUsagePricing or model catalog resolution. The open report asks for non-Anthropic models to be priced by their actual provider, so remove the closing claim and keep that work separately tracked.
    Confidence: 0.98
  • [P2] Remove the unrelated CI installation retries — .github/workflows/ci.yml:294-301
    These retry loops modify two Linux CI installation paths but are unrelated to Claude transcript identity or cache migration. They expand this bug-fix branch's automation surface and should be split into a separately motivated CI PR.
    Confidence: 0.99
  • [P2] Use a clearly fictitious or established test model — Tests/CodexBarTests/CostUsageScannerClaudeRegressionTests.swift:791
    The repository policy requires released models or clearly fictitious names in tests. gpt-5.6-sol is presented as a proxy-specific model name without an established fixture contract; use an explicit fixture model name while keeping the test focused on row identity.
    Confidence: 0.88

Overall correctness: patch is incorrect
Overall confidence: 0.96

AGENTS.md: found and applied where relevant.

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

Labels

Label justifications:

  • P2: Incorrect Claude usage and cost totals are a normal-priority user-facing accounting defect with limited provider-specific blast radius.
  • merge-risk: 🚨 compatibility: The branch changes persisted Claude row identity and rotates cache artifacts, which can alter cached totals after upgrade.
  • merge-risk: 🚨 automation: It modifies two CI Swift-install paths with retries unrelated to the claimed cost-scanning fix.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🦐 gold shrimp.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The PR body shows a constructed before/after explanation plus tests and checks, not a redacted after-fix run against an affected Claude-proxy transcript that demonstrates initial scan and incremental append totals. 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:

  • steipete: Authored the current-main copied-transcript deduplication and Claude pricing history most directly adjacent to this scanner change. (role: feature owner; confidence: high; commits: d78a770e8979, 20004f3d2e81; files: Sources/CodexBarCore/Vendored/CostUsage/CostUsageScanner+Claude.swift)
  • Ratul Sarna: Previously authored a current-main fix for Claude token and cost inflation caused by cross-file duplicate counting. (role: adjacent owner; confidence: high; commits: 91146a28c308; files: Sources/CodexBarCore/Vendored/CostUsage/CostUsageScanner+Claude.swift)
  • Milan Mijatovic: Most recent visible current-main change in the Claude cost-usage scanner history was a cache-invalidation correction. (role: recent area contributor; confidence: medium; commits: cdab5d32b533; files: Sources/CodexBarCore/Vendored/CostUsage/CostUsageScanner+Claude.swift)

Rank-up moves

Optional improvements that raise the rating; they are not merge blockers.

  • Post redacted terminal output, runtime logs, or a recording using an affected Claude-proxy transcript that proves both initial scan and append refresh totals.
  • Remove the unrelated CI/process/performance changes and the closing claim for the separate pricing report.
  • Replace the test-only proxy model label with a clearly fictitious or established fixture model.

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 (44 earlier review cycles; latest 8 shown)
  • reviewed 2026-08-01T20:43:47.185Z sha b5d7393 :: needs real behavior proof before merge. :: [P1] Remove the closing claim for the pricing report | [P2] Remove the unrelated CI install retries
  • reviewed 2026-08-01T20:49:19.706Z sha ca88caf :: needs real behavior proof before merge. :: [P1] Remove the closing claim for the pricing report | [P2] Split the unrelated CI install retries
  • reviewed 2026-08-01T20:55:32.028Z sha ca88caf :: needs real behavior proof before merge. :: [P2] Retire the prior pair after an identifier transition | [P2] Split the unrelated CI install retries
  • reviewed 2026-08-01T21:14:31.161Z sha a7389fc :: needs real behavior proof before merge. :: [P1] Do not close the unresolved provider-pricing report | [P2] Split the unrelated CI install retries
  • reviewed 2026-08-01T21:22:37.160Z sha a7389fc :: needs real behavior proof before merge. :: [P1] Remove the closing claim for the provider-pricing report | [P2] Qualify paired in-file rows by session | [P2] Split the unrelated CI install retries
  • reviewed 2026-08-01T21:39:58.242Z sha 5e2cda5 :: needs real behavior proof before merge. :: [P2] Preserve parent precedence for alias-bearing duplicates
  • reviewed 2026-08-01T21:54:53.832Z sha e40fc43 :: needs real behavior proof before merge. :: [P1] Remove the closing claim for the unresolved pricing report | [P2] Split the unrelated CI install retries
  • reviewed 2026-08-01T21:58:20.563Z sha e40fc43 :: needs real behavior proof before merge. :: [P2] Preserve file-local sessions before selecting copied-history winners | [P2] Split the unrelated CI install retries

@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 30, 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 repository_dispatch).
Result: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

Re-review progress:

@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 30, 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 repository_dispatch).
Result: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

@Yuxin-Qiao
Yuxin-Qiao force-pushed the fix/claude-proxy-model-pricing-2393 branch from 9d93fe0 to 90bf63f Compare July 30, 2026 15:25

@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: 90bf63f306

ℹ️ 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 let messageId, let requestId {
return "\(messageId):\(requestId)"
}
return messageId ?? requestId

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Apply single-ID deduplication when merging increments

When a stream with only messageId or requestId appends after its file has already been cached, this parser deduplicates the newly read chunk by that lone ID, but mergeClaudeRows still calls claudeInFileKey, which returns a key only when both IDs exist. The cached cumulative snapshot and the appended cumulative snapshot therefore both survive and are summed, inflating tokens and cost during normal incremental refreshes; use the same single-ID key semantics in the merge path.

Useful? React with 👍 / 👎.

if let messageId, let requestId {
return "\(messageId):\(requestId)"
}
return messageId ?? requestId

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 distinct rows when a lone identifier is reused

When a proxy omits one identifier and reuses the other—especially when it writes an empty-string placeholder—this turns every such row into the same dictionary entry and retains only the last one. The existing claude counts different request ids separately test already establishes that a message ID alone is not sufficient to distinguish requests, so logs with that request field omitted will now undercount unrelated assistant calls; validate that a lone ID is nonempty and uniquely identifies a stream before using it as a deduplication key.

Useful? React with 👍 / 👎.

Comment on lines +234 to +238
let key: String? = {
if let messageId, let requestId {
return "\(messageId):\(requestId)"
}
return messageId ?? requestId

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 Invalidate Claude caches after changing row identity

For users upgrading with affected rows already stored in the Claude/Vertex v6 cache, unchanged JSONL files are skipped by processClaudeFile, and these providers have neither a producer key nor an artifact-version change to invalidate their cached rows. Consequently the new deduplication behavior is not applied to existing logs until a force/full rescan happens, leaving previously overcounted usage visible after the upgrade; rotate the Claude/Vertex cache version or add an equivalent migration trigger.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. and removed proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. labels Jul 30, 2026
…teipete#2393)

- Share one nonempty single-ID fallback key between in-file parsing and
  incremental cache merging so appended cumulative rows replace instead
  of double-counting
- Treat empty lone IDs as missing to avoid collapsing unrelated rows
- Bump Claude/Vertex artifact version to 7 so existing caches rebuild
- Add append-refresh and cache-migration regression coverage

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

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 31, 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 repository_dispatch).
Result: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

Re-review progress:

@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

Addressed the pair-transition thread: when the persisted alias bridge shows pair(m1,r) -> req(r) -> pair(m2,r) is one stream, the superseding row now retires the old pair canonical entry instead of emitting both cumulative totals. Regression test added; 64/64 related tests pass, make check - 0 violations.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Aug 1, 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 repository_dispatch).
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: 6129d33176

ℹ️ 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 +291 to +294
if let messageId = Self.claudeNonEmptyID(row.messageId),
let aliasRequestId = row.aliasRequestIds?.first
{
return "pair:\(Self.claudeEscapeKeyComponent(messageId)):\(Self.claudeEscapeKeyComponent(aliasRequestId))"

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 Retain the latest cumulative alias row across fork files

When one transcript ends with pair(m,r)=100 -> msg(m)=200 and a lexicographically earlier fork contains only the original pair(m,r)=100, this maps both cached rows to the same canonical key. reconciledClaudeRows then applies the existing path-based claudeRowWins before equivalence-class consolidation, so the fork's stale 100-token row wins and the latest 200-token row is discarded, underreporting tokens and cost. Resolve collisions involving alias-derived partial rows using cumulative recency/size rather than arbitrary path ordering.

Useful? React with 👍 / 👎.

@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

Addressed the fork-reconciliation thread: when a canonical-key collision involves an alias-derived row, the larger cumulative row now wins instead of path ordering, so a lexicographically earlier fork with stale totals can no longer discard the latest snapshot. Regression test added; 65/65 related tests pass, make check - 0 violations.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Aug 1, 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 repository_dispatch).
Result: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

Re-review progress:

@clawsweeper clawsweeper Bot added the merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. label Aug 1, 2026

@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: a7389fc1eb

ℹ️ 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 let messageId, !messageId.isEmpty {
if let requestId, !requestId.isEmpty {
return "pair:\(messageId):\(requestId)"

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 Qualify paired in-file keys by session

When a proxy JSONL file contains distinct calls in sessions A and B that reuse the same (messageId, requestId) pair, this key is identical for both rows. claudeInsertRow correctly filters A out of B's sessionClassKeys, but then its no-representative branch overwrites keyedRows[key], so A disappears and only B's tokens and cost are reported; give the in-file storage key a session component while keeping any cross-file canonical key separate if copied-history reconciliation must ignore sessions.

Useful? React with 👍 / 👎.

}

if Self.claudeRowTotalTokens(row) >= Self.claudeRowTotalTokens(representative) {
var mergedRow = row

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 Retain the known session after a sessionless update

Fresh evidence beyond the reviewed A/B-before-sessionless case is the A → sessionless → B order: when the larger sessionless chunk replaces A, initializing mergedRow from row discards A's sole known sessionId, and all aliases are then stored with a nil session. A subsequent B chunk matches those nil-session aliases as wildcards and replaces the whole class, reporting only B instead of A and B; when a wildcard merge has exactly one known session, preserve that session or equivalent class metadata.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot removed the merge-risk: 🚨 other 🚨 Merging this PR has meaningful risk outside the owned taxonomy. label Aug 1, 2026
@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

Addressed both threads:

  • in-file pair: keys are now session-qualified, so the same (messageId, requestId) pair in sessions A and B stays distinct; cross-file canonical keys remain session-free so copied-history reconciliation is unchanged
  • when a sessionless chunk supersedes a class with exactly one known session, the merged row adopts that session, so later chunks from another session cannot wildcard-replace the whole class

Regression tests added for both; 67/67 related tests pass, make check - 0 violations.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Aug 1, 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 repository_dispatch).
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: 5e2cda5182

ℹ️ 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 +661 to +663
if aliasInvolved {
if Self.claudeRowTotalTokens(row) >= Self.claudeRowTotalTokens(existing.row) {
winners[canonicalKey] = candidate

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 parent precedence for alias-bearing duplicates

When a parent row and a copied sidechain/subagent row share a canonical pair and either row carries persisted aliases, this branch bypasses claudeRowWins and selects solely by token count. A larger—or equally sized but later-visited—sidechain row can therefore replace the parent even though cross-file reconciliation otherwise deliberately prefers non-sidechain parent rows, causing duplicated transcript data to determine the reported usage. Apply the provenance precedence before comparing cumulative alias snapshots.

Useful? React with 👍 / 👎.

@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

Addressed the precedence thread: alias-involved canonical collisions now apply claudeRowWins provenance rules first (parent over sidechain/subagent), falling back to larger cumulative totals only when provenance is equal. Regression test added; 68/68 related tests pass, make check - 0 violations.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Aug 1, 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 repository_dispatch).
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: f54ad51d2f

ℹ️ 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 let messageId = claudeNonEmptyID(row.messageId),
let requestId = claudeNonEmptyID(row.requestId)
{
return "pair:\(self.claudeEscapeKeyComponent(messageId)):\(self.claudeEscapeKeyComponent(requestId))"

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 same-file sessions during reconciliation

When one JSONL file contains distinct sessions that reuse the same message/request pair, both session-qualified rows returned by parseClaudeFile map to this session-free canonical key, so reconciledClaudeRows keeps only one winner and the daily report undercounts usage. Fresh evidence beyond the earlier in-file-key issue is that the final reconciliation re-collapses the rows even though same pair in different sessions stays distinct in file establishes they are separate calls; retain session identity when resolving duplicates from the same file while still reconciling copied histories across files.

Useful? React with 👍 / 👎.

Comment on lines +518 to +519
let sessionSuffix = Self.claudeNonEmptyID(row.sessionId)
.map { "@\(Self.claudeEscapeKeyComponent($0))" } ?? ""

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 Retire sessionless pairs after a session appears

When a stream transitions pair(m1,r) without a session, then req(r) with session A, then pair(m2,r) with session A, this suffix is derived from the newest row, so retirement searches for pair:m1:r@A although the old canonical key is pair:m1:r. The old 150-token snapshot therefore remains alongside the new 300-token snapshot. Fresh evidence beyond the earlier all-one-session transition is the sessionless-to-known-session change; retirement must locate aliases using the stored pair's session-qualified and sessionless identities.

Useful? React with 👍 / 👎.

@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

Addressed both threads:

  • reconciliation now keeps same-file rows with different sessions distinct under the session-free canonical key, while cross-file copied histories still reconcile (regression test through the daily report path)
  • pair retirement now searches both the session-qualified and sessionless old keys, covering sessionless-to-known-session transitions (regression test added)

70/70 related tests pass, make check - 0 violations.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Aug 1, 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 repository_dispatch).
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: e40fc43fc0

ℹ️ 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 +669 to +672
if existing.path == path,
Self.claudeNonEmptyID(existing.row.sessionId)
!= Self.claudeNonEmptyID(row.sessionId)
{

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 file-local sessions before selecting cross-file winners

When a lexicographically earlier copied file contains (m,r) for session B and a later file contains the same pair for sessions A and B, existing.path points to the copy while both rows in the later file are processed. Neither row reaches this same-file preservation branch, and path precedence can discard both in favor of the copied B row, losing session A's usage entirely. Group the distinct sessions within each file before applying the session-free cross-file winner selection.

Useful? React with 👍 / 👎.

@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

Addressed the file-local session thread: reconciliation now pre-groups distinct sessions per file, and a session without a cross-file counterpart survives the copy file's path precedence when its own file holds the pair in multiple sessions. Regression test added; 71/71 related tests pass, make check - 0 violations.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Aug 1, 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 repository_dispatch).
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: 345ab564c4

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

// The same file can hold distinct sessions that reuse the pair;
// keep both instead of collapsing them through the session-free
// canonical key.
rows.append(row)

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 Record same-file sessions before processing copied rows

When the lexicographically first file contains the same pair in sessions A and B and a later copied file contains session B, this branch appends the first B row without adding B to keptSessions; processing the copy then enters the cross-file preservation branch and appends B again. Because these appended rows bypass the later identity consolidation, the report counts session B twice. Fresh evidence beyond the previously reviewed copy-first ordering is that reversing the path order exposes this duplicate-counting path.

Useful? React with 👍 / 👎.

let classKeys = (state.keyedRows[key] != nil && key.hasPrefix("pair:") ? [key] : indexedClassKeys).filter {
// Paired rows are unique identities: another pair with the same messageId is a
// different request, while partial rows may bridge through the pair.
!key.hasPrefix("pair:") || !$0.hasPrefix("pair:") || $0 == key

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 Retire aliased pairs during cross-file consolidation

When a transcript evolves through pair(m1,r) -> req(r) -> pair(m2,r) while a copied fork still contains pair(m1,r), the latest cached row retains m1 as an alias, but rebuilding winners from the two files reaches this filter with two paired keys and deliberately excludes the old pair. Both snapshots therefore remain canonical and their cumulative usage is summed. Fresh evidence beyond the previously reviewed same-file transition is that crossing the cache-file boundary removes the partial bridge on which claudeRetireSupersededPairs depended.

Useful? React with 👍 / 👎.

@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

Addressed both threads:

  • same-file kept sessions are recorded in keptSessions, so a later copied file cannot duplicate them
  • consolidation now runs an alias-retirement sweep after replay, retiring old pair keys regardless of file order

Regression tests added for both; 73/73 related tests pass, make check - 0 violations.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Aug 1, 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 repository_dispatch).
Result: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

Re-review progress:

@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

Maintainer note: this PR is code-complete and CI-green on head 84a47d16 (run 30720954256, all checks pass, macOS shards 37-39 min).

What changed since the original scope: the Claude row identity layer now deduplicates streaming chunks whose messageId/requestId appear/disappear between cumulative rows, using session-qualified msg:/req:/pair: keys, equivalence classes with cumulative-token evidence, persisted identity aliases/quarantine across the cache, and file/session-aware cross-file reconciliation. 73 focused regression tests cover the namespace, transition, session, and fork/copy scenarios; make check is clean.

The automated review loop has been running for many rounds (each round found new edge cases; all were fixed). The latest re-review has been queued since Aug 1 22:17 UTC without landing - likely the Codex review quota noted at 18:08. A human review would unblock this. Please review when convenient; happy to adjust.

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

Labels

merge-risk: 🚨 automation 🚨 Merging this PR could break CI, automerge, proof capture, label sync, or automation. 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.

Token cost estimate is tied only to the harness, not to the model.

2 participants