feat(token-usage): match forked Codex sessions against their parent's usage prefix
A forked rollout replays its parent's history with timestamps rewritten to the fork instant. The rewritten-burst heuristic (skip leading events spaced <= 1s apart) misidentifies a real fork whose own first turn follows the replay after a longer pause — observed in the wild as a 16,508-token replayed event counted as genuine usage 6.975s before the child's first own turn. Port ccusage's parent-prefix matching into the incremental extractor: a fork now parks in AwaitingParent until the worker resolves the parent rollout and answers with its pre-fork usage signatures (per-event deltas, timestamps excluded; collected without replay filtering so a prefix the parent itself replayed stays included, truncated at the child's session_meta timestamp). The child's leading events consume the matching front of that prefix; a mismatch after any match means the replayed history ended, and a mismatch with nothing matched — or an unresolvable parent — falls back to the burst heuristic exactly as before (never retried, matching ccusage's unavailable-parent path). The unmatched remainder persists in the extractor state, so the parent is read once per fork, not per pass or restart. The worker serves prefix requests after restoring state and after every consumed line. Parent resolution tries files tracked under the parent's external session id, then a bounded scan of the codex sessions tree, always confirming a candidate by its recorded session_meta id (ccusage locates parents by id, never filename) — a bounded single-file read in the async worker. The spec's fork section is rewritten and the split-burst accepted limitation narrows to the unresolvable-parent fallback path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
S
Sasha Varlamov committed
262201056f65346acea89c3f149c7ff8113a03ca
Parent: aa9b098