Repository navigation
fix(claude): keep entries with null model inside usage iterations - #1715
github-actions[bot] wants to merge 1 commit into
Conversation
Co-authored-by: n0soc <[email protected]>
|
Important Review skippedBot user detected. To trigger a single review, invoke the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
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 |
|
@coderabbitai @cubic-dev-ai Please review this one-line Nushell runtime fix. |
@ryoppippi Couldn't start the review: please upgrade to a paid plan to review bot-authored PRs. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '--- PR metadata and changed files ---'
gh pr view 1715 --repo ccusage/ccusage --json title,body,baseRefName,headRefName,files --jq '{title, baseRefName, headRefName, files: [.files[] | {path, additions, deletions}]}'
echo '--- Diff ---'
gh pr diff 1715 --repo ccusage/ccusage --color=never
echo '--- Adapter source outline ---'
ast-grep outline rust/adapters/claude/src/lib.rs --items all --view expanded 2>/dev/null || true
echo '--- Relevant symbols and test references ---'
rg -n -A60 -B15 'has_unsupported_null_field|iterations|claude-fable-5-1' rust/adapters/claude/src/lib.rsLength of output: 34636 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo '--- Null-field policy and TokenUsageRaw definition/usages ---'
rg -n -A45 -B15 'struct TokenUsageRaw|enum Speed|is_unsupported_nullable_field|has_unsupported_null_field' rust
echo '--- Claude TypeScript loader null handling ---'
rg -n -A45 -B15 'unsupported.*null|null.*unsupported|iterations' --glob '*.ts' --glob '*.tsx' .
echo '--- Current PR commit and comparison ---'
gh pr view 1715 --repo ccusage/ccusage --json commits --jq '.commits[] | {oid: .oid, messageHeadline: .messageHeadline}'
echo '--- JSON tests covering invalid nulls within iterations ---'
rg -n -A8 -B5 'iterations.*(speed|input_tokens|output_tokens|type).*null|(speed|input_tokens|output_tokens|type).*null.*iterations' rust/adapters/claude/src/lib.rsLength of output: 43797
You are interacting with an AI system. |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
ccusage-guide | 50c549a | Commit Preview URL Branch Preview URL |
Sep 12 2026, 10:49 PM |
| continue; | ||
| } | ||
| } | ||
| cursor = key_start + 1; |
There was a problem hiding this comment.
This fallthrough flips the string state for the rest of the line.
When "iterations" matches at cursor but is not followed by : and [, the loop resumes at key_start + 1 with in_string still false. The scan then walks the bytes of iterations, reaches the closing quote, and sets in_string = true, so from here on every quote is read in reverse. Two inputs reach this path: a string value that is exactly "iterations", and an iterations key whose value is not an array.
The effect on a real Fable line is fail-closed: a later "iterations":[ key is never seen because the scan arrives at its opening quote believing it is inside a string, no range is recorded, and the line is dropped as before this PR. The reverse case also exists: a quoted \"iterations\":[ inside a later string would be taken for a real array.
The opening quote already belongs to a string in this case, so the fix is to enter string mode before resuming:
cursor = key_start + 1;
in_string = true;
continue;A test that fails on the current commit and passes with that change:
#[test]
fn keeps_string_state_after_iterations_string_value() {
// A string value equal to "iterations" precedes the real array.
assert!(!has_unsupported_null_field(
br#"{"message":{"model":"m","content":"iterations","usage":{"input_tokens":0,"iterations":[{"type":"message","model":null,"input_tokens":0,"output_tokens":0}]}}}"#
));
}Unrelated to the above: the CodeRabbit finding about exempting every null inside the array can stay as is. TokenUsageRaw in ccusage-core has no iterations field, so nothing inside the array reaches the typed parse of
the main entry, and speed there is already Option<Speed>. A null token count inside an iteration only makes advisor_usages_from_line return nothing, which is a softer failure than dropping the whole line.
References #1710:
has_unsupported_null_fieldinrust/adapters/claude/src/lib.rsno longer drops entries whose only listed null ismessage.usage.iterations[].model. It computes string-aware byte ranges for every"iterations": [...]array and skips:nullhits inside them, so Fable 5.1 entries deserialize normally. Top-level nulls are still rejected. Shared by both entry and daily loaders.\n\nTests: added 4 regression tests including the exact JSONL line from the issue (1 entry underclaude-fable-5-1). Full adapter suite: 26 passed, 0 failed; fmt and clippy clean.\n\nCommitted locally on branchpullfrog/1710-iterations-null-model(commit535bce34); working tree clean. Push disabled in this environment (Push is disabled. This repository is configured for read-only access.), so a maintainer needs to push the branch / open the PR.Closes #1710
Summary by cubic
Fixes issue #1710 by keeping Claude usage entries whose only null field is
message.usage.iterations[].model, which Fable 5.1 writes as explicitnull. Previously these entries were dropped as unsupported; nowhas_unsupported_null_fieldskips:nullhits inside"iterations": [...]arrays, while still rejecting top-level nulls.Written for commit 50c549a. Summary will update on new commits.