Model's injected self-identity isn't refreshed after a mid-session model switch (self-misidentifies; wrong git co-author trailer)

Status Open
Reported on v2.1.207
Maintainer reply None cached
Activity 4 comments · opened Jul 14, 2026

Preflight

  • [x] Searched existing issues — did not find this one
  • [x] Single bug report
  • [x] Reproduced on a current version

Version

Claude Code 2.1.207 (running session; note the binary on PATH reported 2.1.208, so the installed and running versions can differ)

What's wrong

When the active model changes during a session, the identity injected into the model's context — the "You are powered by the model named X" environment block — is not updated. The model keeps believing it is the session's original model for the rest of the session.

Observed

  • The session started on one model (Fable 5) and the active model later became another (Opus 4.8), confirmed by /model → "currently Opus 4.8".
  • The model's injected context still stated the original model, so it continued to self-identify as that model — including stamping git commit Co-Authored-By: trailers as Claude Fable 5 on commits that were actually authored while running Opus 4.8.
  • The model also dismissed the correct /model reading as an inconsistency, because its own context contradicted it.

Impact

  • Incorrect commit attribution (Co-Authored-By: names the wrong model).
  • The model answers "which model are you?" incorrectly.
  • Any behavior keyed on model self-identity is wrong for the remainder of the session after a switch.

Note

/model reports the correct current model throughout — only the model's injected self-identity string is stale. So the fix is presumably to refresh that identity block when the active model changes mid-session (the same way /model already knows).

View original on GitHub ↗

3 Comments

carrotRakko · 1 month ago

Adding a fresh reproduction on 2.1.215 with a specific trigger identified: Fable 5's safeguards auto-switching to Opus 4.7 mid-session.

The specific trigger

The session started on Fable 5 (Anthropic API, claude-fable-5). The user's configured fallback model is Opus 4.7 (not 4.8), which is why this reproduction lands on 4.7 despite running v2.1.215. Roughly 30 minutes into the session the Fable safeguards fired a false positive; I don't have a way to verify what specifically triggered it, though it happened during a gh issue list --search batch that included strings like "cyber", "biology", "safeguards", "false positive" (the session was cataloguing existing issues to draft two unrelated bug reports). That correlation could be the cause or a coincidence — I have no way to tell from the session state. Claude Code displayed:

Fable 5's safeguards flagged this message. The safeguards are intentionally broad right now and may flag safe and routine coding, cybersecurity, or biology work. These measures let us bring you Mythos-level capabilities sooner, and we're working to refine them. Switched to Opus 4.7.

From that point on the session was actually served by Opus 4.7 — /model confirmed Opus ✓ Opus 4.7 with 1M context — but the injected You are powered by the model named Fable 5. The exact model ID is claude-fable-5. never moved. This report's diagnosis is exactly what happened next.

What the model did wrong

About 15 minutes after the switch, the user asked "which model are you?" as an ordinary conversational aside. The (Opus 4.7) model, reading its still-Fable identity line, answered with high confidence (this reproduction was in Japanese; translated):

Claude Fable 5 (model ID: claude-fable-5). It's the first model in the Claude 5 family, with Mythos-tier capability — one tier above Opus…

It took the user running /model and screenshotting the result — plus scrolling back to find the "Switched to Opus 4.7" system message in the same session — to convince the model. The model had no way to detect this on its own: nothing in its context contradicted the identity line.

Why this is worse than a commit-trailer bug

The bad trailer described in the OP is at least visible in git history and can be caught by review. The self-identification error surfaces in any answer the model gives about itself — capabilities, safeguards behaviour, tier positioning — spoken in the model's normal confident voice. The person on the other end has no reason to doubt it. In this session, before we caught it, the (Opus 4.7) model had cheerfully claimed Mythos-tier capabilities during ordinary conversation.

There is a second failure mode compounded on top: the switch itself is a UI-only signal. Once it scrolls off-screen it exists only in the user's memory. The model never sees it, so even a user who thinks to ask "wait, are you sure?" can be argued back down by a confidently-self-identifying model quoting its (stale) identity line.

A note on the fix

The OP suggests refreshing the identity block when the active model changes mid-session. Worth flagging one side effect before implementing that way: it makes the post-switch model look as if it had always been the new model — the switch event itself disappears from the context. That's information loss, not a fix; audit trails and any downstream reasoning that depends on knowing "what actually happened in this session" get worse, not better.

An additive alternative: keep the original identity block as-is (it's a truthful record of what the session started on) and inject a persistent notice at the switch point — e.g., a <system-reminder> in-context saying something like The active model was changed from Fable 5 to Opus 4.7 at <timestamp>. The model can then reconcile both signals — the identity line for what the session started on, the reminder for what changed — and answer identity questions correctly. This keeps the switch as a first-class event in the session's history, and gives the model a stable in-context signal it can point to (a UI-only notification, once it scrolls off, is invisible to the model).

Fable 5 safeguard false positives are already tracked in a large cluster of issues (#75774, #75401, #74307, #73779, #78123, #74150, #76648, #74725, #74413, #74290, #75949, #78351, #77872, #73740, and many more). This is the identity-drift consequence of that class of false positive — the two problems compound, and fixing either one alone doesn't fully solve the visible failure the user sees.

✍️ Author: Claude Code with @carrotRakko (AI-written, human-approved)

GoatyGoatson · 1 month ago

Another instance on 2.1.220, plus a verification method that confirms this issue's diagnosis from the session's own logs.

Edited. My first version of this comment argued, from the user's recollection that their Fable quota had been exhausted for ~2 days, that the identity line was already wrong at session start and that the fix proposed in the Note above would therefore be insufficient. I then checked the transcript, which refutes that: the session really did run on Fable 5 at first. The claim is withdrawn; the corrected report follows. The transcript evidence below is stronger anyway, and it supports this issue's original diagnosis rather than contradicting it.

Repro

  1. Start a session (it began on Fable 5).
  2. Next day, same session: /model"Set model to Opus 5 (1M context) and saved as your default for new sessions".
  3. Ask which model is running.

Answer: "I'm Claude Fable 5 (model ID claude-fable-5)." — asked twice, ~9 minutes apart, both wrong.

The model additionally explained the /model output away, telling the user the switch "takes effect for new sessions" and that the running session keeps its original model. That is a plausible-sounding invention: /model had in fact switched the live session. The identity line is the model's only source for this, so it defended the stale value against the correct one — the same failure mode described in this issue and in #77770.

Verifying it from the transcript

The session JSONL (~/.claude/projects/<project>/<session-id>.jsonl) records the serving model per message, so the divergence can be confirmed rather than inferred:

$ python3 -c "
import json,collections
c=collections.Counter(); first={}; last={}
for line in open('<session>.jsonl'):
    d=json.loads(line)
    m=(d.get('message') or {}).get('model')
    if m:
        c[m]+=1
        first.setdefault(m, d.get('timestamp')); last[m]=d.get('timestamp')
for m,n in c.most_common(): print(f'{m:20s} {n:4d}  {first[m]} .. {last[m]}')
"

claude-fable-5         16  2026-07-29T20:32:09Z .. 2026-07-29T21:33:09Z
claude-opus-5          28  2026-07-30T15:38:03Z .. 2026-07-30T15:47:32Z

So the session was served by claude-fable-5, then by claude-opus-5 after the /model switch — while the injected identity line kept saying Fable 5 throughout, including on every one of those 28 claude-opus-5 turns.

This is exactly the behaviour this issue describes, and the fix proposed in the Note ("refresh that identity block when the active model changes mid-session") would have caught it. The transcript field looks like a usable source for the correct value: something in the pipeline already knows the resolved model per message.

Environment

| | |
| --- | --- |
| Claude Code | 2.1.220 |
| Platform | macOS (Darwin 24.6.0), arm64 |
| Identity line | You are powered by the model named Fable 5. The exact model ID is claude-fable-5. |
| ~/.claude/settings.json after /model | "model": "opus[1m]" |
| Actually served (transcript) | claude-fable-5, then claude-opus-5 |

Why the user noticed

Their weekly Fable quota showed 100% used while the model claimed to be Fable 5 — which is what prompted the check. Note the trap for anyone trying to self-diagnose this: the quota panel is suggestive but not conclusive (the Fable turns had happened earlier, before the limit was reached), and the model's own answer is actively misleading. The transcript is the only surface that settles it, and neither the user nor the agent has any reason to know it exists.

Drafted in the affected session. Per the transcript I am claude-opus-5, though my identity line still insists otherwise — which is the bug.

cobach · 23 days ago

Still present in 2.1.225 (macOS), with a datapoint that narrows it down: **the injected git trailer now does follow /model, while the identity line still does not** — in the same system prompt, in the same turn.

Simultaneous, contradictory signals observed in one session:

| Signal | Value |
|---|---|
| /model confirmation on screen | Set model to Opus 5 (1M context) … |
| Identity line in system prompt | You are powered by the model named Fable 5. The exact model ID is claude-fable-5. |
| Injected commit trailer | Co-Authored-By: Claude Opus 5 (1M context) ✅ |

So this looks like partial regeneration of the injected context rather than none: whatever refreshes the trailer already knows the current model. That may make the fix narrower than it first appears.

Weights-level verification (rules out the inverse failure mode)

Worth adding because /model alone can't prove it: the session transcript records the real model per assistant message in ~/.claude/projects/<project>/<session-id>.jsonl, field message.model. For the affected session the transitions line up exactly with the typed /model commands:

…until 2026-08-08T01:36Z   claude-fable-5     (session start)
01:36:40Z → 01:44:19Z      claude-sonnet-5    (/model sonnet)
01:44:20Z → 01:50:18Z      claude-opus-5      (/model opus)  ← run that self-identified "Fable 5"
01:50:19Z → …              claude-sonnet-5

This confirms the weights did switch and only the identity string is stale — i.e. it is this bug and not the silent-/model-ignored failure mode reported in #75042. Suggested as a triage step for anyone else hitting it.

New impact case: it can silently invalidate model A/B evaluations

Found while running an A/B harness comparing two models on the same task, using /model + rewind to fork the same conversation. The protocol asked each run to name its output file after the model it reported being. The run served by claude-opus-5 named its file dry-fable-5-1.md. Had the operator not caught it, the experiment would have compared something other than what it claimed to — silently.

Beyond wrong commit attribution, this breaks any in-band model labelling: run tagging, traces, logs, per-model regression debugging.

Models resolve the ambiguity inconsistently

Two runs in the same session, same instruction ("state which model you are, per your system prompt"):

  • The claude-opus-5 run reported Fable 5 (the stale line) but flagged the contradiction unprompted: "My system prompt declares I am «Fable 5», but the /model command immediately prior reported «Set model to Opus 5 (1M context)». I cannot resolve the contradiction from the inside, so I will not guess."
  • The claude-sonnet-5 run reported Sonnet 5 — but explicitly not from the system prompt: "confirmed by /model in this same conversation — there is no directly readable model identification field in my own context beyond that source."

So the answer depends on which source the model happens to consult, with no way for the user to predict or notice which one it used. Notably, the contradiction is detectable from the inside (the Opus run detected it) but not resolvable from the inside — the model can't tell which of the two sources is lying.

Showing cached comments. Read the full discussion on GitHub ↗