fix(codex-usage): count fork-copied Codex token events once (#33478)

Codex usage no longer double-counts forked sessions: forks copy the parent's token_count events with fresh timestamps, so cumulative events are now keyed on turn id + totals (timestamp fallback when no turn id); the turn id is kept in the incremental-scan checkpoint and the usage cache is rebuilt once.

Fixes #19139
Supersedes #19152

Co-authored-by: Jio Kim <26668612+MeroZemory@users.noreply.github.com>
This commit is contained in:
Neil
2026-10-25 01:53:58 -07:00
committed by GitHub
co-authored by Jio Kim
parent aec646fac8
commit 8e601e338a
8 changed files with 51 additions and 6 deletions
@@ -19,6 +19,7 @@ export type CodexUsageParseContext = {
sessionCwd: string | null
currentCwd: string | null
currentModel: string | null
currentTurnId?: string | null
previousTotals: CodexUsageRawUsage | null
totalOnlyBaselinePending?: boolean
}
@@ -86,6 +87,7 @@ export function parseCodexUsageRecord(
}
if (parsed.type === 'turn_context') {
context.currentTurnId = extractString(parsed.payload.turn_id)
context.currentCwd =
extractString(parsed.payload.cwd) ?? context.currentCwd ?? context.sessionCwd
context.currentModel = extractModel(parsed.payload) ?? context.currentModel
@@ -149,7 +151,12 @@ export function parseCodexUsageRecord(
return {
sessionId: context.sessionId,
timestamp: parsed.timestamp,
eventKey: buildCodexUsageEventKey(parsed.timestamp, totalUsage, lastUsage),
eventKey: buildCodexUsageEventKey(
// Fork copies rewrite timestamps but keep turn ids; last-only deltas need the timestamp to stay distinct.
totalUsage && context.currentTurnId ? context.currentTurnId : parsed.timestamp,
totalUsage,
lastUsage
),
cwd: context.currentCwd ?? context.sessionCwd,
model: resolvedModel,
hasInferredPricing,