Summary: In parseProviderSources (src/parser.ts), turns are range-filtered by turn.calls[0]?.timestamp. For long-running sessions whose turn spans midnight (common with autonomous Codex runs lasting many hours), all calls after midnight are dropped from the new day — today shows nothing until the turn ends, and daily history attributes the whole turn's cost to the turn-start day.
Repro (synthetic rollout):
{"timestamp":"2026-07-28T15:55:00.000Z","type":"session_meta","payload":{"session_id":"x","originator":"codex_cli_rs","cwd":"/tmp/t","model":"gpt-5.5"}}
{"timestamp":"2026-07-28T15:57:00.000Z","type":"response_item","payload":{"type":"message","role":"user","content":[{"type":"input_text","text":"work through midnight"}]}}
{"timestamp":"2026-07-28T15:58:00.000Z","type":"event_msg","payload":{"type":"token_count","info":{"total_token_usage":{"input_tokens":100000,"cached_input_tokens":50000,"cache_write_input_tokens":0,"output_tokens":2000,"reasoning_output_tokens":0,"total_tokens":102000},"last_token_usage":{"input_tokens":100000,"cached_input_tokens":50000,"cache_write_input_tokens":0,"output_tokens":2000,"reasoning_output_tokens":0,"total_tokens":102000}}}}
{"timestamp":"2026-07-28T16:10:00.000Z","type":"event_msg","payload":{"type":"token_count","info":{"total_token_usage":{"input_tokens":200000,"cached_input_tokens":100000,"cache_write_input_tokens":0,"output_tokens":4000,"reasoning_output_tokens":0,"total_tokens":204000},"last_token_usage":{"input_tokens":100000,"cached_input_tokens":50000,"cache_write_input_tokens":0,"output_tokens":2000,"reasoning_output_tokens":0,"total_tokens":102000}}}}
In timezone UTC+8: at local 2026-07-29 00:30, codeburn today reports "No usage data found", although the second token_count (2026-07-29 00:10 local) is squarely inside today. export --from 2026-07-29 likewise returns 0 calls. Same-day control case (user message repeated before the second event) works fine, which isolates the cause to turn-level filtering.
Real-world case: a Codex session running autonomously for 30+ hours (one turn, last user message at 23:57 local) — all post-midnight usage (~150 calls) vanished from today.
Suggested fix: filter calls inside the turn instead of dropping the whole turn:
if (dateRange) {
const inRangeCalls = turn.calls.filter((c) => {
const ts = new Date(c.timestamp);
return !Number.isNaN(ts.getTime()) && ts >= dateRange.start && ts <= dateRange.end;
});
if (inRangeCalls.length === 0) continue;
turn = { ...turn, calls: inRangeCalls };
}
(applies to both the servedSources loop and the durableSources loop in parseProviderSources)
Optionally, in aggregateProjectsIntoDays, attribute per-call cost/token columns to dateKey(call.timestamp) rather than the turn day, so multi-day turns distribute cost across actual days in daily history. Turn-level stats (categories, one-shot) can stay turn-based.
I've verified both changes locally against the repro and a real 51MB rollout: post-midnight usage shows up in today correctly, monthly totals unchanged.
Happy to open a PR with this if you prefer.
Summary: In
parseProviderSources(src/parser.ts), turns are range-filtered byturn.calls[0]?.timestamp. For long-running sessions whose turn spans midnight (common with autonomous Codex runs lasting many hours), all calls after midnight are dropped from the new day —todayshows nothing until the turn ends, and daily history attributes the whole turn's cost to the turn-start day.Repro (synthetic rollout):
{"timestamp":"2026-07-28T15:55:00.000Z","type":"session_meta","payload":{"session_id":"x","originator":"codex_cli_rs","cwd":"/tmp/t","model":"gpt-5.5"}} {"timestamp":"2026-07-28T15:57:00.000Z","type":"response_item","payload":{"type":"message","role":"user","content":[{"type":"input_text","text":"work through midnight"}]}} {"timestamp":"2026-07-28T15:58:00.000Z","type":"event_msg","payload":{"type":"token_count","info":{"total_token_usage":{"input_tokens":100000,"cached_input_tokens":50000,"cache_write_input_tokens":0,"output_tokens":2000,"reasoning_output_tokens":0,"total_tokens":102000},"last_token_usage":{"input_tokens":100000,"cached_input_tokens":50000,"cache_write_input_tokens":0,"output_tokens":2000,"reasoning_output_tokens":0,"total_tokens":102000}}}} {"timestamp":"2026-07-28T16:10:00.000Z","type":"event_msg","payload":{"type":"token_count","info":{"total_token_usage":{"input_tokens":200000,"cached_input_tokens":100000,"cache_write_input_tokens":0,"output_tokens":4000,"reasoning_output_tokens":0,"total_tokens":204000},"last_token_usage":{"input_tokens":100000,"cached_input_tokens":50000,"cache_write_input_tokens":0,"output_tokens":2000,"reasoning_output_tokens":0,"total_tokens":102000}}}}In timezone UTC+8: at local 2026-07-29 00:30,
codeburn todayreports "No usage data found", although the secondtoken_count(2026-07-29 00:10 local) is squarely inside today.export --from 2026-07-29likewise returns 0 calls. Same-day control case (user message repeated before the second event) works fine, which isolates the cause to turn-level filtering.Real-world case: a Codex session running autonomously for 30+ hours (one turn, last user message at 23:57 local) — all post-midnight usage (~150 calls) vanished from
today.Suggested fix: filter calls inside the turn instead of dropping the whole turn:
(applies to both the
servedSourcesloop and thedurableSourcesloop in parseProviderSources)Optionally, in
aggregateProjectsIntoDays, attribute per-call cost/token columns todateKey(call.timestamp)rather than the turn day, so multi-day turns distribute cost across actual days in daily history. Turn-level stats (categories, one-shot) can stay turn-based.I've verified both changes locally against the repro and a real 51MB rollout: post-midnight usage shows up in
todaycorrectly, monthly totals unchanged.Happy to open a PR with this if you prefer.