Skip to content

Codex fork replays spanning multiple seconds are counted as native usage #1460

Closed

Description

@MaxGhenis

What happened?

Codex fork replays that span more than one wall-clock second are counted as native usage. The replay detection in rust/crates/ccusage/src/adapter/codex/parser.rs only treats the first two token events as replay if their timestamps share a second (parser.rs:123-132), but real forked rollouts copy history with preserved original timestamps across many seconds. On a minimized fixture from my corpus, v20.0.17 and Rust HEAD both overcount by 238,700,000 tokens.

I'm the heaviest fork-user I know of (I'm the person behind straude's Codex overcounting report, ohong/straude#87, back in April), so my sessions hit this constantly. Two smaller adjacent findings from the same fixture audit: the same heuristic can also discard genuine fork-local work that shares the replay second, and legacy records without total_tokens derive it as input + output + reasoning, double-counting reasoning (types.rs:193-196) since reasoning is already inside output.

Full 12-cell verification matrix (v20.0.17 and HEAD vs an independent oracle, with credit to #1218/#1369 for the same-second and reset handling that already works): https://github.com/MaxGhenis/logpile/blob/main/docs/reviews/2026-07-18-ccusage-verification.md

Steps to reproduce

  1. Take a forked rollout whose copied history spans >1 second — minimized fixture: https://github.com/MaxGhenis/ccusage/blob/codex-structural-replay-boundary/rust/crates/ccusage/tests/fixtures/codex/replay-multisecond-modern.jsonl
  2. Place it in a scratch CODEX_HOME/sessions/YYYY/MM/DD/
  3. ccusage codex daily --json --offline --no-cost --timezone UTC
  4. Expected (native only): 5,000 input / 500 output. Reported: 236,705,000 / 2,000,500.

Anything else?

I'd like to implement this. I filed PRs before reading the contribution gate — my mistake — and they auto-closed: #1457 (structural replay boundary, fixes the overcount and the fork-local discard together), #1458 (legacy total fallback), #1459 (session-scoped dedupe, stacked on #1457). All three pass just fmt/typecheck/test (445/445 workspace) and the 12-cell matrix. Happy to split this into separate issues, rework the approach, or drop any part — whatever fits how you want to take it.

Activity

  1. github-actions commented on Jul 19, 2026

    @github-actions
    Contributor

    This issue was auto-closed. Issues from new contributors are auto-closed by default.

    Maintainers review auto-closed issues and reopen worthwhile ones. Issues that do not meet the quality bar in CONTRIBUTING.md may not be reopened or receive a reply.

    Keep the issue short, concrete, and written in your own voice.

    If a maintainer replies lgtmi, your future issues will stay open. If a maintainer replies lgtm, your future issues and PRs will stay open.

    See CONTRIBUTING.md.

  2. ryoppippi commented on Jul 27, 2026

    @ryoppippi
    Member

    lgtm

  3. github-actions commented on Jul 27, 2026

    @github-actions
    Contributor

    @MaxGhenis approved for issues and PRs. Your future issues and PRs will not be auto-closed.

    See CONTRIBUTING.md.

  4. ryoppippi commented on Aug 31, 2026

    @ryoppippi
    Member

    Historical audit: this discussion was auto-closed by the legacy contributor gate. That closure did not assess technical importance.

    Audit result: resolved. A later merged change or the current main implementation covers this request. This item is kept for history and does not need to be reopened.

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

    triage:resolvedResolved by a later change or current implementation.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions