Repository navigation
[Phase 2 blocker] Deep-tier reviews fail on v1-next: invalid claude-sonnet-5-0 ID (404), stale cached Claude Code CLI 2.1.138, and a rate-limit regex that hides every Claude error #1957
Copy link
Copy link
Closed
Labels
Description
Summary
The Opus 5.5 canary (#1899) found a regression: every pr-review that escalates to the deep tier fails on pr-review/v1-next (v1.17.0 and v1.18.0, since 2026-09-25 14:07Z). Low-risk PRs are unaffected because they stop at triage plus a Fable 5 check. Four defects combine to cause it. Three were latent under Opus 4.8, because 4.8 always answered first.
Evidence (identical in every failed run inspected, e.g. runs 36280169426 on #1906 and 36280307395 on #1794, debug artifact pr-review-debug-84020-1):
[tier2] deep review (claude-opus-5-5) + rubber duck (o4-mini via copilot)
::warning::[claude] model claude-opus-5-5 throttled (rc=1) — trying next in chain # ~1s, 0 tokens
{"is_error":true,"api_error_status":404,"result":"There's an issue with the selected model (claude-sonnet-5-0). It may not exist or you may not have access to it."}
::warning::[claude] model claude-sonnet-5-0 throttled (rc=1)
triage stderr: [copilot] ... flags=--deny-tool * → Invalid --deny-tool value. Error: Invalid rule format: *
##[error]Review failed ... (exit code 1)
Model ID audit (checked against the current Anthropic model catalog)
| Where | Current value | Valid? | Notes / recommendation |
|---|---|---|---|
Triage ENGINE_TRIAGE_MODEL, chain head, headroom probe |
claude-haiku-4-5-20251001 |
✅ | Full snapshot ID of Haiku 4.5 (alias claude-haiku-4-5). No newer Haiku exists, so no bump. |
Deep ENGINE_DEEP_MODEL, chain head |
claude-opus-5-5 |
✅ ID valid | Fails at runtime on CI, cause unconfirmed (see D2/D3). Thinking is always on; effort is the only control and defaults to medium, so the deep tier's --effort high pin is correct. thinking: disabled and budget_tokens return 400; forced tool_choice returns 400. |
Action ENGINE_ACTION_MODEL; 2nd hop in triage, deep and action chains; scripts/aw.sh model allowlist |
claude-sonnet-5-0 |
❌ invalid → 404 | The correct ID is claude-sonnet-5 (no -0). The action tier has probably been silently falling back to claude-opus-4-8 since #1100. |
Audit / single ENGINE_AUDIT_MODEL, ENGINE_SINGLE_MODEL |
claude-fable-5 |
✅ | Still served. Its successor, claude-fable-5-1, has the same price ($10/$50) and is stronger, but is not a drop-in: forced tool_choice returns 400 and thinking blocks are bound to the model. Optional bump; gate it on the audit held-out A/B (add it as an arm in #1901) rather than swapping blind. |
| Fallback hops (audit/action/single) | claude-opus-4-8, claude-opus-4-7 |
✅ | Valid. #1900 replaces the 4.8 hops with Opus 5.5, but only after Opus 5.5 passes liveness (AC-5 below). |
Duck DUCK_MODEL (claude duck engine) |
claude-sonnet-4-6 |
✅ | Previous-generation Sonnet. Optional bump to claude-sonnet-5 once the ID fix lands. Not required. |
persona-runner-reusable.yml |
--model claude-opus-5-5 --fallback-model opus --effort high |
✅ ID valid | Runs on the same stale CLI (D2), so likely affected too. opus is a CLI alias that resolves per CLI version. |
model-pricing.tsv |
glob claude-sonnet-5-* |
Does not match claude-sonnet-5. Fixing the ID without a matching price row would leave Sonnet 5 calls unpriced. |
Also available but unused: claude-opus-5 ($5/$25). No action proposed.
Defects
- D1: invalid model ID.
claude-sonnet-5-0returns HTTP 404 and appears inscripts/engine.sh(lines ~122, 147, 151, 153) andscripts/aw.sh:93. - D2: stale Claude Code CLI on CI. Runners log
claude-code cache hit: 2.1.138. TheCache claude-code CLIstep uses the fixed keyclaude-code-latest-Linux, andinstall_claudereturns early when aclaudebinary exists, soCLAUDE_CODE_VERSION: latestis never re-resolved. The current release is 2.1.283. 2.1.138 probably predates the Opus 5.5 launch (2026-09-22), so it may send a request shape Opus 5.5 rejects (e.g.thinkingdisabled orbudget_tokens, both 400 on Opus 5.5) or not know the model. This is the leading hypothesis for the Opus 5.5 failure, and is unconfirmed; the other candidates are no account access, or a genuine 429. - D3: the rate-limit classifier masks every Claude error.
_rate_limit_patterncontainsclaude.*usage|usage.*claude. Every--output-format jsonresult includes the model name and a"usage"object, so any Claude CLI error (400, 404, …) is classified as "throttled" and silently falls through. On top of that,_claude_chain_invokekeeps only the last hop's stdout, so Opus 5.5's actual error text is lost. - D4: Copilot fallback is broken. It passes
--deny-tool '*', which the currentgh copilotrejects (Invalid rule format: *). The duck logsClassic Personal Access Tokens (ghp_) are not supported by Copilot, and the Gemini fallback is out of credits (prepayment credits depleted; [Phase 2] Swap the deep tier to claude-opus-5-5 in engine.sh (model, chain, label, effort) #1898's run also hitgemini-2.5-pro is no longer available to new users). With D1–D3, a deep review has no working fallback.
Acceptance Criteria
- ID fix (D1): every live
claude-sonnet-5-0inscripts/engine.shandscripts/aw.shbecomesclaude-sonnet-5, with the affected bats tests updated. Historical docs and fixtures stay unchanged.model-pricing.tsvgets an appended row (append-only convention) with a glob matchingclaude-sonnet-5at the same effective-dated rates as the existingclaude-sonnet-5-*rows, andprice_for claude-sonnet-5 <date>is covered by a test. - Current CLI on CI (D2): the workflows that install Claude Code (
pr-review.yml,dev-lead-reusable.yml,persona-runner-reusable.yml,ci-failure-analyst-reusable.yml, and any other workflow using theclaude-code-latest-*cache) resolve a current version. Either key the cache on the resolved version, or pinCLAUDE_CODE_VERSIONto a reviewed version that supports Opus 5.5 and bump it deliberately. Each run logsclaude --version. - Honest error classification (D3): a JSON result with
is_error: trueand anapi_error_statusother than 429/529 is not treated as a rate limit. 404 is labelled "model unavailable" and 400 "invalid request". The next hop may still be tried, but the log says why, and each hop's stdout and stderr are kept in the cascade log. Removeclaude.*usage|usage.*claude, or scope it so it can't match a JSON envelope. Bats covers a 404 envelope, a 400 envelope and a real 429. - Deep-tier safety net:
CLAUDE_DEEP_MODEL_CHAINgets a known-good hop (claude-opus-5-5,claude-opus-4-8, thenclaude-sonnet-5once AC-1 lands), so an Opus 5.5 failure degrades to Opus 4.8 instead of failing the review. Token records already carry the model actually used, so the canary report ([Phase 2] Canary go/no-go report: compare deep-tier cost, cache-read cost and latency by model from token-usage artifacts #1951) counts only real Opus 5.5 calls. - Liveness (the epic's untracked prerequisite): after AC-1 to AC-3 reach
v1-next, run the [Phase 2] Add a workflow_dispatch runner for model-ab.sh plus a liveness/effort probe, so the Opus 5.5 non-regression A/B actually executes #1950 probe (or an equivalent one-shotclaude --print --model <id> --output-format json) with the CI credential for every ID in the chains:claude-haiku-4-5-20251001,claude-sonnet-5,claude-opus-5-5,claude-fable-5,claude-opus-4-8andclaude-opus-4-7. Record the result on [Phase 2] Canary the deep-tier swap through the v1-next ring and monitor before stable promotion #1899, including Opus 5.5's real error if it still fails. - Copilot fallback (D4): replace
--deny-tool '*'with a rule syntax currentgh copilotaccepts. Record whether the duck's classic PAT must become a fine-grained token (a secrets change for a maintainer). If this is too large, split it into its own issue linked here; AC-1 to AC-5 must not wait on it. shellcheck --severity=warning -xis clean, the touched bats suites pass, and the PR states that anextchannel cut is required (autocut will do it) before the canary resumes.
Out of scope / decisions for the maintainer
- Fable 5 → Fable 5.1 for the audit and single tiers: evaluate through the [Phase 3] Deprecate Fable 5: move the audit and single tiers to Opus 5.5 and remove Fable from every default chain #1901 A/B (add a
claude-fable-5-1arm), not in this fix. - Sonnet 4.6 → Sonnet 5 for the duck: optional, after AC-1.
- Immediate mitigation while this lands: a maintainer may roll
pr-review/v1-nextback topr-review/v1.16.0(scripts/cut-release.sh pr-review 1.16.0 --promote --channel next --push) to restore Opus 4.8 deep reviews. No ring beyondnextcarries the swap yet.
Blocks #1899 (canary metrics can't be measured while every Opus 5.5 deep call fails) and therefore #1900. Epic #1895.
Reactions are currently unavailable
Activity
don-petry commentedon Sep 27, 2026
Decision: fix forward. No rollback of
pr-review/v1-next. I've implemented this issue in #1958, so dev-lead doesn't need to pick it up.claude-sonnet-5inengine.shandaw.sh;claude-sonnet-5pricing rows plus testslatestresolved to the concrete npm version before the cache step (8 workflows); pr-review and dev-lead logclaude --versionclaude.*usageremoved; failed hops classified byapi_error_status; per-hop output kept incascade/claude-chain-hops.log(debug artifact); bats for 404, 400, 5xx and a real 429claude-opus-5-5,claude-opus-4-8,claude-sonnet-5next(needs the #1950 probe, PR #1952)--deny-tool '*'replaced with--deny-tool shell --deny-tool write. Maintainer action still needed: the duck's classic PAT (ghp_) must become a fine-grained token, and Gemini is out of prepaid creditsAfter merge, Release Manager autocut cuts a release to
nextwithin about 4h, and the canary on #1899 resumes from there.Generated by Claude Code
fix(engine): unblock Opus 5.5 deep tier — valid Sonnet 5 id, fresh CL…