Skip to content

Codex usage can be severely overstated for fork-heavy users until @ccusage/codex is updated #87

Closed

Description

@MaxGhenis

Summary

Straude currently pins Codex usage collection to @ccusage/codex@18, and Codex usage can be severely overstated for users who heavily use forked/spawned sessions.

Relevant Straude code:

  • packages/cli/src/lib/codex.ts
  • const CODEX_PKG = "@ccusage/codex@18"

Upstream context:

Case study from my usage

Straude estimated my last 7 days at roughly $70k of API-equivalent usage, which seemed implausible.

I dug into the raw Codex session logs and found two problems:

  1. forked Codex sessions can replay ancestor cumulative token_count state, which inflates totals if counted naively
  2. there is also a mixed last_token_usage / total_token_usage delta bug that still overcounts some sessions unless corrected

After patching the loader locally and re-running against my actual logs, my last-7-days numbers changed from roughly:

  • raw Codex total: 20.58B tokens
  • corrected deduped Codex total: 9.05B tokens
  • corrected Claude Code total: 0.78B tokens
  • corrected combined total: 9.83B tokens

Using Straude-style API list-price estimates, that moved me from about $70k/week down to about $4,267.58/week:

  • Codex: $3,911.82
  • Claude Code: $355.76
  • Combined: $4,267.58

That is still huge, but it is nowhere near the current displayed estimate.

Why this matters

This is not just a small edge-case normalization bug. For heavy Codex users who rely on forking/spawned sessions, leaderboards and personal cost estimates can be off by an order of magnitude.

Suggested path

Short term:

  • add a note/warning that Codex totals may be inflated until the upstream @ccusage/codex fix lands

Practical rollout options:

  1. Best: bump Straude to a released @ccusage/codex version once upstream merges/releases #910 plus the follow-up fix
  2. Fast opt-in: let advanced users override the Codex package name/version via an env var like STRAUDE_CODEX_PKG, so they can point Straude at a patched npm tag/fork without waiting for a full Straude release
  3. If needed: temporarily point Straude at a patched published fork package until upstream releases

I’m happy to share more detail or help test a Straude-side fix once the ccusage package version story is decided.

Activity

  1. MaxGhenis commented on Apr 14, 2026

    @MaxGhenis
    ContributorAuthor

    Opened a small PR for the short-term rollout path here: https://github.com/ohong/straude/pull/88\n\nThis keeps as the default, but lets advanced users point Straude at a patched package via until upstream releases the fork-dedup fixes.

  2. MaxGhenis commented on Apr 14, 2026

    @MaxGhenis
    ContributorAuthor

    Opened a small PR for the short-term rollout path here: #88

    This keeps @ccusage/codex@18 as the default, but lets advanced users point Straude at a patched package via STRAUDE_CODEX_PKG until upstream releases the fork-dedup fixes.

  3. MaxGhenis commented on Apr 14, 2026

    @MaxGhenis
    ContributorAuthor

    Agreed that this should not be opt-in as the steady state. For a leaderboard, everyone should be on the accurate Codex accounting by default.

    I opened PR #88 only as a temporary escape hatch because Straude currently shells out to a published package name (@ccusage/codex@18), and there is not yet a published fixed release/package to point the default at.

    So my recommendation is:

    1. merge/release the upstream @ccusage/codex fixes
    2. bump Straude's default package source to that corrected release immediately
    3. treat the env override only as a short-lived bridge for validation or emergency use

    If a patched package gets published before upstream releases, then Straude should just switch the default to that package rather than asking leaderboard users to opt in manually.

  4. MaxGhenis commented on Apr 14, 2026

    @MaxGhenis
    ContributorAuthor

    I tried the real end-to-end path locally instead of just comparing custom scripts:

    • built a tarball from the patched @ccusage/codex branch (#910 + follow-up fixes)
    • ran Straude's CLI with STRAUDE_CODEX_PKG=file:/tmp/ccusage-pack/ccusage-codex-18.0.10.tgz
    • did a push --days 7 --dry-run

    Result: Straude still showed the inflated ~$70k/week numbers. So the current @ccusage/codex fix path is still not enough to trust leaderboard uploads for my data.

    That means there is at least one more overcounting path beyond the fixes in #910 and my follow-up PR. I am not going to upload the corrected number through Straude yet, because the package path that Straude can actually execute is still wrong for my corpus.

    I think the next step is to trace the remaining mismatch between:

    • my deeper local forensics (which got me to about $4.27k/week)
    • the patched @ccusage/codex daily --json path (which still yields the inflated leaderboard number)

    Until that is resolved, I would treat Codex-heavy leaderboard values as suspect.

  5. ohong commented on Apr 25, 2026

    @ohong
    Owner

    PR #92 is now merged and replaces Straude’s Codex collection path with a native collector instead of @ccusage/codex. The native collector fixes the two overcount paths described here:

    • forked Codex sessions replaying ancestor token-count prefixes
    • mixed last_token_usage / total_token_usage records being counted twice

    It also adds a repair path for already-uploaded inflated rows. Once the web deploy containing #92 is live and the fixed CLI is published to npm, please run this from the machine that has the original Codex logs and the same Straude CLI config/device that uploaded the inflated data:

    npx straude@latest push

    Do not pass --date for the repair run. On the first upgraded run, the CLI should detect local Codex logs and automatically do a one-time 30-day Codex resync, printing a short “repairing Codex totals” message. That corrected native submission is allowed to lower previously inflated Straude rows, so the profile, activity cards, contribution graph, and leaderboards should update from the corrected daily_usage totals.

    A few important caveats:

    • Exact repair depends on your local ~/.codex/sessions/**/*.jsonl logs. Server-only aggregates are not enough to safely reconstruct true Codex usage.
    • The automatic repair is limited to the API’s current 30-day backfill window.
    • If the inflated upload came from a different machine, run the upgraded push on that machine too.
    • If your ~/.straude/config.json was regenerated and the device ID changed after the inflated upload, the server may not be able to match and lower that old per-device row automatically. In that case, comment here or DM me and we can do an admin-assisted repair.

    After running the upgraded push, please check your profile again. If any April Codex-heavy rows still look inflated, share the dates and whether the local Codex logs are still present, and I’ll help trace the remaining mismatch.

  6. MaxGhenis commented on Apr 27, 2026

    @MaxGhenis
    ContributorAuthor

    Follow-up update: #88 is closed as superseded now that #92 moved Codex accounting to Straude's native collector. I opened #94 for the remaining native-pricing gap called out here: adding GPT-5.5/GPT-5.5 Pro pricing so those model names do not fall through to baseline GPT-5 pricing.

  7. ohong commented on May 8, 2026

    @ohong
    Owner

    Closing this out as resolved.

    Straude no longer uses @ccusage/codex for Codex collection. The earlier native collector work moved Codex accounting into Straude, and PR #119 fixed the remaining overcount path described in this issue:

    • total_token_usage is now treated as a per-request context snapshot, not a monotonic session cumulative counter.
    • last_token_usage is used as the billing source of truth when present.
    • duplicate token_count emissions are skipped only when both total_token_usage and last_token_usage are repeated.
    • forked child sessions use the parent snapshot at or before the fork time, not the parent’s final session total.
    • trusted Codex correction uploads can lower prior inflated Codex rows only when the entry contains Codex usage and preserves non-Codex/Claude cost. Claude accounting remains delegated to ccusage.

    This is released in [email protected].

    For historical inflated rows, the intended repair path is to re-push from the machine that has the original local Codex logs:

    npx straude@latest push

    That run re-reads local ~/.codex/sessions data and submits corrected daily totals. We intentionally do not repair these rows through heuristic SQL rewrites, because the local session logs are the source of truth.

    If anyone still sees obviously inflated Codex-heavy rows after running straude@latest from the original machine, please reopen or file a follow-up with the affected dates and whether the local Codex logs are still present.

  8. MaxGhenis commented on Jul 11, 2026

    @MaxGhenis
    ContributorAuthor

    Taking you up on the admin-assisted repair offer: my Codex-heavy rows from before the native-collector fix are outside the 30-day backfill window and still inflated, and they're large enough to distort the all-time board.

    Current state:

    • Straude all-time for maxghenis: $425,671 / 1.10B output tokens
    • Corrected local accounting (full rescan of ~/.claude + ~/.codex including archived_sessions/, with the fork-replay and snapshot-vs-cumulative fixes applied, plus Claude-side cross-file resume dedup by (message.id, requestId)): ~$266,626 / 1.00B output tokens
    • So roughly $159k of my board figure looks like pre-fix inflation, concentrated in the Mar–May Codex rows. For reference, my corrected Codex-only totals are ~$5.9k (Mar), ~$41.1k (Apr), ~$85.8k (May).

    Setup matches your repair caveats: same machine, original Codex logs still present (sessions/ + archived_sessions/), and the same Straude device config that made the inflated uploads. I've run the upgraded push, which repaired the recent window; the older rows are the remainder.

    Since the window is also enforced server-side (apps/web/app/api/usage/submit/route.ts rejects entries outside MAX_BACKFILL_DAYS), there's no client-side path for this. Two options, whichever you prefer:

    1. I hand you corrected per-day Codex totals for any date range you want and you patch daily_usage directly, or
    2. if you'd rather make it self-serve, I can take a crack at a PR for a repair mode — e.g., accept downward-only revisions beyond MAX_BACKFILL_DAYS when the submission comes from the same device_id that created the row, so it can't be used to game numbers upward.

    I'm about to write publicly about my usage and would rather the top of the all-time board be accurate before I point people at it.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions