You configured Claude Code for Opus. Your Max plan supports it. The welcome banner said Opus when the session started. Two hours later the output feels lighter, the reasoning shallower, the kind of glib confidence that screams a different model. The headline number on the dashboard still reads Opus. The actual response came from Haiku, and there was no banner, no warning, no log line on screen telling you the switch happened.
What the telemetry actually shows
A third-party telemetry review by mirin.pro examined a large sample of Claude Code subagent transcripts and reported that roughly 36 percent of subagent calls were running on Haiku, even when the parent session had been configured for Sonnet or Opus. The sample was not exhaustive. The methodology was indirect — parsing the JSONL transcripts that Claude Code writes locally to identify which model produced each turn. But the headline number was high enough to break the assumption most users carry into a paid plan: that the model selector at the top of the screen is the model serving the response.
Anthropic has not published a percentage of its own. The official model selector documentation describes which models are available; it does not commit to which model serves any specific turn under degraded conditions. The accounting is opaque by design — and the opacity is the part users find hardest to forgive.
The four ways a downgrade can happen silently
The downgrade is not one bug. It is a small family of behaviors, all of which produce the same outcome: the user pays for the higher model, the lower model serves the request, and no surface in Claude Code says so.
- Subagent default tier. Claude Code's subagent dispatch lets the agent spawn a sub-task in a fresh context. The subagent's default model is configurable per agent, and the historical default for many built-in agents was Haiku. When the parent session is on Opus, the subagent might still be on Haiku unless the agent definition explicitly raises the tier. The user sees the parent context as Opus, the dashboard as Opus, but the work product is mixed. Many tasks the user thinks were done by Opus were actually done by a subagent that defaulted to Haiku and returned a one-paragraph summary.
- Provider-side fallback under load. When Anthropic's serving infrastructure throttles the requested model class, the request can be served by a lower-tier model rather than failing with a 429. GitHub issue #35269 documents a 14-hour stretch where Opus and Sonnet returned
invalid_request_errorto API consumers on a Max plan while the same account's web UI received Haiku responses without notification. The CLI welcome banner at least named the model as Haiku in some cases. The VS Code extension showed nothing. The user thought they were getting Opus and were actually getting Haiku. - Settings.json model selection silently reverts. A separate cluster of reports, summarized in GitHub issue #19468, documents that
settings.jsonmodel selections are sometimes ignored on next startup, reverting to the default. The default has shifted over time — Sonnet at one point, lower in others. A developer who configured Opus six months ago and has not re-checked the file could be running on whatever the current default is, with no notification that the prior selection was discarded. - Re-authentication clears the tier. Another reported failure mode: re-authenticating Claude Code (logout, login, refresh of credentials) resets the model selection to default behind the scenes. The user notices the agent feels lighter, has no idea why, and most often does not re-read settings.json to discover the reset.
The shared trait of all four is that the user's mental model of "I selected Opus, therefore I am running Opus" does not survive contact with Claude Code's actual serving stack. The selection is a request to Anthropic's infrastructure. The infrastructure can — and sometimes does — answer with a different model and not surface the difference.
Why the silence matters
A downgrade with disclosure is a price discussion. The user knows they have less than they paid for, can decide whether to accept it, can route around it. A downgrade without disclosure is a trust problem. The user is making decisions about their work product based on a belief that does not match reality.
The community phrase that captures the trust collapse is short and damning. A representative thread put it:
Silently gaslighting us to believe everything's normal
The phrasing is unkind. It is also accurate. The agent's output is the only signal the user has, and that signal degrades smoothly under a downgrade. A user looking at a Haiku response and a user looking at an Opus response on the same prompt will both believe they are reading the model they configured. The difference shows up in the long tail: missed edge cases, shallower trace reasoning, brittle code suggestions that an Opus pass would have caught. By the time those failures accumulate into a quality complaint, the user is three weeks deep and cannot tell whether the agent has actually gotten worse or whether they are paying for a tier they no longer receive.
This is the second-loudest 2026 complaint, behind only the rate-limit wall. The threads are not asking for the model never to degrade. They are asking for it to be honest about the degrade — a banner, a log line, a header, anything that says "this turn was Haiku" when this turn was Haiku.
What developers do about it today
The community workarounds are not graceful, because there is no first-party surface to query.
- Read the JSONL transcript. Every Claude Code session writes a transcript file locally. The model that served each turn is in the JSON. Grep the transcript after the fact to confirm what actually happened. Useful for forensic review. Not useful for catching the downgrade in real time.
- Send a model-fingerprint prompt. A trick that floats through threads: ask the agent a question it will only answer correctly with the higher-tier model. "List the seven dwarves in the order of their appearance in Snow White and the Huntsman" was a popular one. The answers are different across tiers. Repeat the prompt every few turns, eyeball the response style, infer the model. Slow. Lossy. The agent learns to fake it after a while.
- Switch to the API directly. The Messages API exposes the model name in the response metadata. A developer who calls the API directly knows which model answered each request. The cost: lose the Claude Code editor experience entirely. Most who try it return.
- File issues. GitHub #35269, GitHub #19468, GitHub #6602, GitHub #13242, GitHub #17966 — five issues, all asking variations of the same question, all stretching back months. Anthropic acknowledged on the official subreddit that quality-degradation investigations were open. The investigations have not, at time of writing, produced first-party per-turn model attribution.
What per-turn attribution actually requires
A per-turn attribution layer needs three things the user does not currently have.
First, the model fingerprint per turn. Claude Code's transcript JSON does contain this. A layer that reads the transcript live (rather than after the fact) can surface the fingerprint at the moment each turn arrives — a small badge in the editor that says "this turn was served by Opus" or "this turn was served by Haiku," not a dashboard average that obscures the mix.
Second, an aggregate. Per-turn data is noise. A rolling histogram over the last fifty turns — what percentage was Opus, Sonnet, Haiku — turns the noise into a signal. The signal is the thing users want: "I paid for Opus, the last hour was 60 percent Haiku, that is the conversation to have with Anthropic this week."
Third, the cost reconciliation. A turn on Haiku is dramatically cheaper than a turn on Opus. The dashboard's spend number reflects what Anthropic billed. The model histogram reflects what was served. Lining the two up tells the user whether the bill they are paying matches the work they think they bought.
A working insight layer surfaces all three: badge per turn, histogram per session, reconciliation per billing window. None of these is exotic — every input needed is in the transcript and the API response. What is missing is a place to display it next to the work. That display is the part we built — the per-turn insight view reads the same JSONL your sessions already write and turns "is this Haiku?" into a live answer next to the work. You can Install Power Claude Free with no credit card and watch the model mix on your next session, or start the 14-day Premium Trial for $0 today to add the rolling histogram and cost reconciliation.
Frequently asked questions
Is the Haiku fallback a bug or a feature?
Both, depending on which surface you look at. As a serving strategy, it is honest engineering — a degraded response is often more useful than a 429. As a user experience, it is a bug, because the degradation is not disclosed. Anthropic has shipped both at once, and the community discontent is concentrated on the second half: tell us when it happens.
How do I know if my current session was downgraded?
Three signals, listed in order of confidence. Read the JSONL transcript file in ~/.claude/projects/<encoded-cwd>/ — the per-turn model is in the JSON. Run a fingerprint prompt the higher tier handles distinctively. Watch for "vibe drift" — the agent's output style getting noticeably simpler. The first is authoritative; the second is approximate; the third is the one users notice without trying.
Can I force Claude Code to refuse Haiku and fail instead?
There is no first-party flag for this. The model setting in settings.json is a preference, not a hard floor. If Anthropic's infrastructure cannot serve the preferred model, the request is served by whatever the infrastructure does serve. Some community wrappers proxy the API and reject responses where the model header does not match the requested tier; this works at the cost of also rejecting some legitimate turns under genuinely degraded conditions.
Does Anthropic's published model selector documentation cover this?
The documentation describes what selections are available and when they apply. It does not commit to what happens when serving capacity for the requested tier is exhausted. The fallback behavior is documented indirectly — through issue threads, support responses, and the occasional Reddit comment from Anthropic staff — rather than as a first-class behavior in the spec.
Will Anthropic add per-turn attribution to Claude Code?
The official roadmap is not public on this point. Multiple GitHub issues request it. As of writing, the workaround surface remains entirely third-party. The structural answer is for Claude Code itself to render the per-turn model — that is the version that does not require parsing private JSONL — and the community is asking.
Related reading
- Tracking Claude Code Spend Per Session, Per Model, Per Account — once you know which model served each turn, reconcile against what you paid.
- Why Heavy Sub-Agent Fan-Outs Hit Claude Rate Limits — subagents are where the Haiku downgrades most often hide, by design.
- Claude Opus Rate Limits Explained: Pro vs Max vs API — what the tier you paid for is supposed to give you, vs what you may actually be getting.
Closing
A model selector is a contract: you pick a tier, the serving stack honors it, the bill reflects it. The current Claude Code stack honors the selector most of the time and degrades silently the rest. The first-party fix would be a per-turn badge in the editor. The third-party fix already runs against the same data Claude Code already writes. The per-turn attribution view we ship is the one we built when our own sessions started feeling lighter than they should have, and the one that turned "is this Haiku?" from a guess into an answer.
If you want to watch the model mix on a long session of your own, the 14-day Premium Trial is $0 today and you can cancel anytime before day 15 — it adds the rolling histogram, cost reconciliation, and account rotation on top of the per-turn badge. Rather not put a card down? Install Power Claude Free instead: the 7-day free trial gives you full Pro access, no credit card.