fix(review): print the provider failure beneath "request failed"; classify it in the review workflow - #6384
Conversation
`codewhale review` reported a failed model request as the outermost anyhow
context only — "Responses API request failed" — because `{error}` prints
one layer of the chain. The `LlmError` underneath, which names the class
(quota, auth, rate limit, upstream 5xx, network, timeout) and carries the
sanitized provider body, never reached the log or the CI classifier. Every
Codewhale review run since 752bae3 on 2026-09-21 failed with that bare
line, while the last runs that completed a request (2026-09-19 04:00 and
04:38 UTC) ran the same client, transport and workflow, so the cause is
provider-side or network and the message hid which.
Render the chain with the alternate format, as the sub-agent failure
receipt already does for the same masking (#3884). The review workflow's
non-run classifier only knew the legacy `LLM error: HTTP <status>` form;
it now also matches the `LlmError` display prefixes, so a funding, key,
rate-limit, upstream or network failure posts the advisory non-run note
instead of failing the job, while a 400 or an exhausted output budget
still fails it as a real review failure.
Validation (rustc 1.98.1): cargo check -p codewhale-tui --lib --locked:
0 warnings, exit 0 (2m34s); cargo fmt --all -- --check: clean; the classifier was
exercised in bash against the current masked line (still fails the job),
the chained quota/5xx/402/network lines (non-run note) and an invalid
request or budget-exhausted line (still fails the job); the workflow YAML
parses. The chain itself is only observable on a live provider failure, so
the next Codewhale review run on main is the product evidence.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134iUMxmGuXiG1LzPgfZVnv
|
Version drift is red on This PR changes Generated by Claude Code |
|
Claude finished @Hmbown's task in 1m 24s —— View job Review: PR #6384
SummarySmall, well-scoped fix. No correctness bugs, no provider/route-safety issues, nothing to flag on security.
Minor, non-blocking observations:
No blocking issues found. |
The previous commit walked the error chain in the agent-callable
`ReviewTool`, but `codewhale review`, the path the review workflow runs,
dispatches to `run_review` in the crate root, which formats its own
request failure with `{error}` and so still printed the bare outer
context (review finding by Devin on this PR).
Both paths now build the line through one helper beside the usage
accumulator they already share, and a regression test pins that a
wrapped `LlmError` keeps its class and body beneath "Responses API
request failed".
Validation (rustc 1.98.1, tui lib test build --all-features --locked,
hermetic test HOME, default 2 MiB test stack):
request_failure_message_keeps_the_provider_failure_beneath_the_context
-> test result: ok. 1 passed; 0 failed
tools::review::tests:: -> test result: ok. 35 passed; 0 failed
cargo fmt --all -- --check: clean. The proof run with the helper
neutralized to `{error}` and the non-test cargo check are reported in
the PR.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134iUMxmGuXiG1LzPgfZVnv
|
Claude finished @Hmbown's task in 1m 27s —— View job Review: PR #6384
SummaryThe second commit ( Devin's finding is resolved. Verified the new test against Workflow classifier still correct. Re-checked the extended No new provider/route-safety issue. This change only touches how an already-classified Security. The alternate One thing I couldn't verify myself: I don't have permission to run No blocking issues found. |
The widened classifier searched the whole CLI output for a class prefix, so provider body text deeper in the chain could impersonate one: an `Invalid request (400)` whose body mentioned "Network error" would have posted the advisory non-run note and exited 0 instead of failing the job (review finding by Devin on this PR). Match the class only where the CLI puts it: right after "Review pass N/M request failed:" and the client's one optional "<wire> API request failed:" layer. Body text after the class cannot reach that position, and a chain with any other shape stays a real failure. Validation: the pattern exercised in bash against ten sample lines — the masked line, three impersonation lines (400 and model-error bodies mentioning a class), the budget and partial-review lines all still fail the job; the chained quota, 5xx, 402 and network lines, with and without the wire layer, classify as non-run. The workflow YAML parses. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0134iUMxmGuXiG1LzPgfZVnv
Codewhale review did not run
|
Review: PR #6384
|
actionlint's shellcheck pass rejected `"$NONRUN[^\"]..."` as an array
expansion (SC1087). `${NONRUN}` says what is meant; the pattern and the
reason it extracts are unchanged.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0134iUMxmGuXiG1LzPgfZVnv
|
Claude finished @Hmbown's task in 3m 43s —— View job Review: PR #6384
SummaryRe-reviewed the head at Anchoring fix ( Shared-helper fix ( Compile-correctness of the new test (
Provider/route safety: no concern — this only changes how an already-constructed Security: no new exposure — the alternate Tests: the one new Rust test is a real regression test for the masking bug (PR shows it failing when the helper is neutralized to Nothing further to flag; this looks ready pending the outstanding CI runs (Workflow lint, Lint, Test ubuntu/macos/windows) noted in the PR's own checklist. |

Summary
The Codewhale review bot has failed on every non-draft run since
752bae3(2026-09-21 00:01 UTC, workflow runs 729 through 750) with one bare line:The last runs that completed their DeepSeek request were 710 (2026-09-19 04:00 UTC, tree
919d602, review posted) and 713 (04:38 UTC, tree041e628, request completed with 47k input tokens, then failed on the output budget). Between041e628and752bae3the request path is byte-identical:crates/tui/src/client/(Responses handler, stream entry, prepared request) is unchanged,client.rschanged only for StepFun,Cargo.lockchanged only workspace version numbers, andcodewhale-review.ymlis the same file. So the failure was provider-side, and the message hid which class.Real cause, confirmed by this PR's own review run on
bcbf690:LLM error: HTTP 402: Insufficient Balance. The DeepSeek review key is out of funds. That is a maintainer action (fund or rotate the key), not a code defect; this PR makes the failure say so and keeps it advisory.Why the line was bare. The client wraps the retry loop's
LlmErrorin.context("Responses API request failed"), and both review paths formatted the failure with{error}, which prints only the outermost anyhow layer. TheLlmErrorunderneath names the class (quota, auth, rate limit, upstream 5xx, network, timeout) and carries the sanitized provider body. The sub-agent failure receipt already renders the chain with the alternate format for exactly this masking (#3884).Four commits.
4598534rendered the chain in the agent-callableReviewTooland widened the workflow classifier.bcbf690(Devin finding):codewhale review, the path the workflow runs, dispatches torun_reviewin the crate root, which formats its own request failure and was still masked. Both paths now build the line through onerequest_failure_messagehelper beside theadd_review_usagethey already share, and a regression test pins that a wrappedLlmErrorkeeps its class and body beneath the outer context.32b9256(Devin finding): the classifier searched the whole output, so provider body text deeper in the chain could impersonate a class. The class is now anchored to its position: right afterReview pass N/M request failed:and the client's one optional<wire> API request failed:layer.35e0b84: braces the pattern expansion for shellcheck (SC1087); no behaviour change.Why the job failed instead of posting the non-run note. The workflow's classifier only matched the legacy
LLM error: HTTP <status>form, whichLlmError'sDisplayproduces only for statuses without a class of their own (402 without quota wording, 408). It now also matches the class prefixes (Provider plan quota exhausted,Authentication failed,Authorization failed,Rate limit exceeded,Server error (NNN),Network error,Request timed out) at the anchored position, so a funding, key, rate-limit, upstream or network failure posts the advisory non-run note and exits 0, while anInvalid request (400)or an exhausted output budget still fails the job as a real review failure. Onbcbf690and again on35e0b84the run posted exactly that note and the check went green.No-Issue: review-bot outage diagnosis before the v0.10.0 tag; a shared one-line formatter, its test, and the workflow classifier.
Testing
rustc 1.98.1, tui lib test build with
--all-features --locked, hermetic test HOME, default 2 MiB test stack:Regression test shown failing without the fix (rebuilt with the helper neutralized to
{error}; call sites and test kept):cargo fmt --all -- --check: clean.Non-test
cargo check -p codewhale-tui --lib --locked: 0 warnings, exit 0.Classifier exercised in bash against ten sample lines: the masked line, three impersonation lines (400 and model-error bodies mentioning a class), the budget-exhausted and partial-review lines all still fail the job; the chained quota, 5xx, 402 and network lines, with and without the wire layer, classify as non-run.
The workflow YAML parses; Workflow lint (actionlint + shellcheck) passes on
35e0b84.Live: the Codewhale review run on
bcbf690printedLLM error: HTTP 402: Insufficient Balance, posted the non-run note, and exited 0; the anchored classifier on35e0b84updated the note with the anchored reason and exited 0.Version drift went red once on
4598534in the release test script's temp-dir cleanup (rm: cannot remove ... Directory not empty), outside this PR's files; it passed on the single re-run. The script fix is queued separately.cargo fmt --all -- --checkNon-test
cargo check -p codewhale-tui --lib --lockedTargeted tests and the proof without the fix (above)
Codewhale review run shows the underlying provider failure (402 on
bcbf690)Workflow lint, Lint, Test ubuntu / macos / windows — all 30 checks green on
35e0b84Checklist
🤖 Generated with Claude Code
https://claude.ai/code/session_0134iUMxmGuXiG1LzPgfZVnv