Skip to content

[Bug]: Codex "Today" and "30d" show identical cost and tokens while the local scan is paused (no_progress) #755

Closed

Description

@boden0002

Summary

With the Codex local cost scan paused, the card shows the same cost and token count for Today and 30d, even though the cache holds separate per-day data. A value for one period appears to be returned for another.

This issue is only about the period mix-up. How cost is estimated, and why some fork parents are unresolved, are out of scope.

Environment

  • Win-CodexBar 0.70.0 portable (tag f0b45ed); the exe hash matches the release asset
  • Windows 11, time zone Asia/Tokyo, Codex provider

Observed facts

Displayed:

Shown
Today $465.72
30d cost $465.72
30d tokens 677.5M
Latest tokens 677.5M

Cost cache (%LOCALAPPDATA%\CodexBar\cost-usage\codex-v1.json, schema 6):

  • 2026-10-04 only: input 166,464,992 / cached input 159,182,976 / output 405,204 (166.9M input+output)
  • all 27 cached days, 2026-09-05 to 2026-10-04: input 674,925,823 / cached input 649,697,927 / output 2,610,177 (677.5M input+output)
  • codex_scan_incomplete: true, codex_scan_pause_reason: "no_progress"
  • codex_pending_paths: 161 entries; 160 of them have codex_unresolved_fork_parent: true, empty days and parsed_bytes: 0 (145 of these are marked child, 15 have no lineage field); the remaining one has 2026-10-04 data and its file is no longer on disk
  • no previous_report

The tokens shown for "Latest" equal the 30d tokens, not today's, so the mix-up is not limited to the cost. The same card's daily bar chart shows clearly different heights per day, so per-day data is present.

Manual refresh attempt (Ctrl+R / "Refresh" in the panel, once, then waited about 2.5 minutes):

  • Today, 30d cost, 30d tokens and Latest tokens were unchanged
  • Session / weekly usage bars did update (65% → 67%, 87% → 88%)
  • the cost cache file was byte-identical afterwards (same SHA-256, same last_scan_unix_ms); codex_pending_paths stayed at 161, no_progress and codex_scan_incomplete: true unchanged

So the paused state did not recover on its own or through one manual refresh. I do not know whether that refresh requests a new cost scan or only refreshes usage limits.

Analysis from reading v0.70.0 (not confirmed at runtime)

I have not traced this with a debugger or logs. The following comes from reading the source at the tag.

  1. commands/chart.rs scans Rolling(30) and Rolling(1) separately and uses the second result for today_cost and latest_tokens.
  2. While paused, scan.rs calls paused_codex_summary.
  3. reconciliation.rs: if the requested window is not "established", it returns previous_report, or else JsonlScanner::cached_cost_report_from_days(cache).
  4. cached_cost_report_from_days uses range = None, so it sums every cached day.
  5. summary_from_cached_report copies those totals and only sets period_start / period_end to the requested range.
  6. previous_report is one stored report with no window information, so it could be returned for a different period too (not exercised here, since none is stored).

A range-filtered builder, cached_cost_report_for_range, already exists, and the established-window branch uses it. The fallback branch does not.

Condition that leads here: codex_current_window_is_established treats a pending path as affecting the window when codex_unresolved_fork_parent is set or its days is empty. With the 160 unresolved-fork entries above, I infer that neither the Today window nor the 30d window is established. Why the parents are unresolved is not part of this report.

Expected behavior / acceptance criteria

  1. A value computed for one period is never returned for a different period. This covers both the all-days fallback and previous_report without matching window information.
  2. If a partial figure is shown for a requested period (for example, only the days available in the cache for that period), the UI marks it as an incomplete scan. It must not look like a confirmed total for Today.
  3. If nothing can be said for the period, show "unknown" rather than a number from another period.
  4. Once the scan completes, the incomplete marker goes away and Today and 30d are computed from their own days.

Regression test idea: a cache with two days, one pending unresolved-fork path, no_progress pause, no previous_report. paused_codex_summary for Rolling(1) and Rolling(30) must not return the same totals, Rolling(1) must contain only the latest day, and history_coverage_established must stay false. A second case with a previous_report from a different window must not leak into Rolling(1).

Not verified

  • No runtime trace; the code path is from source reading.
  • No test on a fixed build.
  • Whether other users with different cache states are affected.
  • Whether the panel's refresh triggers an app-driven cost scan (the source suggests an app-driven scan clears the no_progress pause, but the cache did not change here). Restarting the app and cache deletion were not tried.

Steps to reproduce

I do not have an external reproduction. This is the state I am in: Codex local cost scan paused with no_progress, 160 pending entries with unresolved fork parents, no previous_report. Open the tray panel, Codex tab, Usage details: Today and 30d show the same values. A unit-level reproduction is described under the regression test idea above.

Related

Activity

  1. boden0002 commented on Oct 4, 2026

    @boden0002
    Author

    Update: I pressed Settings > Usage & Spend > Refresh once and restarted the app. Today and 30d now show different values:

    • Today $44.19, Latest tokens 153.5M
    • 30d cost $397.96, 30d tokens 643.2M

    These match the cache (today 153.5M and all cached days 643.2M, input+output).

    Cache after that: codex_scan_pause_reason is null, but codex_scan_incomplete is still true and codex_pending_paths is 163. So the scan resumed but has not finished. The numbers changed from before (30d tokens 677.5M → 643.2M); I have not checked why.

    This suggests the pause is cleared by a forced rescan (the tray refresh did not do it). The fallback in paused_codex_summary is unchanged, so if the scan pauses with no_progress again, Today and 30d would again receive the cache-wide total. I cannot tell whether the Refresh or the restart cleared 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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions