You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Rust parity · slice 12 — absorb main fixes: Fable 5.1 (0.025x, #74) + Opus 5.5 (0.05x, #102) cache-read + Gemini match parity #76
The parity stack (#43→#54) branched from main at 15ea443 (#41). After that, #74 changed a statusline behavior on main: Claude Fable 5.1 / Mythos 5.1 bill cache hits at 0.025x base input, and every other model stays at 0.1x (pricing). The bash oracle now renders read(0.025x) and a different eq / saving % on those models. Then #102 added a third price: Claude Opus 5.5 bills cache hits at 0.05x. The Rust port still hardcodes 0.1, so it has fallen behind the oracle.
opus[- ]5[-.]5([^0-9]|$) → "0.05". Matches: claude-opus-5-5, claude-opus-5-5[1m], Opus 5.5 (1M context). No match: claude-opus-5, claude-opus-5-50.
In the non-Gemini branch of compute_turn_breakdown, read_mult="$claude_read_mult". Labels 0.025x / 0.05x / 0.1x. Write stays 1.25x (5m) / 2x (1h), output stays 5x, and Gemini is untouched.
What to change in rust/
input.rs:
add #[serde(default)] pub id: String to Model;
add the Claude cache-read multiplier to Session (value + label, e.g. an enum Standard / Opus55 / Fable51), with the same matches and precedence as bash.
Match by hand: regex is not a dependency (serde, serde_json, jiff only). Unit tests for the matching and non-matching ids and names above.
economics.rs:
the non-Gemini tuples (5m and 1h) hardcode (0.1, "0.1", …); take the read value/label from the session (0.025 / 0.05 / 0.1);
tests for 5m and 1h, including read_label == "0.025x" / "0.05x" and the eq / saving math.
ratelimits.rs: its test helper session() builds Session field by field, so add the new field there.
Bash (the oracle):[[ "$model" =~ [Gg]emini ]] matches the substring Gemini or gemini only.
input.rs today:display_name.to_lowercase().contains("gemini") matches any casing, so GEMINI or gEMINI is classified as Gemini. That switches the multipliers and drops the rate-limit line, where bash would not.
Real hosts send Gemini 2.5 Pro, so this is a byte-parity gap rather than a user-visible bug. v1's contract is still byte-exact with bash.
Unit tests:Gemini 2.5 Pro and gemini-2.5-pro → true; GEMINI and Opus 4.8 → false.
Golden: a fixture with an all-caps name, captured from bash.
Sequencing
This is slice 12. It lands after slice 11 as its own PR into rust-parity-v1. Don't amend the open slice PRs: injecting commits into the stacked branches shifts their tips and forces a re-stack of everything above them. Merge #75 and #103 first, so the golden output comes from the corrected oracle.
Done when
cargo test passes, and the Fable 5.1 and Opus 5.5 golden fixtures are byte-identical to tokenline.sh output for the same payload.
Part of #27 · parity v1, slice 12 (after slice 11, #89). Absorbs:
Context
The parity stack (#43→#54) branched from
mainat15ea443(#41). After that, #74 changed a statusline behavior onmain: Claude Fable 5.1 / Mythos 5.1 bill cache hits at 0.025x base input, and every other model stays at 0.1x (pricing). The bash oracle now rendersread(0.025x)and a differenteq/saving %on those models. Then #102 added a third price: Claude Opus 5.5 bills cache hits at 0.05x. The Rust port still hardcodes0.1, so it has fallen behind the oracle.What
tokenline.shdoes now (after #75 and #103)jqpass also reads(.model.id // "")as the last field, so the existing indices are unchanged.claude_read_mult(a string, default"0.1") from the lowercasedmodel.idor the lowercaseddisplay_name, first match wins:(fable|mythos)[- ]5[-.]1([^0-9]|$)→"0.025". Matches:claude-fable-5-1,claude-mythos-5-1[1m],Fable 5.1 (1M context). No match:claude-fable-5,claude-fable-5-10.opus[- ]5[-.]5([^0-9]|$)→"0.05". Matches:claude-opus-5-5,claude-opus-5-5[1m],Opus 5.5 (1M context). No match:claude-opus-5,claude-opus-5-50.compute_turn_breakdown,read_mult="$claude_read_mult". Labels0.025x/0.05x/0.1x. Write stays 1.25x (5m) / 2x (1h), output stays 5x, and Gemini is untouched.What to change in
rust/input.rs:#[serde(default)] pub id: StringtoModel;Session(value + label, e.g. an enumStandard/Opus55/Fable51), with the same matches and precedence as bash.regexis not a dependency (serde, serde_json, jiff only). Unit tests for the matching and non-matching ids and names above.economics.rs:(0.1, "0.1", …); take the read value/label from the session (0.025/0.05/0.1);read_label == "0.025x"/"0.05x"and theeq/savingmath.ratelimits.rs: its test helpersession()buildsSessionfield by field, so add the new field there.tests/golden: add a Fable 5.1 fixture and an Opus 5.5 fixture (withmodel.id). Capture its golden output from the fixed bash (mainafter fix: bill cache reads at 0.025x on Claude Fable 5.1 / Mythos 5.1 #75) and check byte-exact parity.Gemini detection parity
[[ "$model" =~ [Gg]emini ]]matches the substringGeminiorgeminionly.input.rstoday:display_name.to_lowercase().contains("gemini")matches any casing, soGEMINIorgEMINIis classified as Gemini. That switches the multipliers and drops the rate-limit line, where bash would not.Gemini 2.5 Pro, so this is a byte-parity gap rather than a user-visible bug. v1's contract is still byte-exact with bash.To do:
input.rs:is_gemini = name.contains("Gemini") || name.contains("gemini").Gemini 2.5 Proandgemini-2.5-pro→ true;GEMINIandOpus 4.8→ false.Sequencing
This is slice 12. It lands after slice 11 as its own PR into
rust-parity-v1. Don't amend the open slice PRs: injecting commits into the stacked branches shifts their tips and forces a re-stack of everything above them. Merge #75 and #103 first, so the golden output comes from the corrected oracle.Done when
cargo testpasses, and the Fable 5.1 and Opus 5.5 golden fixtures are byte-identical totokenline.shoutput for the same payload.