[BUG] CLI and mobile app report DIFFERENT models for the same live session, 60s apart, across pricing tiers — session cost is unverifiable
Summary
Two surfaces report different models for the same live session, and they disagree about which model is running right now — not which is saved as a default. Because the models involved sit in different pricing tiers, there is no way to determine what a session actually cost.
This is distinct from the existing issues in this area:
- #67976 requests a panel showing each agent's model (feature request, not a mismatch).
- #58450 is billing diverging from configuration.
- #54426 is a session self-downgrading mid-run.
This one is two readouts of the same session, taken a minute apart, that do not agree with each other.
Reproduction
Open a session, then read the model from two surfaces in quick succession.
Instance 1 — 60 seconds apart, same named session:
| Time | Surface | Reported model |
|---|---|---|
| 09:09 | Desktop CLI — /model help text | Set the AI model for Claude Code (currently Sonnet 5) |
| 09:10 | Mobile app, same session | Opus 5 |
The desktop reading is the /model command's own parenthetical statement of what the session is running now — not a stored preference. Sonnet-tier and Opus-tier bill at materially different rates.
Instance 2 — same day, different session:
| Surface | Reported model |
|---|---|
| Desktop /model picker | Fable 5, selected, checkmark shown |
| Mobile app, same session | Opus 4.8 — a model that does not appear in the desktop picker's list at all |
Secondary defect in the same picker
The picker lists the same model twice with byte-identical descriptions:
1. Default (recommended) Opus 5 with 1M context · Best for everyday, complex tasks
2. Opus (1M context) Opus 5 with 1M context · Best for everyday, complex tasks
There is no stated difference between entries 1 and 2. Compounding it, [1m] is redundant on this model — 1M context is its default and its maximum — so a user who deliberately selects entry 2 to secure the larger window has changed nothing and is told nothing.
Impact
- Spend is unverifiable. Model identity is the unit of billing. When two surfaces disagree about the running model across pricing tiers, per-session cost cannot be determined by the user or reconstructed afterward.
- It makes other reports unfalsifiable. Any issue involving unexpected usage, or a model switching mid-session, rests on a model-identity readout. If those readouts disagree with each other, neither the user nor the vendor can settle the question.
- It breaks per-window model assignment as a workflow. Assigning cheaper tiers to routine lanes and expensive tiers to hard reasoning is a documented pattern; it depends on being able to confirm which lane is on which model.
Environment
- Claude Code 2.1.220 (observed); still present after upgrading to 2.1.222
- Windows 11 desktop + iOS app, same account, same session
- Screenshots available on request
Suggested fix
Have every surface read model identity from one authoritative session-state source rather than each deriving it independently, and de-duplicate the picker entries (or state what distinguishes them).
3 Comments
A sharper instance: the picker contradicts itself within a single render
This isn't CLI-vs-mobile this time — it's the
/modeldialog disagreeing with itself, in one screen, at one paint.Reproduction, verbatim from the session:
Then opening
/modelagain in the same still-running session, the picker renders:The header line and the checkmark disagree about which model is active, in the same dialog:
✔(the element that normally marks the active selection): on option 2, Opus, not option 4, Sonnet.So a user reading this screen gets two contradictory, equally-authoritative-looking answers from the UI in the same instant, with no indication which one is real.
Why this is worse than the restart-precedence case
The third
/modelinvocation above is correct and self-consistent — it plainly states the session override took effect and names the settings.json pin that will override it back on restart. That's a good UX pattern: two facts, both true, clearly attributed.The picker render is not that. It is one screen making one claim in prose and a contradicting claim in its own selection indicator, with no restart or persistence framing to explain the discrepancy. There is no reading of this screen that resolves to a single confident answer for "what model is this session actually using right now."
Why it matters beyond confusion
This is the same underlying class as the original report — the model a session is billed against and the model the UI displays are not reliably the same fact — except here it's reproducible from a single command with no second device or account needed. Given
/modelis the only user-facing surface for checking this, and it can render self-contradictory in a single paint, there currently isn't a reliable way for a user to answer "what am I running, and what am I being charged for" from inside the product at all.Environment
claude-opus-5) and user-level (sonnet)settings.jsonmodel pins in playFollowing up on your earlier post — this one hits even harder for me. The two readouts disagreeing about which model is running right now (not what's stored as default) means the trust gap isn't just "what was I billed" but "what did I actually get."
The downstream consequence that's hard to recover from: even if Anthropic eventually publishes a per-session cost breakdown, you have no ground truth to reconcile against. If Sonnet shows on CLI but Opus shows on mobile, the bill is just whatever the wire log says — and you can't verify the wire log without an internal audit tool the customer doesn't have.
One thing I'm genuinely curious about: when you saw Sonnet-vs-Opus on the same session a minute apart, did you keep watching for the rest of that session? Did the model that actually ran match either readout, or did it match neither? Asking because if the actual-run model is a third thing entirely, that's a different class of bug than "the surface is wrong."
Not looking for resolution from you — just trying to understand which layer of "the bill is unverifiable" is the actual fracture point.
I've spent the last hour reading both your posts end-to-end (#84002 and this one), and I think I owe you something more direct than another question.
Your "session cost is unverifiable" isn't really a billing bug — it's the read-trust collapse. Once two surfaces disagree about which model is running right now, every downstream number (token counts, response time, cost-per-task, even what features were available in the session) becomes unauditable. That's not "Claude lied to you about price." That's "you have no way to check whether your bills reflect reality, ever again, without trusting them."
I've been building tooling to detect exactly this class of failure in agent systems — not Claude-specific, but the broader pattern where pricing/observability/state diverge. The honest answer I can give you right now:
model_config.api_moderesolution paths (your session likely had a fallback chain active during that 60-second window — same class of issue as thechat_completionsvsanthropic_messagesdrift in hermes-agent#81481).I have one offer for you, no strings:
I'll spend ~2 hours building a per-session audit script you can run locally — it logs model identity, mode, token accounting events, and any surface mismatches in real time on your own sessions. You'll get verifiable ground truth regardless of what any client surface tells you.
I want to do this because:
If it works for you, great — you'll have a working audit trail on your next 10 sessions. If it doesn't, I'll tell you why and you'll know not to trust me next time either.
Want to try? Just reply "yes" and I'll ship it within 24 hours. No email required, no upsell, no "free trial" funnel.