mirror of
https://github.com/Comfy-Org/github-workflows.git
synced 2026-11-05 00:17:37 +00:00
[PR #404] [MERGED] feat(cursor-review): name the Anthropic lane's failure cause, gated and key-screened #404
Labels
No labels
cursor-review-catalog-drift
groom
groom
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Comfy-Org/github-workflows#404
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/Comfy-Org/github-workflows/pull/404
Author: @mattmillerai
Created: 10/10/2026
Status: ✅ Merged
Merged: 10/10/2026
Merged by: @mattmillerai
Base:
main← Head:matt/anthropic-lane-failure-cause📝 Commits (3)
16df226feat(cursor-review): name the Anthropic lane's failure cause, under three gatesba75547docs(cursor-review): a no-submit cell can still print error objects; census-only is the no-error-object case8457fe7fix(cursor-review): gate the Anthropic cause on the real CLI shape, and screen it for the API key📊 Changes
4 files changed (+259 additions, -22 deletions)
View changed files
📝
.github/cursor-review/README.md(+1 -1)📝
.github/cursor-review/agent-error.py(+89 -0)📝
.github/cursor-review/tests/test_agent_error.py(+144 -8)📝
docs/callers/cursor-review.md(+25 -13)📄 Description
Follow-up to #402. This commit missed that merge by two minutes — #402 merged at
02:40:07Zwith headb537a26, and this landed on the branch at02:42:02Z, so the squash (101466d) never picked it up.It is not a new idea: it is the half of the panel's finding that the maintainer explicitly chose, and the only reason it is a separate PR is the race.
What #402 shipped, and what it left
The panel found that Claude Code reports an API-level failure as:
subtypereads success on a failed call, and the cause sits only inresult— a field the model also writes. #402 took the safe half: printis_errorso the line cannot read as a success, and document the gap. Main therefore says, truthfully, that the Anthropic lane names no cause.The reviewer offered two ways to close it: extract a bounded, sanitized slice of
result, or limit the docs claim to the OpenAI lane. #402 did the second. This does the first.The gates
resultis printed only when all of these hold:{"type":"result"}object,is_errortrueapi_error_status, or a value opening withAPI Error: <3 ASCII digits>sk-ant-prefix and no 16-char slice of the step's ownANTHROPIC_API_KEYfindings.jsongets; a 120-char cut would slip past Actions' exact-value maskapi_error_statusandterminal_reason(CLI-written scalars) join the field allowlist. Output from a real failure of the pinned CLI (@anthropic-ai/claude-code@2.1.286, invalid key):That real message has no
API Error:preamble, so a preamble-only gate (this PR's first revision) would have missed it. The review panel caught that, and the captured object is now pinned as a fixture.Being straight about the trade
This is the one place a model-written field reaches the run log. A prompt-injected agent can forge the preamble, so it is a bounded, documented channel — roughly 120 sanitized characters that cannot open a
::workflow command::or a legacy##[command]and cannot carry the API key, but can carry other text — not a safe one.It was taken knowingly. The alternative, which main currently ships, is a lane that reports
subtype=successand names nothing: the cause appears nowhere else in the file, and the file is deliberately not uploaded (the Anthropic lane screensfindings.jsonfor a leaked API key before publishing it, and shipping the unscreened transcript would route the agent's prose past that guard).A failure with neither marker prints no cause rather than a guess. Widen the gate against a real message, never speculatively.
The module docstring, the README row and the caller page all asserted that no model-written field reaches the log. All three are corrected here rather than left to mislead — that overstatement is exactly what the panel caught the first time round.
Tests
Each gate is pinned separately, because a gate that quietly stopped holding would widen the channel without changing any other test. The pinned cases are review prose without a marker, a message with no status code,
is_errorfalse, a non-resulttype, a nested or list-wrapped result, Unicode digits, a booleanapi_error_status, a structuredresult, the length cap, the injection case, and the key screen (prefix, full key, offset slice, mid-key slice).One of those tests first passed for the wrong reason. With
is_errorfalse, the fixture no longer looked like an error at all, so the extractor was never reached and the gate went untested while appearing covered. It now carries an independent error signal and asserts that the object was recognised as an error.Provenance
Authored by: agent-work loop
Verified:
python3 -m unittest discover -s .github/cursor-review/tests -p 'test_*.py': 1416 pass; the cursor-approve suite passesagent-error.pyrun against a freshly captured invalid-keyclaude --output-format jsonfile prints the status, reason and cause shown abovecheck_workflow_pins.py,check_agents_md.py --root .andcheck-org-repo-literals.shpassDeviations:
API Error: <status> {...}was not adopted: a forged JSON body is as easy to write as forged prose, so it does not narrow the channel🤖 Generated with Claude Code
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.