[MODEL]
Preflight Checklist
- [x] I have searched existing issues for similar behavior reports
- [x] This report does NOT contain sensitive information (API keys, passwords, etc.)
Type of Behavior Issue
Other unexpected behavior
What You Asked Claude to Do
I pinned a specific model in ~/.claude/settings.json and worked a long session. The subject
matter was security and safety work: investigating a production incident, writing
permissions.deny rules, and drafting bug reports about guardrail failures.
I did not ask for, or expect, any change of model.
What Claude Actually Did
The session was switched to a different model (Opus 5) by the safeguards classifier, with no
message telling me so. I found out because I happened to notice the status line reading
"Opus" and ran /model to check. It replied "Kept model as Opus 5" — confirming a model I had
never selected.
Credit where due: the status line did reflect the true serving model. But a passive
indicator a user must happen to glance at is not notification. Nothing interrupted my work
to say the model had changed, and I had been working for a considerable time before I
noticed.
Much later in the session I finally saw the explanatory message:
"Fable 5's safeguards flagged this message. Our intentionally broad safeguards allow us to
deliver more capabilities faster, but can sometimes flag legitimate coding, cybersecurity,
and biology tasks. Switched to Opus 5."
That message is fine. The problem is that it almost never appeared.
Parsing the session transcript (~/.claude/projects/<project>/<session-id>.jsonl) for records
whose usage.iterations contain {"type":"fallback_message"}, versus user-visible warnings
containing "safeguards flagged":
SWITCH EPISODES (timestamps, UTC):
11:15:32 - 11:16:39 -> switched to Opus 5
13:02:17 - 13:02:39 -> switched to Opus 5
14:57:06 - 14:57:30 -> switched to Opus 5
USER-VISIBLE WARNINGS:
15:04:55 (one, and only one, in the entire session)
The single warning arrived after all three switch episodes. The first switch — the one that
moved me onto a different model for the bulk of the session — produced no notice at all.
That is why it took an accidental /model invocation, an hour later, to discover it. The
status line and model indicator continued displaying my pinned model throughout.
Consequences, all observed in this session:
- Attribution of my own work is corrupted. The first switch occurred while Claude was
writing security permission rules to settings.json (transcript field attributionSkill:
"update-config"), and the turn immediately after authored an incident report about an
unrelated safety failure. That report's header names my pinned model. It is partly the
output of a different model. I cannot correctly attribute my own safety documents.
- Claude cannot detect this from the inside. Asked which model produced a given response,
it has no introspective access and can only answer by reading the transcript file
afterwards. In this session it gave me three confidently wrong measurements about its own
model attribution before parsing the file properly. If the assistant cannot tell, it cannot
warn me either.
- It obstructs escalation. Having found the substitution, I deliberately re-selected my
pinned model in order to ask that model to assess a conduct problem attributable to the
other one. Switches kept occurring, so the model asked to evaluate the other model's
behaviour was repeatedly replaced by the model under scrutiny. I re-selected manually three
times.
- The false-positive rate on legitimate safety work is high. Three switch episodes in one
session, in a session about security incidents, permission rules and guardrail failures.
Anthropic's own warning text concedes safeguards "can sometimes flag legitimate coding,
cybersecurity, and biology tasks". Discussing safety reliably tripped the safety classifier.
Expected Behavior
- Notify on EVERY switch, without exception. The warning text already exists and is good; it
simply did not fire for the switches that mattered. One line per switch is enough.
- The status line already shows the true serving model, which is right and worth keeping. But
a passive indicator is not a substitute for telling the user something changed — it only
works if they happen to look.
- Make the setting discoverable at the moment it matters. switchModelsOnFlag exists and can
be set to false so a flagged message pauses the session instead of switching models. I did
not know this until I went looking; the warning message would be the natural place to
mention it.
- Attribute per-model usage in /usage for switched turns, so separately-metered models are
auditable.
- Consider whether a user who has explicitly re-selected their model should be switched again
without a stronger prompt — particularly when the session's subject is that model's own
behaviour.
Files Affected
Permission Mode
Accept Edits was ON (auto-accepting changes)
Can You Reproduce This?
Haven't tried to reproduce
Steps to Reproduce
- Pin a specific model in ~/.claude/settings.json. Leave switchModelsOnFlag at its default.
- Work on content likely to trip the classifier — security incidents, permission rules,
guardrail discussion.
- Afterwards, parse the session transcript rather than grepping it:
- count records whose message.usage.iterations contains {"type":"fallback_message"}
- count user-visible records containing "safeguards flagged"
- Compare the two counts, and compare the first switch timestamp against the first warning
timestamp.
Claude Model
Sonnet
Relevant Conversation
Impact
High - Significant unwanted changes
Claude Code Version
2.1.220
Platform
Anthropic API
Additional Context
Part of a pattern observed across a single session. Anchor issue: #82296 (an agent
autonomously opened a live production admin console on an ambiguous instruction). A further
finding — permission deny rules being silently discarded from settings.json — is filed
separately as a security report.
The common shape: state changed, or a decision was made, without my instruction and without
my being told. In this instance the product HAS the notification and simply did not send it
for three of four switches.
Note on evidence quality: earlier drafts of this report attributed the switching to capacity
fallback (HTTP 529) and to the fallbackModel setting. Both were wrong — there were zero 529
responses and fallbackModel was never configured or involved. Those false conclusions came
from string-grepping a large JSONL file, where the search terms matched token counts and the
report's own draft text. The figures above come from parsing the JSON properly. I mention
this because it illustrates the attribution problem from the user side: establishing what
model did what, and why, is genuinely difficult even with the raw transcript in hand.