Skip to content

fix(codex): count unreported compaction usage - #1821

Merged
ryoppippi merged 5 commits into
mainfrom
codex/count-codex-compaction-usage
Oct 2, 2026
Merged

ryoppippi merged 5 commits into
mainfrom
codex/count-codex-compaction-usage

Conversation

@ryoppippi

@ryoppippi ryoppippi commented Oct 2, 2026 •

Copy link
Copy Markdown
Member

Codex remote compaction can persist provider usage without adding it to the cumulative token_count totals, causing ccusage reports to omit those requests. Pair token_usage_record and compacted entries by response ID, and add only usage that an intervening cumulative snapshot has not already counted. The distinction follows Codex's remote compaction path and local compaction path.

Copied compaction responses are counted once, including when a fork's parent is outside the selected date range. Parent history retains matched response IDs even when cumulative snapshots already account for their usage, protecting retained child logs with a missing snapshot. Serial and parallel aggregation retain the same session, timestamp, model attribution, and merged speed tier. A separate follow-up commit fixes whitespace-sensitive JSON classification exposed by the CLI regression checks.

Supersedes #1805, based on @HenryTeo27's contribution. Henry Teo is credited as a co-author of the implementation commit. The documentation explains the local-log coverage and inferred model attribution.

Validation:

  • Codex adapter: 125 tests passed.
  • Workspace Rust tests, Clippy with -D warnings, formatting, and secret checks passed through the push hooks.
  • just typecheck and just test passed.
  • Synthetic CLI checks: daily, monthly, and session JSON/table output; serial/parallel parity; date-bounded fork replay.
  • Claude CLI review: fixed the date-bounded replay finding; follow-up reviews of the implementation, JSON whitespace handling, and parent-history fix found no established correctness bugs.

Summary by CodeRabbit

  • Bug Fixes

    • Improved Codex usage reports to count automatic compaction usage accurately, including when records arrive in different orders or appear across replayed sessions.
    • Prevented duplicate usage across copied records and avoided counting compaction usage already reflected in cumulative totals.
    • Improved model attribution and cost estimates when model details are missing, without changing token totals.
  • Documentation

    • Clarified how retained local logs, date ranges, and pricing aliases affect Codex usage reports.

ryoppippi and others added 2 commits October 2, 2026 13:52
Match token_usage_record responses to compacted markers and add usage
omitted from Codex's cumulative token counts. Suppress records already
covered by an advancing snapshot so local compaction stays counted once.

Deduplicate response IDs across copied sessions, including parents outside
the report's date range, and preserve deterministic attribution and speed
tier merging in serial and parallel aggregation.

Rework the contribution from #1805 for the current adapter.

Co-authored-by: Henry Teo <[email protected]>
Allow the line classifier to fall back to its whitespace-aware scan for
turn contexts and nested token counts with spaces after type colons.
This prevents valid JSONL from silently omitting normal request usage
when calculating totals alongside compaction records.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
ccusage-guide abe086f Commit Preview URL

Branch Preview URL
Oct 02 2026, 09:34 PM

@coderabbitai

coderabbitai Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 5a85654d-7733-4b58-8017-37131a2c8c4b

📥 Commits

Reviewing files that changed from the base of the PR and between dbac9e6 and abe086f.

📒 Files selected for processing (3)
  • rust/adapters/codex/src/README.md
  • rust/adapters/codex/src/compaction_tests.rs
  • rust/adapters/codex/src/parser.rs
💤 Files with no reviewable changes (1)
  • rust/adapters/codex/src/parser.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • rust/adapters/codex/src/README.md

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 6 remain after this review.


📝 Walkthrough

Walkthrough

Codex now parses automatic compaction usage from session logs, filters compactions replayed from parent sessions, and deduplicates copied compaction events during report aggregation. Documentation and regression tests cover matching, attribution, replay, and cumulative usage handling.

Changes

Codex compaction accounting

Layer / File(s) Summary
Parse response-linked compaction usage
rust/adapters/codex/src/types.rs, rust/adapters/codex/src/parser.rs, rust/adapters/codex/src/lib.rs, rust/adapters/codex/src/compaction_tests.rs, rust/crates/ccusage/src/main.rs
Codex payloads and events carry response IDs. Session parsing matches usage records to compaction markers, checks cumulative usage, and emits qualifying usage without changing the active turn model or cumulative baseline. Tests and fixtures cover the event shape and parser behavior.
Filter replayed compactions
rust/adapters/codex/src/parser.rs, rust/adapters/codex/src/replay.rs, rust/adapters/codex/src/loader.rs, rust/adapters/codex/src/compaction_tests.rs
Replay planning tracks parent compaction IDs and timestamps. Session loading skips replayed compactions and deduplicates loaded events by response ID when available. Tests cover parent-child replay and bounded reports.
Deduplicate compactions in reports
rust/adapters/codex/src/aggregate.rs, rust/adapters/codex/src/compaction_tests.rs, rust/adapters/codex/src/README.md, docs/guide/codex/index.md
Aggregation deduplicates compactions by response ID, keeps attribution from the earliest file, and merges service tiers. Tests cover report modes, serial and parallel loading, and duplicate events. Documentation describes the accounting rules and reporting limits.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~45 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant CodexSessionParser
  participant CodexReplayPlan
  participant CodexSessionLoader
  participant CodexAggregator
  CodexSessionParser->>CodexReplayPlan: Parent compaction IDs and timestamps
  CodexSessionLoader->>CodexReplayPlan: Check child path and response ID
  CodexReplayPlan-->>CodexSessionLoader: Whether compaction is replayed
  CodexSessionLoader->>CodexAggregator: Retained usage events
  CodexAggregator->>CodexAggregator: Deduplicate compactions by response ID
Loading

Merge Risk: ⚪ Minimal · up to abe08

No actionable merge-blocking risk is identified for the Codex compaction accounting change; it is mergeable after normal checks.

Architecture Summary

Architecture risk: 🔵 Low · up to abe08

The change affects 2 systems.

Changed systems: rust, docs

Architecture concerns
No architecture-level concerns identified.

Review details

Systems and components

  • observed — rust (service) was modified; 9 changed files map to changed impact.
  • observed — docs (service) was modified; 1 changed file maps to changed impact.

Before / after behavior

  • observed — Modified behavior in docs/guide/codex/index.md: Adds documentation of the conditions for counting automatic compaction usage, deduplication of copied response IDs across reports, fallback model selection, and preservation of the normal cumulative baseline.
  • observed — Modified behavior in docs/guide/codex/index.md: Adds a notice that reports use retained local logs, missing compaction records cannot be recovered from markers alone, and pricing aliases affect cost estimates but not token totals or identification of an unrecorded backend model.
  • observed — Modified behavior in rust/adapters/codex/src/aggregate.rs: Adds FxHashSet and defines separate deduplication-key variants: response ID for compaction events and a structured usage key for ordinary events.
  • observed — Modified behavior in rust/adapters/codex/src/aggregate.rs: Adds compaction metadata to each deduplication record: the source file index, parsed timestamp, and copied usage event.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 55.88% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 68 functions across 8 files. (1 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: counting Codex compaction usage that was not included in cumulative totals.
Full details: Docstring Coverage

Explanation

Docstring coverage is 55.88% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 68 functions across 8 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ryoppippi

Copy link
Copy Markdown
Member Author

@coderabbitai @cubic-dev-ai Please review this replacement for #1805, especially suppression of compaction usage already included in cumulative token counts, fork replay when the parent falls outside the date range, and deterministic serial/parallel attribution. Claude CLI has also reviewed the implementation; its date-bounded replay finding is fixed and covered by a regression test.

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai @cubic-dev-ai Please review this replacement for #1805, especially suppression of compaction usage already included in cumulative token counts, fork replay when the parent falls outside the date range, and deterministic serial/parallel attribution. Claude CLI has also reviewed the implementation; its date-bounded replay finding is fixed and covered by a regression test.

@ryoppippi I have started the AI code review. It will take a few minutes to complete.

@pkg-pr-new

pkg-pr-new Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

ccusage

npx https://pkg.pr.new/ccusage@1821

@ccusage/ccusage-darwin-arm64

npx https://pkg.pr.new/@ccusage/ccusage-darwin-arm64@1821

@ccusage/ccusage-darwin-x64

npx https://pkg.pr.new/@ccusage/ccusage-darwin-x64@1821

@ccusage/ccusage-linux-arm64

npx https://pkg.pr.new/@ccusage/ccusage-linux-arm64@1821

@ccusage/ccusage-linux-x64

npx https://pkg.pr.new/@ccusage/ccusage-linux-x64@1821

@ccusage/ccusage-win32-x64

npx https://pkg.pr.new/@ccusage/ccusage-win32-x64@1821

commit: abe086f

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 10 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread rust/adapters/codex/src/replay.rs Resolved
@coderabbitai

coderabbitai Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

@ryoppippi I’ll review #1821, with emphasis on:

  • Suppressing compaction usage already included in cumulative token counts.
  • Handling fork replay when the parent is outside the selected date range.
  • Preserving deterministic attribution and speed-tier merging in serial and parallel aggregation.
  • Checking the regression test for the date-bounded replay finding.
⚠️ Action not completed

Already reviewed the last commit. Use @coderabbitai full review to rerun a review of the entire changeset.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ Minor suggestions only — one edge case worth a look.

Reviewed changes

Reviewed the full diff of this run (5a41412 compaction counting plus ad2d201 whitespace parsing):

  • Compaction pairing in parser.rs — pairs token_usage_record entries with compacted markers by response ID in either order, and suppresses the extra event when an intervening cumulative token_count snapshot already accounts for the usage (exact-delta match or thread_token_usage match).
  • Response-ID dedupe across aggregation paths — new CodexEventKey::Response / CodexEventDeduplicationKey::Response keys in aggregate.rs and loader.rs collapse copied compaction responses to one, with first-file-wins attribution, merged service tiers, and deferred accumulation so parallel workers agree.
  • Fork-replay handling in replay.rs — compaction IDs are indexed per parent and excluded from the normal replay prefix, so date-bounded child reports drop parent copies without losing the child's own requests.
  • Whitespace-tolerant line classification — compact byte finders plus a whitespace-aware type scanner so spaced JSON no longer silently drops token_count, token_usage_record, or compacted lines.
  • Tests and docs — exact-total assertions that fail under double counting (e.g. 510 in the local-compaction test), serial/parallel parity checks, and updated Codex guide plus adapter README.

The tests assert exact token totals rather than loose bounds, so they genuinely pin the fix. Parities I verified by reading: loader dedupe keeps first-file attribution matching aggregate's file_index rule, aggregate_events merges tiers the same way, and compaction_tiers[response_id] indexing is safe because empty-model events continue before both the seeding pass and the use site.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using muse-spark-1.3-contributor (free via Pullfrog for OSS) | 𝕏

Comment thread rust/adapters/codex/src/parser.rs Resolved
Keep matched parent response IDs independently of usage emission, so a
retained child log missing the intervening cumulative snapshot cannot
count an already-accounted compaction again in a date-bounded report.

Collect identities during the existing parent pass. Normal report parsing
does not allocate the optional history map, and ordinary replay matching
continues to use only token-count deltas.

Add a regression covering the loader and serial/parallel reports with a
missing child snapshot. This addresses Cubic's review finding on #1821.
@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: ad2d2012053d
Base SHA: 41407251305f

This compares the PR package against the configured base package on the same CI runner.

Package runtime diagnostics

Compares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself.

Fixtures: Claude /home/runner/_work/_temp/ccusage-large-fixture (1.01 GiB, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 files)
All rows run --offline --json, measured by hyperfine with 0 warmups and 1 runs. This isolates wrapper overhead from the installed native optional dependency and the workspace release binary built on the runner.

Command Runtime Input Median Throughput Samples
claude --offline --json Package wrapper 1.01 GiB 387.3ms 2.60 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 340.1ms 2.96 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 140.8ms 7.15 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 114.8ms 8.77 GiB/s 1

Committed fixture performance

Committed small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage.

Fixtures: Claude apps/ccusage/test/fixtures/claude (0.00 MiB, 2 files), Codex apps/ccusage/test/fixtures/codex (0.00 MiB, 1 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published ccusage package from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 2 warmups and 7 runs.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude daily --offline --json 0.00 MiB 38.8ms 34.8ms 1.12x 55.75 MiB 55.75 MiB 1.00x 0.04 MiB/s 0.04 MiB/s
claude session --offline --json 0.00 MiB 34.1ms 35.8ms 0.95x 55.75 MiB 55.75 MiB 1.00x 0.05 MiB/s 0.04 MiB/s
codex daily --offline --json 0.00 MiB 37.0ms 36.1ms 1.02x 55.50 MiB 55.50 MiB 1.00x 0.02 MiB/s 0.02 MiB/s
codex session --offline --json 0.00 MiB 33.9ms 33.3ms 1.02x 55.50 MiB 55.75 MiB 1.00x 0.03 MiB/s 0.03 MiB/s

Large real-world-shaped fixture performance

Generated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures.

Fixtures: Claude /home/runner/_work/_temp/ccusage-large-fixture (1.01 GiB, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published ccusage package from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 0 warmups and 1 runs.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude --offline --json 1.01 GiB 393.4ms 396.4ms 0.99x 947.09 MiB 947.09 MiB 1.00x 2.56 GiB/s 2.54 GiB/s
codex --offline --json 1.01 GiB 150.2ms 142.3ms 1.06x 455.42 MiB 497.44 MiB 1.09x 6.70 GiB/s 7.08 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 23.69 KiB 23.69 KiB +0.00 KiB 1.00x
installed native package binary 4641.03 KiB 4665.59 KiB +24.56 KiB 0.99x

Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees.

@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: ad2d2012053d
Base SHA: 41407251305f

This compares the Rust PR release binary against the configured base package on the same CI runner.

Package runtime diagnostics

Compares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself.

Fixtures: Claude /home/runner/_work/_temp/ccusage-large-fixture (1.01 GiB, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 files)
All rows run --offline --json, measured by hyperfine with 0 warmups and 1 runs. This isolates wrapper overhead from the installed native optional dependency and the workspace release binary built on the runner.

Command Runtime Input Median Throughput Samples
claude --offline --json Package wrapper 1.01 GiB 502.2ms 2.00 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 366.8ms 2.74 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 137.4ms 7.33 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 143.7ms 7.01 GiB/s 1

Committed fixture performance

Committed small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage.

Fixtures: Claude apps/ccusage/test/fixtures/claude (0.00 MiB, 2 files), Codex apps/ccusage/test/fixtures/codex (0.00 MiB, 1 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published native ccusage binary from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 2 warmups and 7 runs.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude daily --offline --json 0.00 MiB 40.8ms 11.4ms 3.58x 55.50 MiB 22.97 MiB 0.41x 0.04 MiB/s 0.14 MiB/s
claude session --offline --json 0.00 MiB 35.5ms 11.5ms 3.09x 55.75 MiB 23.21 MiB 0.42x 0.04 MiB/s 0.13 MiB/s
codex daily --offline --json 0.00 MiB 32.9ms 11.7ms 2.81x 55.75 MiB 23.21 MiB 0.42x 0.03 MiB/s 0.07 MiB/s
codex session --offline --json 0.00 MiB 35.3ms 10.5ms 3.37x 55.75 MiB 23.21 MiB 0.42x 0.02 MiB/s 0.08 MiB/s

Large real-world-shaped fixture performance

Generated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures.

Fixtures: Claude /home/runner/_work/_temp/ccusage-large-fixture (1.01 GiB, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published native ccusage binary from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 0 warmups and 1 runs.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude --offline --json 1.01 GiB 381.9ms 359.0ms 1.06x 911.09 MiB 929.09 MiB 1.02x 2.64 GiB/s 2.80 GiB/s
codex --offline --json 1.01 GiB 177.9ms 152.4ms 1.17x 431.42 MiB 497.43 MiB 1.15x 5.66 GiB/s 6.60 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 23.69 KiB 23.69 KiB +0.00 KiB 1.00x
installed native package binary 4641.03 KiB 4665.59 KiB +24.56 KiB 0.99x

Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees.

@ryoppippi

Copy link
Copy Markdown
Member Author

@coderabbitai @cubic-dev-ai Please review dbac9e6, which retains matched parent compaction IDs even when cumulative snapshots already cover their usage. The missing-child-snapshot regression now passes through the loader and serial/parallel bounded reports, and Claude CLI found no correctness bugs in this follow-up.

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai @cubic-dev-ai Please review dbac9e6, which retains matched parent compaction IDs even when cumulative snapshots already cover their usage. The missing-child-snapshot regression now passes through the loader and serial/parallel bounded reports, and Claude CLI found no correctness bugs in this follow-up.

@ryoppippi I have started the AI code review. It will take a few minutes to complete.

@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: dbac9e6b0738
Base SHA: 41407251305f

This compares the Rust PR release binary against the configured base package on the same CI runner.

Package runtime diagnostics

Compares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself.

Fixtures: Claude /home/runner/_work/_temp/ccusage-large-fixture (1.01 GiB, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 files)
All rows run --offline --json, measured by hyperfine with 0 warmups and 1 runs. This isolates wrapper overhead from the installed native optional dependency and the workspace release binary built on the runner.

Command Runtime Input Median Throughput Samples
claude --offline --json Package wrapper 1.01 GiB 374.6ms 2.69 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 342.0ms 2.94 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 144.4ms 6.97 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 118.5ms 8.50 GiB/s 1

Committed fixture performance

Committed small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage.

Fixtures: Claude apps/ccusage/test/fixtures/claude (0.00 MiB, 2 files), Codex apps/ccusage/test/fixtures/codex (0.00 MiB, 1 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published native ccusage binary from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 2 warmups and 7 runs.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude daily --offline --json 0.00 MiB 37.9ms 10.5ms 3.61x 55.75 MiB 22.97 MiB 0.41x 0.04 MiB/s 0.15 MiB/s
claude session --offline --json 0.00 MiB 37.1ms 10.5ms 3.52x 55.50 MiB 23.21 MiB 0.42x 0.04 MiB/s 0.15 MiB/s
codex daily --offline --json 0.00 MiB 31.5ms 10.6ms 2.98x 55.50 MiB 22.96 MiB 0.41x 0.03 MiB/s 0.08 MiB/s
codex session --offline --json 0.00 MiB 33.8ms 10.4ms 3.24x 55.50 MiB 22.97 MiB 0.41x 0.03 MiB/s 0.08 MiB/s

Large real-world-shaped fixture performance

Generated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures.

Fixtures: Claude /home/runner/_work/_temp/ccusage-large-fixture (1.01 GiB, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published native ccusage binary from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 0 warmups and 1 runs.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude --offline --json 1.01 GiB 358.3ms 359.0ms 1.00x 911.09 MiB 931.09 MiB 1.02x 2.81 GiB/s 2.80 GiB/s
codex --offline --json 1.01 GiB 123.9ms 113.4ms 1.09x 449.42 MiB 491.44 MiB 1.09x 8.13 GiB/s 8.88 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 23.69 KiB 23.69 KiB -0.00 KiB 1.00x
installed native package binary 4641.03 KiB 4667.59 KiB +26.56 KiB 0.99x

Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees.

@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: dbac9e6b0738
Base SHA: 41407251305f

This compares the PR package against the configured base package on the same CI runner.

Package runtime diagnostics

Compares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself.

Fixtures: Claude /home/runner/_work/_temp/ccusage-large-fixture (1.01 GiB, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 files)
All rows run --offline --json, measured by hyperfine with 0 warmups and 1 runs. This isolates wrapper overhead from the installed native optional dependency and the workspace release binary built on the runner.

Command Runtime Input Median Throughput Samples
claude --offline --json Package wrapper 1.01 GiB 384.1ms 2.62 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 352.3ms 2.86 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 134.1ms 7.51 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 120.4ms 8.36 GiB/s 1

Committed fixture performance

Committed small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage.

Fixtures: Claude apps/ccusage/test/fixtures/claude (0.00 MiB, 2 files), Codex apps/ccusage/test/fixtures/codex (0.00 MiB, 1 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published ccusage package from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 2 warmups and 7 runs.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude daily --offline --json 0.00 MiB 61.9ms 56.2ms 1.10x 55.75 MiB 55.75 MiB 1.00x 0.02 MiB/s 0.03 MiB/s
claude session --offline --json 0.00 MiB 35.6ms 33.9ms 1.05x 55.50 MiB 55.75 MiB 1.00x 0.04 MiB/s 0.05 MiB/s
codex daily --offline --json 0.00 MiB 35.3ms 32.9ms 1.07x 55.50 MiB 55.75 MiB 1.00x 0.02 MiB/s 0.03 MiB/s
codex session --offline --json 0.00 MiB 31.7ms 33.4ms 0.95x 55.75 MiB 55.75 MiB 1.00x 0.03 MiB/s 0.03 MiB/s

Large real-world-shaped fixture performance

Generated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures.

Fixtures: Claude /home/runner/_work/_temp/ccusage-large-fixture (1.01 GiB, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published ccusage package from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 0 warmups and 1 runs.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude --offline --json 1.01 GiB 376.1ms 380.4ms 0.99x 901.08 MiB 929.09 MiB 1.03x 2.68 GiB/s 2.65 GiB/s
codex --offline --json 1.01 GiB 138.8ms 136.7ms 1.02x 445.42 MiB 493.43 MiB 1.11x 7.25 GiB/s 7.37 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 23.69 KiB 23.69 KiB -0.00 KiB 1.00x
installed native package binary 4641.03 KiB 4667.59 KiB +26.56 KiB 0.99x

Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees.

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 10 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread rust/adapters/codex/src/parser.rs Resolved
Comment thread rust/adapters/codex/src/README.md Resolved
@coderabbitai

coderabbitai Bot commented Oct 2, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
git show --stat dbac9e6b
git show --format=fuller --no-ext-diff dbac9e6b -- rust/adapters/codex/src/parser.rs rust/adapters/codex/src/replay.rs rust/adapters/codex/src/compaction_tests.rs
ast-grep outline rust/adapters/codex/src/parser.rs --items all
ast-grep outline rust/adapters/codex/src/replay.rs --items all
ast-grep outline rust/adapters/codex/src/compaction_tests.rs --items all

Length of output: 19699


🏁 Script executed:

#!/bin/bash
set -euo pipefail
git rev-parse HEAD
nl -ba rust/adapters/codex/src/parser.rs | sed -n '201,557p'
nl -ba rust/adapters/codex/src/replay.rs | sed -n '75,202p'
nl -ba rust/adapters/codex/src/replay.rs | sed -n '218,272p;309,430p'
nl -ba rust/adapters/codex/src/compaction_tests.rs | sed -n '1,178p'
ast-grep outline rust/adapters/codex/src/loader.rs --items all
ast-grep outline rust/adapters/codex/src/aggregate.rs --items all
rg -n -C 5 'is_replayed_compaction\(|for_bounded_files\(|replay_prefix\(' rust/adapters/codex/src/loader.rs rust/adapters/codex/src/aggregate.rs
git show dbac9e6b -- rust/adapters/codex/src/README.md

Length of output: 53414


@ryoppippi I reviewed dbac9e6b. I found no correctness issues in this follow-up.

  • The parser retains matched parent compaction IDs before cumulative snapshots suppress usage emission.
  • Replay filtering uses those IDs when the parent is outside the selected date range. Compaction events remain separate from the normal token-count replay prefix.
  • The new regression covers the missing child snapshot through the loader and bounded daily reports with both single_thread settings. It checks that the copied compaction is excluded and the child’s own usage remains.

The loader and both aggregation paths apply the same compaction replay filter. This change does not alter attribution or service-tier merging.

This was a static code review. I did not run the tests.

You are interacting with an AI system.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ℹ️ No new issues in this delta — one prior thread stays open.

Reviewed changes

Reviewed the delta since the prior pullfrog review (ad2d201 → dbac9e6):

  • Retained counted compaction IDs in replay history — parent scans now collect every matched token_usage_record/compacted response ID (including snapshot-covered usage) via the new visit_codex_session_file_with_compaction_history path, so date-bounded child reports suppress the copy even when the child log omits the cumulative snapshot.
  • Kept the normal replay prefix compaction-free — read_usage_events excludes response_id events from the prefix timestamps/usage, preserving the existing token-count matching behavior while the ID map handles compactions independently.
  • Added a missing-snapshot regression test — bounded_reports_exclude_counted_parent_compactions_without_a_copied_snapshot pins the exact 120-token total across serial, parallel, and loader paths.
  • Updated the adapter README — documents that all matched parent compaction IDs are preserved, including snapshot-covered usage.

The new test asserts exact totals (not loose bounds), so it genuinely pins the fix. Parities I verified by reading: normal report parsing passes None for the history map (no allocation, no behavior change), or_insert_with keeps first-seen timestamps, and the end-of-file retain drops unmatched IDs before extending the parent map. The prior inline thread on latest_usage_response_id being cleared before validation (parser.rs:364) is unchanged by this delta and stays open for the author to decide.

Pullfrog  | Fix it ➔ | View workflow run | Using muse-spark-1.3-contributor (free via Pullfrog for OSS) | 𝕏

Keep the latest valid response ID when an invalid or already-accounted
record is ignored. Clearing it before validation prevented cumulative
snapshots from consuming the pending compaction usage and counted it twice.

Add exact-total regressions for missing IDs, timestamps, empty usage, and
duplicate completed responses. This addresses Pullfrog's review on #1821.
@ryoppippi

Copy link
Copy Markdown
Member Author

@coderabbitai @cubic-dev-ai Please review the latest commits, 8f4df2a and abe086f. Invalid or completed records preserve the latest valid pending usage ID, and the documentation now distinguishes first-copy attribution from merged service tiers. All 125 Codex tests and workspace push checks passed. The previous CI test job failed because the Nix SQLite database was busy, so the latest CI run also retries that environment failure.

@cubic-dev-ai

cubic-dev-ai Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai @cubic-dev-ai Please review the latest commits, 8f4df2a and abe086f. Invalid or completed records preserve the latest valid pending usage ID, and the documentation now distinguishes first-copy attribution from merged service tiers. All 125 Codex tests and workspace push checks passed. The previous CI test job failed because the Nix SQLite database was busy, so the latest CI run also retries that environment failure.

@ryoppippi I have started the AI code review. It will take a few minutes to complete.

@coderabbitai

coderabbitai Bot commented Oct 2, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
git rev-parse HEAD
git show --stat 8f4df2a0
git show --stat abe086fc
git show --format=fuller --no-ext-diff 8f4df2a0 abe086fc
ast-grep outline rust/adapters/codex/src/parser.rs --items all
ast-grep outline rust/adapters/codex/src/aggregate.rs --items all
ast-grep outline rust/adapters/codex/src/compaction_tests.rs --items all

Length of output: 17499


🏁 Script executed:

#!/bin/bash
set -euo pipefail
nl -ba rust/adapters/codex/src/parser.rs | sed -n '68,97p;201,556p;1283,1317p'
nl -ba rust/adapters/codex/src/compaction_tests.rs | sed -n '179,375p'
nl -ba rust/adapters/codex/src/aggregate.rs | sed -n '578,777p;839,892p;918,990p'
nl -ba rust/adapters/codex/src/README.md | sed -n '1,45p'

Length of output: 46594


@ryoppippi I reviewed 8f4df2a0 and abe086fc. I found no correctness issues in these two commits.

  • Pending usage: Invalid records and already-accounted response IDs return before changing latest_usage_response_id. A valid record still updates that ID after validation. The next matching cumulative snapshot can therefore suppress the pending compaction usage.
  • Regression coverage: The new test covers a blank ID, a missing timestamp, empty usage, and a duplicate completed response. Each case asserts exactly 450 tokens and no separate compaction event.
  • Documentation: The first-copy attribution rule matches the implementation. Aggregation selects the lowest file index for usage, session, timestamp, and model. It merges service tiers independently. Existing tests cover serial/parallel parity and reversed worker completion order.

This was a static review. I did not run tests or verify the latest CI result.

Thanks for clarifying the attribution rules.


✏️ Learnings added
Learnt from: ryoppippi
URL: https://github.com/ccusage/ccusage/pull/1821

Timestamp: 2026-10-02T21:38:17.591Z
Learning: In the Rust Codex adapter, rust/adapters/codex/src/parser.rs must preserve CodexCompactionUsageState.latest_usage_response_id when a token_usage_record is invalid or its response ID is already accounted for. Clearing this ID can prevent a subsequent cumulative snapshot from suppressing pending compaction usage and cause double counting. In rust/adapters/codex/src/aggregate.rs, copied compactions retain the first file's usage, session, timestamp, and model attribution, while service tiers merge across copies independently of parallel worker completion order.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

You are interacting with an AI system.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No issues found across 10 files

Re-trigger cubic

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ No new issues found.

Reviewed changes Reviewed the delta since the prior pullfrog review (dbac9e6 → abe086f), which addresses the open latest_usage_response_id thread:

  • Preserved valid pending usage across invalid records — removed the pre-validation reset so latest_usage_response_id is only overwritten after timestamp and usage validation, letting the cumulative snapshot still suppress the pending compaction entry.
  • Added exact-total regression coverage — new invalid_or_completed_records_do_not_hide_pending_compaction_usage test pins all four gap shapes (blank ID, missing timestamp, empty usage, duplicate completed response) at 450 total tokens with no response_id events leaking.
  • Clarified duplicate compaction attribution docs — README now states first-file session, timestamp, and model retention with merged service tiers, matching the insert_dedupe_record first-file-wins behavior.

The new test asserts exact totals rather than loose bounds, so it genuinely pins the fix. Parities I verified by reading: early returns for blank IDs, missing timestamps, zero usage, and already-emitted IDs all exit before the latest_usage_response_id assignment at parser.rs:428, and the duplicate-record path exits via the emitted_response_ids guard.

Pullfrog  | View workflow run | Using muse-spark-1.3-contributor (free via Pullfrog for OSS) | 𝕏

@ryoppippi
ryoppippi merged commit 8f32f3c into main Oct 2, 2026
39 checks passed
@ryoppippi
ryoppippi deleted the codex/count-codex-compaction-usage branch October 2, 2026 21:59
@github-actions github-actions Bot mentioned this pull request Oct 2, 2026
@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: abe086fc10e2
Base SHA: 41407251305f

This compares the Rust PR release binary against the configured base package on the same CI runner.

Package runtime diagnostics

Compares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself.

Fixtures: Claude /home/runner/_work/_temp/ccusage-large-fixture (1.01 GiB, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 files)
All rows run --offline --json, measured by hyperfine with 0 warmups and 1 runs. This isolates wrapper overhead from the installed native optional dependency and the workspace release binary built on the runner.

Command Runtime Input Median Throughput Samples
claude --offline --json Package wrapper 1.01 GiB 390.4ms 2.58 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 347.9ms 2.89 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 145.4ms 6.93 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 117.9ms 8.54 GiB/s 1

Committed fixture performance

Committed small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage.

Fixtures: Claude apps/ccusage/test/fixtures/claude (0.00 MiB, 2 files), Codex apps/ccusage/test/fixtures/codex (0.00 MiB, 1 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published native ccusage binary from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 2 warmups and 7 runs.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude daily --offline --json 0.00 MiB 40.4ms 16.4ms 2.46x 55.75 MiB 22.97 MiB 0.41x 0.04 MiB/s 0.09 MiB/s
claude session --offline --json 0.00 MiB 41.2ms 11.0ms 3.76x 55.50 MiB 23.22 MiB 0.42x 0.04 MiB/s 0.14 MiB/s
codex daily --offline --json 0.00 MiB 35.4ms 10.9ms 3.25x 55.50 MiB 22.97 MiB 0.41x 0.02 MiB/s 0.08 MiB/s
codex session --offline --json 0.00 MiB 33.6ms 10.7ms 3.15x 55.50 MiB 22.96 MiB 0.41x 0.03 MiB/s 0.08 MiB/s

Large real-world-shaped fixture performance

Generated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures.

Fixtures: Claude /home/runner/_work/_temp/ccusage-large-fixture (1.01 GiB, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published native ccusage binary from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 0 warmups and 1 runs.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude --offline --json 1.01 GiB 386.8ms 370.6ms 1.04x 933.09 MiB 927.09 MiB 0.99x 2.60 GiB/s 2.72 GiB/s
codex --offline --json 1.01 GiB 144.3ms 120.0ms 1.20x 439.42 MiB 505.44 MiB 1.15x 6.98 GiB/s 8.39 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 23.69 KiB 23.69 KiB +0.00 KiB 1.00x
installed native package binary 4641.03 KiB 4667.47 KiB +26.44 KiB 0.99x

Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees.

@github-actions

github-actions Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

ccusage performance comparison

PR SHA: abe086fc10e2
Base SHA: 41407251305f

This compares the PR package against the configured base package on the same CI runner.

Package runtime diagnostics

Compares the PR package wrapper, the installed native optional dependency binary, and the workspace release binary on the same large fixture. This identifies whether slow package results come from JavaScript wrapper overhead, the published native binary build, or the Rust core itself.

Fixtures: Claude /home/runner/_work/_temp/ccusage-large-fixture (1.01 GiB, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 files)
All rows run --offline --json, measured by hyperfine with 0 warmups and 1 runs. This isolates wrapper overhead from the installed native optional dependency and the workspace release binary built on the runner.

Command Runtime Input Median Throughput Samples
claude --offline --json Package wrapper 1.01 GiB 415.7ms 2.42 GiB/s 1
claude --offline --json Installed native binary 1.01 GiB 377.6ms 2.67 GiB/s 1
codex --offline --json Package wrapper 1.01 GiB 163.0ms 6.18 GiB/s 1
codex --offline --json Installed native binary 1.01 GiB 142.9ms 7.05 GiB/s 1

Committed fixture performance

Committed small fixtures for stable PR-to-PR feedback and explicit Claude/Codex command coverage.

Fixtures: Claude apps/ccusage/test/fixtures/claude (0.00 MiB, 2 files), Codex apps/ccusage/test/fixtures/codex (0.00 MiB, 1 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published ccusage package from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 2 warmups and 7 runs.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude daily --offline --json 0.00 MiB 44.9ms 46.2ms 0.97x 55.75 MiB 55.75 MiB 1.00x 0.03 MiB/s 0.03 MiB/s
claude session --offline --json 0.00 MiB 42.3ms 37.7ms 1.12x 55.75 MiB 55.50 MiB 1.00x 0.04 MiB/s 0.04 MiB/s
codex daily --offline --json 0.00 MiB 42.5ms 39.8ms 1.07x 55.50 MiB 55.75 MiB 1.00x 0.02 MiB/s 0.02 MiB/s
codex session --offline --json 0.00 MiB 39.5ms 39.6ms 1.00x 55.50 MiB 55.75 MiB 1.00x 0.02 MiB/s 0.02 MiB/s

Large real-world-shaped fixture performance

Generated fixtures shaped from aggregate local log statistics: thousands of JSONL files, many small sessions, and a long tail of larger sessions. No real prompts, paths, or outputs are stored in the fixtures.

Fixtures: Claude /home/runner/_work/_temp/ccusage-large-fixture (1.01 GiB, 2597 files), Codex /home/runner/_work/_temp/ccusage-large-codex-fixture (1.01 GiB, 2597 files)
Base runs the published ccusage package from pkg.pr.new, installed before measurement; PR runs the published ccusage package from pkg.pr.new, installed before measurement. Both run --offline --json, measured by hyperfine with 0 warmups and 1 runs.
Peak RSS is measured separately with /usr/bin/time using 1 runs. Lower RSS ratios are better.

Command Input Base median PR median PR vs base Base peak RSS PR peak RSS PR/base RSS Base throughput PR throughput
claude --offline --json 1.01 GiB 415.8ms 427.6ms 0.97x 943.09 MiB 885.08 MiB 0.94x 2.42 GiB/s 2.35 GiB/s
codex --offline --json 1.01 GiB 163.5ms 161.2ms 1.01x 407.41 MiB 459.42 MiB 1.13x 6.16 GiB/s 6.25 GiB/s

Artifact size

Artifact Base PR Delta Ratio
packed ccusage-*.tgz 23.69 KiB 23.69 KiB +0.00 KiB 1.00x
installed native package binary 4641.03 KiB 4667.47 KiB +26.44 KiB 0.99x

Lower medians and smaller artifacts are better. CI runner noise still applies; use same-run ratios as directional PR feedback, not release guarantees.

@wallmage

wallmage commented Oct 6, 2026

Copy link
Copy Markdown

Confirmed this omission in the currently published ccusage 20.0.26 on macOS arm64 (checked npm latest on 2026-10-06). Posting the reproduction here because this PR already fixes the source, and release PR #1809 is still open.

The v20.0.26 session parser accepts turn_context / event_msg token_count but skips token_usage_record and compacted. This matches missing remote-compaction requests in an independently reconciled local history.

Synthetic reproduction: save these four lines as sessions/synthetic.jsonl under an isolated Codex home:

{"timestamp":"2026-10-05T00:00:00Z","type":"turn_context","payload":{"model":"gpt-6-astra"}}
{"timestamp":"2026-10-05T00:00:01Z","type":"event_msg","payload":{"type":"token_count","info":{"total_token_usage":{"input_tokens":1000,"cached_input_tokens":900,"output_tokens":20,"reasoning_output_tokens":0,"total_tokens":1020},"last_token_usage":{"input_tokens":1000,"cached_input_tokens":900,"output_tokens":20,"reasoning_output_tokens":0,"total_tokens":1020}}}}
{"timestamp":"2026-10-05T00:00:02Z","type":"token_usage_record","payload":{"response_id":"synthetic-compaction-1","model":"gpt-6-astra","usage":{"input_tokens":3000,"cached_input_tokens":2000,"output_tokens":30,"reasoning_output_tokens":0,"total_tokens":3030}}}
{"timestamp":"2026-10-05T00:00:03Z","type":"compacted","payload":{"compaction_response_id":"synthetic-compaction-1"}}

Run with CODEX_HOME pointing to that isolated directory:

ccusage codex daily --json --offline --speed standard --timezone UTC --since 2026-10-05 --until 2026-10-05

I ran this against the 20.0.26 native binary. It exited successfully but returned:

Field Actual Expected
inputTokens (uncached) 100 1,100
cacheReadTokens 900 2,900
outputTokens 20 50
totalTokens 1,020 4,050
costUSD 0.0029 0.0164

Expected cost uses standard GPT-6 Astra input/cache/output rates of $10/$1/$50 per million. All example records are synthetic; no private logs or identifiers are included. I verified the released binary's omission, not a build of this merged fix. A published release containing #1821 should address this specific gap. Thanks for fixing it.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants