Skip to content

[Bug]: 30d and Available history totals remain bounded by the moving 64 MiB usage tail #1497

Description

@alanxchen85

Client or integration

OpenCodex Dashboard

Area

Dashboard / Usage

Current status

This issue is partially mitigated but not fixed.

PR #1532 landed on dev and made the bounded read visible to users by exposing the observed snapshot window and warning when history is truncated. The product should therefore no longer describe the returned tail as if it were silently known to cover the selected range.

The core aggregation defect remains: GET /api/usage still reads the bounded management snapshot first and applies 7d, 30d, or all filtering afterward. On a high-volume installation, the loaded tail can cover much less than the requested period.

The issue stays open until date-range and all-time aggregates are complete across the retained ledger rather than merely truthful about truncation.

Problem

managementUsageMaxReadBytes is 64 MiB by default. If usage.jsonl is larger than that, the management reader loads only the newest tail.

The range filter is applied after that read. As a result:

  • 30d can omit persisted requests that are less than 30 days old;
  • Available history / all can return essentially the same bounded tail;
  • cumulative totals can decrease as older rows fall out of the moving read window;
  • detail rows may be bounded intentionally, but aggregate totals become incomplete too.

PR #1532 improves disclosure only. It does not change that aggregation boundary.

Original measured example

On OpenCodex 2.11.0 with a ledger larger than 64 MiB:

Source Requests Tokens Time covered
Complete usage.jsonl 175,818 23.74B Aug 4-11
Bounded Dashboard/API snapshot 46,417 6.60B roughly 39 hours

The API reported truncation, and 129,401 requests plus 17.14B tokens inside the nominal 30-day range were not included in the aggregate.

Root cause

The management route performs the operations in this order:

readUsageSnapshotForManagement(effectiveReadLimit)
        ↓
newest bounded byte tail
        ↓
summarizeUsage(..., range, ...)

The desired contract requires the date/range aggregation boundary to precede, or be independent of, the bounded recent-detail read.

Required behavior

  • 7d aggregates every retained valid request in the selected 7-day range.
  • 30d aggregates every retained valid request in the selected 30-day range.
  • All-time totals do not decrease merely because the raw tail advances.
  • Detail rows may remain bounded if necessary.
  • Aggregate coverage is explicit when an index/projection is incomplete or rebuilding.
  • The existing snapshotWindowStart / snapshotWindowEnd disclosure from fix(usage): disclose the window a truncated read actually covers #1532 remains truthful and must not be reinterpreted as a proof of complete range coverage.

Important correctness constraint

Do not derive a rangeFullyCovered assertion only from the oldest loaded row timestamp.

usage.jsonl is appended when a request completes while a row can carry the request start time. Completion order and start-time order can differ, so the oldest timestamp in the loaded tail does not prove what timestamps may exist in the dropped prefix.

Preferred implementation direction

Use a rebuildable indexed or incremental aggregate projection for summaries, while keeping usage.jsonl as canonical evidence.

Possible implementations include:

Raising managementUsageMaxReadBytes is only a temporary mitigation.

Close condition

Close when 7d/30d aggregates cover all retained in-range requests and all-time totals remain monotonic across raw-tail rotation/truncation and restart.

Related

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions