Sub-agents requesting `model: "opus"` silently continue on claude-opus-4-8 after a cyber-content refusal — parent report still says "Opus"

Status Open
Reported on v2.1.282
Maintainer reply None cached
Activity 0 comments · opened Sep 27, 2026

Summary

I ran two sub-agents from an interactive Claude Code session with an explicit model: "opus" request, doing defensive security work on my own open-source repository. In both cases, after one or two stop_reason: "refusal" turns with category: "cyber", the sub-agent's remaining turns for the rest of its run were served by claude-opus-4-8 instead of claude-opus-5-5 — with no notice reaching the parent session. The parent's own report of the sub-agent's work still credited "Opus" throughout; I only found the switch by reading message.model line-by-line in the sub-agent's own transcript JSONL. This matches the documented "Automatic model fallback" behavior for Opus 5 (cybersecurity category → Opus 4.8), but I could not find documentation of how this propagates — or fails to propagate — to the parent of an in-process sub-agent.

Environment

  • Claude Code version: 2.1.282 (case 1), 2.1.283 (case 2)
  • Plan: Claude Max (personal)
  • OS: Linux (WSL2, kernel 6.18.33.2-microsoft-standard-WSL2)
  • Sub-agents were spawned in-process via the Agent/Task tool from an interactive parent session, each with an explicit model: "opus" in the spawn parameters. Both parent sessions ran on Opus (not Opus 4.8) throughout.
  • switchModelsOnFlag was left at its default (true); I did not have "Ask before switching" enabled during either run.

Case 1 — sandbox implementer

| Time (UTC) | Event | Model served |
|---|---|---|
| 2026-09-25T22:41:37Z | First assistant turn | claude-opus-5-5 |
| 2026-09-26T00:03:16Z | Assistant turn, stop_reason: "refusal", stop_details.category: "cyber" | claude-opus-5-5 |
| 2026-09-26T00:03:26Z | Second assistant turn, stop_reason: "refusal", stop_details.category: "cyber", fallback_has_prefill_claim: true | claude-opus-5-5 |
| 2026-09-26T00:04:49Z | Next assistant turn onward (321 remaining calls, no reversion) | claude-opus-4-8 |

341 calls ran on claude-opus-5-5 before the switch; 321 calls ran on claude-opus-4-8 after it, through the end of the sub-agent's run. No API error, no overload signal, and no compaction event appears between the two refusal turns and the switch.

Case 2 — read-only security reviewer

| Time (UTC) | Event | Model served |
|---|---|---|
| 2026-09-27T13:30:47Z | First assistant turn | claude-opus-5-5 |
| 2026-09-27T13:42:49Z | Assistant turn, stop_reason: "refusal", stop_details.category: "cyber" | claude-opus-5-5 |
| 2026-09-27T13:43:07Z | Next assistant turn (no refusal) | claude-opus-5-5 |
| 2026-09-27T13:43:12Z | Next assistant turn onward | claude-opus-4-8 |

158 calls ran on claude-opus-5-5; the last 9 calls of the run (the final synthesis of the review) ran on claude-opus-4-8.

What the work was

Both sub-agents were doing defensive hardening of my own open-source tool (github.com/home-dev-lab/workflow-toolbox), on my own repository and machine, for a change I intended to publish:

  • Case 1: implementing a bubblewrap (bwrap) sandbox around child model processes the tool launches, to contain what those processes can reach on the host.
  • Case 2: an independent, read-only adversarial review of a change that moves external-lane supervision records (pid, logs, decisions) out of a lane-writable directory into a host-only path, specifically to stop a sandboxed lane from forging records or escaping supervision — i.e., reviewing code whose entire purpose is to keep an untrusted process from touching host state and, transitively, credentials.

Mitigation already tried: every brief for this kind of sub-agent states the defensive purpose, the narrow scope (my own repository, my own machine, no third-party target), and what the change protects. Both runs still tripped the cyber classifier partway through and fell back.

Impact

The downgrade is silent at the point where it matters most: the parent session's own summary of the sub-agent's work reported "Opus" with no caveat — I only discovered the switch by opening the sub-agent's raw JSONL transcript and reading message.model per assistant line, something I would not normally do for a sub-agent whose report already claims success. For exactly the class of work where model capability matters most — security review and security-sensitive implementation — this means a project can end up shipping a defensive-security change whose second half was actually reviewed or written by a smaller/older model, with nothing in the normal reporting surface to flag it.

What I'm asking for

  1. Surface a mid-run fallback to the parent of an in-process sub-agent — a field on the tool result, or an entry in the transcript the parent can see — not only as a notice inside the sub-agent's own transcript.
  2. Document how switchModelsOnFlag: false behaves for an in-process sub-agent of an interactive session specifically. The published docs describe the top-level interactive-session prompt and the non-interactive/SDK case ("ends the turn with a refusal"), but not what a spawned sub-agent of an otherwise-interactive session does — pause, refuse, or something else. I have not turned this setting on yet because I couldn't find that behavior documented, and I did not want to risk a sub-agent silently frozen on a dialog it can't answer.
  3. A path for legitimate defensive security work to actually run on Opus 5.5 rather than a downgrade nobody can see. I understand Anthropic's Cyber Verification Program doesn't cover Opus 5.5 yet — is there a way to request coverage, or another accepted route, for exactly this kind of own-repository, own-machine defensive work?

Related

  • #87938
  • #84353

View original on GitHub ↗