Repository navigation
Conversation
Prepared with AI assistance (audit + implementation: gpt-5.6-sol; review: Claude Fable 5); reviewed and tested before filing. Co-Authored-By: gpt-5.6-sol <[email protected]> Co-Authored-By: Claude Fable 5 <[email protected]>
|
This PR was auto-closed. Only contributors approved with Maintainers review auto-closed issues and reopen worthwhile ones. Issues that do not meet the quality bar in CONTRIBUTING.md may not be reopened or receive a reply. If a maintainer replies See CONTRIBUTING.md. |
📝 WalkthroughWalkthroughCodex JSONL parsing now detects replay boundaries using ChangesCodex replay attribution
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant CodexLog
participant visit_codex_session_file
participant CodexReplayBoundary
participant UsageAccounting
CodexLog->>visit_codex_session_file: read session metadata and token_count rows
visit_codex_session_file->>CodexReplayBoundary: check line index and token totals
CodexReplayBoundary-->>visit_codex_session_file: classify replay token row
visit_codex_session_file->>UsageAccounting: replace previous totals or emit usage
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@pullfrog review it |
@ryoppippi I have started the AI code review. It will take a few minutes to complete. |
|
✅ Action performedReview finished.
|
There was a problem hiding this comment.
ℹ️ No critical issues — minor suggestions inline.
Reviewed changes — this PR replaces the one-second replay heuristic in the Codex adapter with structural detection based on adjacent leaf/ancestor session_meta records and a native task_started whose started_at matches the record clock. It also carries inherited cumulative totals forward as a baseline and adds fixture-backed coverage for modern last_token_usage and legacy cumulative-only streams.
- Detect replay boundary structurally in
rust/crates/ccusage/src/adapter/codex/parser.rs— introduceddetect_replay_boundary,CodexReplayBoundary, and helpers to identify forked sessions byforked_from_idorsource.subagent.thread_spawn.parent_thread_id. - Skip inherited token_count events before the native boundary while updating
previous_totalswith the terminal cumulative usage. - Preserve same-second native events when a
task_startedproves the boundary is within the creation second. - Add regression fixtures for multi-second replay and fork-local same-second usage in both modern and legacy formats.
Kimi K2 (free via Pullfrog for OSS) | 𝕏
| if !replay_candidate { | ||
| return None; | ||
| } | ||
| leaf_creation_second.map(CodexReplayBoundary::LegacyCreationSecond) |
There was a problem hiding this comment.
The LegacyCreationSecond fallback path has no fixture coverage. Please add a test case for streams that omit task_started after adjacent ancestry metadata, or clarify why this path is intentionally untested.
Technical details
# LegacyCreationSecond is untested
## Affected sites
- `rust/crates/ccusage/src/adapter/codex/parser.rs:190` — returns `LegacyCreationSecond(leaf_creation_second)`
- `rust/crates/ccusage/src/adapter/codex/parser.rs:99-110` — `contains_token_event` skips token_count events whose timestamp second equals the leaf creation second
## Required outcome
- Either add a fixture + test exercising the `LegacyCreationSecond` branch, or document that the branch is intentionally defensive/untested.
- If a test is added, verify the skip semantics: the current code skips events *at* the leaf creation second, whereas the rest of the PR treats events *at or after* a `NativeLine` boundary as native. Confirm this asymmetry matches real Codex legacy log structure.
## Suggested approach
Add a `replay-no-task-started-legacy.jsonl` fixture that has adjacent `session_meta` records but no `task_started` marker, then assert which token_count events are kept/skipped. This protects the fallback from silent drift.
## Open questions for the human
- Is skipping events *at* the leaf creation second (rather than *before* it) the intended semantics for the legacy fallback?
Reviewed the PR: pulled the branch, read the full Verdict: solid and well-tested. The structural approach is a real improvement over the 1-second heuristic, and the modern/legacy × multisecond/fork-local matrix is good coverage. A few things worth confirming before merge, none blocking. 1. The let has_adjacent_parent = value.entry_type.as_deref() == Some("session_meta")
&& ancestor_id == parent_id.as_deref();
if !has_adjacent_parent && !explicit_thread_spawn {
return None; // -> copied history is NOT skipped -> double count
}If Codex ever emits any record between the leaf 2. 3. The Minor:
No code changes made; this is review-only. |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
rust/crates/ccusage/src/adapter/codex/parser.rs (1)
89-96: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low valueShare the replay line counter or document the lockstep invariant. Both paths count every physical line today, but the boundary logic still depends on that shared ordering; a short comment or helper would make the contract harder to break.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@rust/crates/ccusage/src/adapter/codex/parser.rs` around lines 89 - 96, Document the lockstep invariant for CodexReplayBoundary: NativeLine and LegacyCreationSecond must be derived from the same physical replay-line counter and remain aligned with each input line. Add a concise comment near the enum or boundary calculation, or introduce a shared helper, so future changes cannot update one counting path without the other.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@rust/crates/ccusage/src/adapter/codex/parser.rs`:
- Around line 89-96: Document the lockstep invariant for CodexReplayBoundary:
NativeLine and LegacyCreationSecond must be derived from the same physical
replay-line counter and remain aligned with each input line. Add a concise
comment near the enum or boundary calculation, or introduce a shared helper, so
future changes cannot update one counting path without the other.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: c583e65b-9722-4f20-8430-4fcbeabb4ccd
📒 Files selected for processing (5)
rust/crates/ccusage/src/adapter/codex/parser.rsrust/crates/ccusage/tests/fixtures/codex/fork-local-same-second-legacy.jsonlrust/crates/ccusage/tests/fixtures/codex/fork-local-same-second-modern.jsonlrust/crates/ccusage/tests/fixtures/codex/replay-multisecond-legacy.jsonlrust/crates/ccusage/tests/fixtures/codex/replay-multisecond-modern.jsonl
|
@pullfrog read all reviews from them and fix them |
|
I addressed both review findings in commit
Validation passed: However, pushing the commit failed because the PR branch lives on the fork I did not reply to or resolve the review threads because the fixes are not yet live on the remote. If you grant the bot push access to the fork, or if a maintainer can push this commit manually, the review comments are ready to be resolved. Task list (6/6 completed)
|
|
Run failed. View the logs →
|
|
Thanks for digging into this. The underlying bug was real, but this PR has been superseded — the one-second heuristic it replaces no longer exists on #1435 and #1438 replaced it with I checked your
So the common case is already fixed. What remains is narrower than this PR assumes: when the referenced parent log is unavailable, It is better closed inside the Closing this as superseded. A small PR scoped to just that fallback path would be very welcome, and I would review it happily. One process note for next time: the verification links point at |
|
Following up: I closed the fallback gap myself in #1501, so you are not left holding it. The measurements that shaped it, in case they are useful for your accounting work:
Thanks for pointing at the right place even though the patch had moved on. |
When a forked session's parent log is in the scanned set, `CodexReplayPlan` subtracts the exact replayed prefix. When it is not, the parser falls back to skipping the burst Codex rewrote to the fork instant, and that fallback bucketed events by their recorded second. Codex writes the replayed history in a few milliseconds, so a fork landing late in a second straddles the tick and everything past it was counted as the child's own usage. One real subagent log reports 47,175,282 tokens through the fallback against 19,820,638 with the parent log present, a 2.4x over-count from 315 replayed records on the far side of the tick. Follow the run rather than the second: skip while successive events stay within a second of each other and move forward, carrying the last skipped timestamp instead of a fixed second. Measured across the fork logs on hand, a rewritten burst spans 10 to 40ms while the child's own first turn follows a pause of 5.8 to 15.3 seconds, so a second sits two orders of magnitude above the burst and well below the pause. Requiring the step to be forward keeps a malformed log from walking the window backwards and silently dropping events. Verified against 210 real fork sessions whose parent log could be located, each scanned alone and beside its parent: the fallback now agrees with exact prefix subtraction for all 210, against 209 before. A full scan of the same directory is unchanged down to the cost figure, so the normal path is untouched. `skips_missing_parent_replay_when_duplicate_snapshot_is_suppressed` placed the child's own turn 800ms after the burst, which only read as the child's own under second bucketing. Its subject is snapshot suppression, so the fixture now uses a pause a real log would show and keeps testing that. A fork whose own first turn begins within the pause is still skipped. The shortest real pause observed is 5.8 seconds and the previous code carried the same class of exposure, so this narrows the window rather than closing it; the parent-log path has no such limit. Closes the gap left by #1457. Co-authored-by: Codesmith <[email protected]>
|
Historical audit: this pull request was auto-closed by the legacy contributor gate. That closure did not assess technical importance. Audit result: needs review. The current state does not prove resolution, but a fresh technical or product check is required before deciding whether the underlying request is still relevant. This closed PR will not be revived as-is; create a new PR only after reviewing the related issue and current |

Summary
session_metarecords identify copied history, andtask_started.started_atversus the record clock identifies the native boundarylast_token_usageand legacy cumulative-only rolloutsforked_from_idby #1369The reproduction and expected arithmetic follow the independent fixture/oracle approach documented in the Logpile accounting review. The exact 2026-07-18 matrix behind this change is published as the 2026-07-18 ccusage verification.
Testing
cargo +1.96.0 test --manifest-path rust/Cargo.toml --workspace --offline(445 passed)Prepared with AI assistance; I reviewed the implementation and test results.
Need help on this PR? Tag
/codesmithwith what you need. Autofix is disabled.Summary by cubic
Fixes Codex fork replay detection by using structural boundaries instead of a 1-second heuristic. Prevents double-counting and preserves real fork-local usage while skipping copied history across seconds.
session_metaor explicitsource.subagent.thread_spawn.parent_thread_id; set the boundary at a nativetask_startedwhosestarted_atmatches the record second; fall back to the leaf creation second for legacy streams.token_countevents before the boundary (even when they span multiple seconds) and carry their terminal cumulative totals forward as the live baseline.token_countevents; support both modernlast_token_usageand legacy cumulative-only logs.forked_from_id, and tolerate malformedtask_startedlines.Written for commit ebd45b9. Summary will update on new commits.
Summary by CodeRabbit
Bug Fixes
Tests