Real claude-cli/2.1.220 auto-mode classifier requests carry two system
entries: the security-monitor prompt plus an appended session-context
block. The previous len(systemEntries) != 1 guard rejected them before
any content check ran, so claude_code_only groups kept refusing the
classifier (#5152, follow-up to #5041/#5048).
Scan every entry for the monitor prompt instead of requiring exactly
one. Discrimination is unchanged: the matching entry still needs the
10k-char minimum, the fixed prefix, and all eight markers.
Real claude-cli/2.1.220 samples insert <category>...</category> between
</block> and <reason>, breaking the previous literal marker.
Also fix an unchecked type assertion in the test suite.
Locks in that Claude Code detection keys on the billing block prefix +
cc_entrypoint=cli, not on the cch field that the new CLI (and now our own
mimicry) no longer sends:
- BillingBlockRecognizedWithoutCCH: an identity-prose-less sub-request whose
system block is `x-anthropic-billing-header: cc_version=...; cc_entrypoint=cli;`
(no cch) is still detected as Claude Code.
- NoCCHBlockStillRequiresClaudeCodeUA: dropping cch did not loosen detection —
a non-claude-cli UA is still rejected, so ClaudeCodeOnly groups can't be spoofed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Genuine Claude Code CLI sub-requests (e.g. the security monitor) carry
no identity system prompt, so claude_code_only groups wrongly rejected
them with "this group only allows Claude Code clients". Detect the
x-anthropic-billing-header block with cc_entrypoint=cli as a stable
client signal, while keeping the existing header/metadata checks.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>