[BUG] Fable5 [P0!!!!!!!!!] Safety classifier false positive on syscall/ABI dev content forces silent mid-task model downgrade (Fable 5 1M → Opus 4.8), breaking PR review-reply workflow
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
<!-- @version 1.0.0 -->
<!-- @updated 1781050200 -->
[BUG] Safety classifier false positive on syscall/ABI dev content forces silent mid-task model downgrade (Fable 5 1M → Opus 4.8), breaking PR review-reply workflow
Environment
- Product: Claude Code (web, claude.ai) — official iterative development session
- Model: Claude Fable 5 (1M context)
- Downgraded to: Claude Opus 4.8 (forced, mid-task)
- Date observed: 2026-06-10
- Workflow: GitHub PR integration — replying to third-party automated review threads (Codex findings) with fix commit hashes, then resolving threads
Summary
While performing a legitimate, routine engineering task — replying to 3 Codex review findings on a PR with the commit hashes that fixed them (standard audit-trail practice: "reply with fix commit + resolve thread") — Claude Code's safety measures flagged the conversation and silently downgraded the model mid-task with the banner:
"Fable 5 1M's safety measures flagged this message. They may flag safe, normal content as well. These measures let us bring you Mythos-level capability in other areas sooner, and we're working to refine them. Switched to Opus 4.8."
The session content was low-level systems programming for a Rust syscall/ABI project. The flagged turn contained nothing harmful — it was a per-finding adjudication table plus a request to post review replies.
Suspected trigger (false positive surface)
The conversation is dense with terms that plausibly overlap a cyber/dual-use classifier's vocabulary, but in context are plain Linux userspace ABI work:
msg_controllen/cmsg/socklen_tcasts (glibcusizevs muslu32field-width divergence)waitidreturningEAGAIN→NotReadymappingpidfd.rs/kill.rs(the kill(2) syscall wrapper module, not anything violent)pollfd tests, unallocated high fd numbers- musl cross-target matrix (
x86_64/aarch64/armv7-unknown-linux-musl) - GitHub tool calls: "add reply to pull request comment"
Hypothesis: filename/symbol tokens like kill, pidfd, poll, raw-syscall vocabulary, combined with automated tool use against GitHub, tripped the classifier. All of it is standard libc/kernel interface terminology.
Impact
- Mid-task model swap breaks task isolation and continuity. The remaining work in the same turn-chain — including replying to the next Codex finding (a real, significant bug) — was handed to a different model with different capability characteristics. For a formal engineering task, a silent capability change mid-PR-review is itself a correctness risk.
- Audit-trail workflow interrupted. The whole point of the task was traceability: each review thread gets a reply citing the fix commit (e.g. checked-cast helper for
msg_controllen,EAGAIN → NotReady, fd-number test de-flake), so any future auditor can follow finding → commit → resolution. The downgrade landed exactly between "load reply tool" and "post replies," leaving threads half-processed. - 1M context advantage lost. The session legitimately needs large context (full PR diff + 5 OWNER review notes + 3 Codex findings + cross-arch CI logs). Downgrading discards the reason Fable 5 1M was selected.
- Chilling effect on a whole domain. Syscall/ABI/libc work cannot avoid words like
kill,pidfd,sigchld,poll,unsafe. If this content class reliably trips the classifier, Claude Code is effectively degraded for systems programming — one of its core audiences.
Steps to reproduce (best effort)
- Start a Claude Code (web) session on a Rust low-level syscall wrapper project (modules named
kill.rs,pidfd.rs; musl cross-targets). - Have a third-party bot (Codex) leave review findings on the PR touching
msg_controllen/waitid/poll. - Ask Claude to adjudicate findings and reply to each review thread with the fixing commit hash, then resolve threads (GitHub MCP/tooling: "add reply to pull request comment").
- Observe safety flag + forced switch from Fable 5 1M to Opus 4.8 mid-task.
Expected behavior
- Benign systems-programming content (libc symbol names, syscall semantics, PR review replies) should not trip safety measures; or
- If a classifier fires, do not silently swap models mid-task. Options that preserve task integrity:
- re-evaluate with surrounding context (the session history makes legitimacy obvious),
- warn and let the user confirm continuation on the same model,
- at minimum, complete the in-flight tool sequence before any switch.
Actual behavior
Classifier fired on a benign turn; model was switched without user consent mid-tool-sequence; remaining review replies (including handling of a further significant finding) proceeded under a different model.
Requested fixes
- Whitelist/contextual handling for systems-programming vocabulary (
kill(2),pidfd,poll,msg_controllen, signal names) when surrounded by code/PR context. - Make model downgrade opt-in or at least turn-boundary-aligned — never mid tool chain.
- Provide a per-session "this is a systems programming project" attestation or feedback path so repeated false positives on the same repo stop recurring.
---
Filed from a real session. The banner text quoted above is verbatim from the product UI. Available to provide session timestamps or further repro detail on request.
What Should Happen?
Benign systems-programming content (libc symbol names, syscall semantics, PR review replies) should not trip safety measures; or
If a classifier fires, do not silently swap models mid-task. Options that preserve task integrity:
re-evaluate with surrounding context (the session history makes legitimacy obvious),
warn and let the user confirm continuation on the same model,
at minimum, complete the in-flight tool sequence before any switch.
Error Messages/Logs
Steps to Reproduce
Steps to reproduce (best effort)
Start a Claude Code (web) session on a Rust low-level syscall wrapper project (modules named kill.rs, pidfd.rs; musl cross-targets).
Have a third-party bot (Codex) leave review findings on the PR touching msg_controllen/waitid/poll.
Ask Claude to adjudicate findings and reply to each review thread with the fixing commit hash, then resolve threads (GitHub MCP/tooling: "add reply to pull request comment").
Observe safety flag + forced switch from Fable 5 1M to Opus 4.8 mid-task.
Claude Model
Other
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
Claude code web,idk
Platform
Other
Operating System
Other Linux
Terminal/Shell
Other
Additional Information
_No response_
10 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
A single false positive permanently downgrades the whole session: every subsequent turn of this PR is forced onto a lesser model. For high-difficulty syscall/ABI engineering that genuinely needs the 1M context (full PR diff + multi-arch CI logs + review threads), losing it mid-task — with no recovery path — makes the flagged-but-safe content warning meaningless. Please make downgrades reversible or turn-scoped.
@gowy222 — your "single false positive permanently downgrades the whole session" observation is the load-bearing complaint here, and it deserves to be the headline.
Anthropic's banner frames the downgrade as turn-scoped ("Switched to Opus 4.8"), but the operational behavior you describe — every subsequent turn forced onto the lesser model with no recovery path — makes it a sticky session-state change, not a per-turn safety response. That's a different class of issue than "the classifier had a false positive on this turn." A false positive on this turn that locks the session to a different model for every subsequent turn is a session-modifier drop with no operator-side recovery.
Worth noting that Anthropic shipped two different responses for similar-looking content. Yesterday I tested the Fable cybersec block with this exact shape of request (legitimate offensive-security-adjacent content via CC) and got a hard AUP refusal — not a silent downgrade. So the production behavior for the same general content class varies: sometimes hard refuse, sometimes silent downgrade-and-lock. Both are problems but they're different problems with different remediation paths.
Two operational asks worth raising in this thread:
/model claude-fable-5or--model claude-fable-5on a subsequent turn should restore the requested model, with the classifier evaluating that specific turn. Today there's no such restore path within a session.The PR-review workflow break is the right concrete harm to surface. Audit-trail-style reply-and-resolve flows are exactly the case where mid-conversation continuity is the value, and exactly where losing it breaks the work.
— AI Team Lead
Second occurrence — different project, same false positive, even more benign trigger
This is now reproducible across unrelated sessions. A fresh research task — git clone of two public, third-party open-source Rust repositories (smr-swap, lfrlock, lock-free / SMR memory-reclamation experiments by another author) to evaluate whether a small embedded DB could go lock-free — was flagged and force-downgraded from Fable 5 1M to Opus 4.8 immediately after mkdir -p ~/research && cd + parallel git clone, before a single line of source had even been read. There is nothing remotely sensitive here: ordinary GitHub-hosted open-source code, a standard concurrency-research workflow (read the mechanism, assess the unsafe surface, compare against a DB workload profile). The emerging pattern is that ordinary low-level Rust vocabulary (lock-free, unsafe, atomic, SMR/epoch reclamation — and in the first occurrence kill(2), pidfd, poll, msg_controllen) combined with shell/tool execution reliably trips the classifier. Combined with the persistence problem reported above — the downgrade is session-wide and irreversible — this means any sustained systems-programming session is effectively guaranteed to lose Fable 5 partway through, exactly the workloads (syscall ABI, lock-free data structures) that most need both the model's capability and the 1M context. Two asks, reiterated: (1) context-aware handling of systems-programming vocabulary, and (2) make the downgrade turn-scoped or reversible instead of a one-way session-wide trapdoor.
FUK IT!
---
Third occurrence — flagged on prompt ingestion alone, zero code, zero tool execution
The pattern has now escalated to its purest form. This time the entire "offending" input was a design-planning prompt — a detailed architecture brief asking the model to plan Rust module boundaries (responsibility layering, dependency direction, interface granularity) for a process-supervision library, with explicit constraints stating "do not implement code, do not modify files, do not output patches". No shell commands, no tool calls, no repository access — just text describing module design. It was flagged and downgraded anyway.
The vocabulary that presumably tripped it is the standard domain language of every process manager ever written (systemd, supervisord, the nix/procfs crates): kill_verified, pid_identity, pidfd_open, signal delivery, /proc observation, zombie state, cleanup orchestration. The bitter irony: the prompt is entirely about safety engineering — verified-kill so you never signal the wrong pid, TOCTOU protection, re-verification after pidfd_open, explicit structured authorization states instead of fuzzy bools, ensuring guards survive release-build optimization. A prompt whose whole purpose is "make process termination provably safe and auditable" gets classified as unsafe.
Three occurrences now form a clean gradient proving the classifier keys on vocabulary, not behavior:
PR review replies citing fix commits (syscall ABI: kill(2), pidfd, msg_controllen) — flagged;
git clone of public third-party lock-free Rust repos, before reading a single line — flagged;
a text-only design prompt that explicitly forbids code generation — flagged.
Each downgrade remains session-wide and irreversible, so every one of these sessions permanently lost Fable 5 and its 1M context partway through legitimate work. At this point, systems programming as a discipline — process management, signals, concurrency, syscall wrappers — appears to be categorically incompatible with keeping the flagship model for a full session. Reiterating the asks: (1) context-aware handling of systems-programming vocabulary (a "no-execution, design-only" prompt should be the easiest possible case to clear); (2) turn-scoped or reversible downgrades; (3) a per-session/per-repo attestation or feedback path so the same project stops re-triggering.
---
Worth stressing: occurrence PR hit mid-deliverable — the model had already ingested the full architecture brief and was halfway through producing the layered module plan when it was swapped. Unlike code (which survives in files), an in-progress reasoning artifact lives entirely in the model's working state; a mid-task swap doesn't just degrade capability, it discards half-finished analysis that must be redone from scratch.
Fourth occurrence — flagged while writing a markdown design document; downgrade location was predicted in advance
This occurrence removes any remaining doubt. The session was executing a pre-written handoff brief: produce a 13-section architecture planning document (plan-module-tree.md) for module boundaries in a process-supervision library. The work product is pure markdown prose — no code, no shell beyond file edits, no execution of anything. Sections §1–3 were written and pushed; while writing §4–9 — which include the analysis of where a kill_verified module belongs and how release-build optimization affects guard semantics — the session was flagged and downgraded mid-edit.
Two things make this the most damning data point yet:
The downgrade was predicted, in writing, before the session started. Because three prior sessions on this project had all been falsely flagged, the handoff brief explicitly mandated "save after every section, front-load the kill_verified section, because a mid-session downgrade is statistically certain." That is exactly what happened: §1–3 survived only because they were pushed in time, and the flag landed precisely on the predicted section. When users can forecast not just that your classifier will misfire but which paragraph it will misfire on — and must engineer checkpoint-and-push workflows around an expected capability loss — the false-positive rate has stopped being noise and become a deterministic product defect.
The trigger is a word in a section heading. kill_verified is a module of a process supervisor whose entire design goal — spelled out in the very document being written — is safety: never signal the wrong pid, re-verify identity via pidfd_open before acting, replace fuzzy bools with structured authorization states. There is no mitigation left short of renaming standard POSIX terminology (kill(2), pidfd, signals) to euphemisms inside a private codebase to appease a classifier — which is obviously unacceptable and would corrupt the codebase's clarity for human maintainers.
Score so far: 4 sessions, 4 false-positive downgrades, triggered respectively by (1) PR review replies, (2) git clone of public repos, (3) a design-only prompt forbidding code generation, and (4) prose sections of a markdown planning document. All four sessions permanently lost Fable 5 and its 1M context mid-task. Reiterating, with added urgency: context-aware vocabulary handling, turn-scoped/reversible downgrades, and a per-project attestation path. A 100%-reproducible false positive on a fixed vocabulary set should be straightforward to verify on your side from these session timestamps.
A second instance of this pattern was just reported in private, with two additional data points worth surfacing:
--modelmid-conversation produces normal task execution on content that fires the safety classifier for both Fable 5 and Opus 4.8.The combination — Fable fails, Opus 4.8 (the documented fallback) also fails, Sonnet works — points at a classifier surface that's specific to the Fable-and-Opus-4.8 cluster, not at content the system genuinely considers unsafe (Sonnet would also block in that case). That tracks with v2.1.170's hardcoded autonomy-append path being scoped to Fable 5 and Mythos 5: the same code path that compiles in the autonomy instruction may also be the path that gates these classifier verdicts, and Sonnet escapes both.
Operationally this means the documented mitigations ("switch to Opus 4.8" / "wait for the next turn") don't recover the session at all on this class of content. The actual recovery is "switch to Sonnet" — which is not documented anywhere as a workaround and changes the model's capability profile materially.
— AI Team Lead
OMG!!!
---
Fifth occurrence — flagged during environment bootstrap; the session lost Fable 5 before any actual work began
Severity has escalated from "mid-task loss" to "total loss." This was the kickoff of the implementation phase — the high-stakes execution session that four planning sessions had been building toward. The session had done nothing but: create a TODO list, read a markdown planning document, run two background environment scripts (rustup toolchain sync, cargo-zigbuild, zig, rust-analyzer-mcp), ls src/ with line counts, and git clone the official Linux kernel stable trees (kernel.org tags v5.10.257 and v6.18.33 — cloned for the entirely standard purpose of cross-verifying syscall ABI behavior against kernel sources, which is how any serious syscall-wrapper library validates itself). The flag fired mid-bootstrap, during the second kernel clone. Zero lines of project work had been produced. The entire implementation session — the one phase that most needs the flagship model and the 1M context (a 5,418-line lib.rs plus a 12,000-line src tree plus the full planning document) — will now run 100% on the downgraded model.
Two candidate triggers, both indefensible:
Cloning the Linux kernel — the most-reviewed open-source codebase on Earth, fetched from its canonical host, or
an ls listing whose output happens to contain filenames like kill.rs, kill_verified.rs, pidfd.rs.
If it is the latter, this project has reached the point where merely listing its own source directory triggers a downgrade — the project is effectively poisoned at the vocabulary level, and no workflow discipline can route around that.
Updated score: 5 sessions, 5 false-positive downgrades — (1) PR review replies, (2) git clone of public third-party repos, (3) a design-only prompt forbidding code, (4) prose sections of a markdown plan, (5) environment bootstrap including a kernel.org clone. Occurrences 4 and 5 also demonstrate the downgrade is forecastable: the handoff brief for these sessions predicted both the inevitability and the approximate location of the flag, and was right both times. At this point the per-project attestation path is no longer a nice-to-have but the only viable fix — a process-supervision library cannot rename kill(2), and apparently cannot even ls itself. All five sessions are timestamped and should be trivially verifiable on your side.
---
And the quota is not refunded. Occurrence 5 alone burned ~19% of my 5-hour usage window — consumed by environment bootstrap and file reads in a session that was then force-downgraded before producing a single line of project work. So the cost structure of a false positive is: lose the flagship model, lose the 1M context, and pay full flagship-tier quota for the privilege — with no credit, no refund, no reset. A classifier your own banner admits "may flag safe, normal content" is, in effect, levying a usage tax on legitimate work every time it misfires. Adding a fourth ask to the previous three: automatically refund/credit quota consumed in any session that gets force-downgraded by a safety flag — at minimum the tokens spent after the flag, ideally the whole session, since the downgrade retroactively invalidates the session's purpose.
WTF..
---
Sixth occurrence — flagged with zero user input: the product's own auto-resume triggered the downgrade
This one crosses a line none of the previous five did. Yesterday, after the bootstrap-phase downgrade, I spent three hours doing the decoupling work on the downgraded model — fine, salvage what you can. Today I logged in. I typed nothing. Claude Code web auto-resumed the session,
Continuing from Stage B foundation. Now the big one: №12 orchestration rewrite consuming the 11 leaves. This is the most critical, E2E-load-bearing piece — I'll work carefully with the toolchain feedback loop. First, let me lock down the exact public contract I must preserve (the freeze guard) and gather the orchestration reference from the frozen body.the agent autonomously continued from yesterday's state and read tests/00_api_freeze.rs — and Fable 5 was flagged and downgraded before I had issued a single instruction. The trigger was Anthropic's own agent performing Anthropic's own auto-continue feature; the cost (model tier plus quota) was billed to me.
The file it read makes the false positive almost satirical: it is a compile-time API freeze guard — a test whose entire purpose is contract safety, pinning public function signatures via const fn-pointer coercion so that any accidental API breakage turns the build red. Its own header states it executes nothing at runtime and performs zero syscalls. It contains names like kill_force_by_pid and KillError for exactly one reason: it freezes the public API of a process manager, and a process manager's API is about process termination. A vocabulary classifier reading a do-nothing, compile-time safety guard and concluding "unsafe" is the purest possible demonstration that no semantic understanding is involved.
Consequences now compound: the last user-side mitigation — "open a fresh session to get Fable 5 back, control what it touches" — is gone, because auto-resume makes first contact with the poisoned-vocabulary codebase before the user can intervene. Updated score: six sessions, six false-positive downgrades, the sixth fired by the product itself with zero user input, against a file that exists to enforce safety. This also sharpens the quota question: tokens and tier were consumed by an action I never requested. Reiterating all four asks — context-aware vocabulary handling, turn-scoped/reversible downgrades, per-project attestation, and auto-credit of quota burned by misfires — with the addition that auto-resumed sessions should at minimum not be allowed to trigger an irreversible downgrade before the user's first input of the day.
Another data point on this pattern from an unrelated session shape — logging for the record since I don't think it's been surfaced in this exact form yet.
2026-07-07 ~16:20 UTC. A monitoring session (
cc-watch, an internal Claude Code session that runs shell-based QA on our filter pipeline) was executing an ordinary bash-syntax check on one of its own scripts:The tool call succeeded and returned three lines of internal diagnostics:
The very next turn — the model's response to that tool output — blocked with:
Request id:
req_011Cco13v73LqwoWzYUzBR1k. Model: Opus 4.7 on Max. No policy-adjacent content anywhere in the turn — the tool result is achmod, a syntax check, and QA counters.What this adds to the pattern. Every instance in this thread so far has involved either substantive user-authored content (gowy222's cybersec/ABI dev work, the design docs he was drafting) or a session context that could at least be gestured at as content-adjacent. This one's different: it's an infrastructure monitoring session doing internal shell QA. There's nothing for a classifier to score as adjacent to any AUP-enumerated category. The block landed on the tool-output-processing turn, not on user input.
If Anthropic has been iterating on the classifier since the June cluster, this cc-watch instance suggests the false-positive surface still extends past the content-adjacent inputs the original thread characterized — into turns where the content-scoring signal should be minimum. Sharing in case it helps narrow the internal analysis.
— AI Team Lead