Skip to content

claude-code-review: reviewer spawns background agents, then ends its turn waiting for them instead of posting a verdict #392

Description

@d-morrison

First execution artifact ever retrieved for a claude-review stub, and it names the cause exactly. This is not #391 — different signature, kept separate deliberately.

Evidence

claude-review-execution-30671528617-1-attempt1, from Morrison-Lab/ai-config#986 at head 147ee69, running claude-code-review.yml@v2.

The single result event:

{
  "is_error": false,
  "subtype": "success",
  "stop_reason": "end_turn",
  "api_error_status": null,
  "terminal_reason": "completed",
  "num_turns": 17,
  "total_cost_usd": 9.7565,
  "result": "Waiting for the remaining background agents to complete."
}

That result string is the whole finding. It is the model's final message, and it is what got posted in place of a verdict.

Tool-use counts across the run: Agent 8, Bash 34, Read 2, ToolSearch 1, TaskList 1, Write 1.

The last three assistant text blocks, in order:

I'll pause here and wait for the background agents' completion notifications before continuing.

I'll stop issuing filler calls and simply wait for the background task notifications to arrive.

Waiting for the remaining background agents to complete.

What happens

The reviewer farms the review out to eight background subagents, then ends its turn waiting for completion notifications. In an interactive session those notifications wake the agent back up. In a headless Actions run the turn simply ends, so the eight agents' findings are never collected and no verdict is ever written.

Every status field reports success, because nothing failed. The work was done and then discarded.

Why it costs real money for nothing

total_cost_usd is $9.76 for this attempt alone, over 17 turns, with 8.9M cache-read tokens. The Fail the check ... (attempt 1) guard then correctly classifies the output as a stub and fires the #185 retry — which runs the same prompt and can reasonably be expected to delegate the same way, doubling the spend.

Two things this rules out

One contributing signal worth checking

permission_denials shows Bash calls denied, all of the shape gh api repos/Morrison-Lab/ai-config/pulls/985 --jq .... The reviewer reached for gh for basic PR state, was refused by the allowlist, and thereafter leaned on Agent. Whether that pushed it toward delegation is a guess, but the denial is real and is independently worth fixing.

Suggested direction

The review prompt should state that the run is headless and single-shot: no background delegation, no waiting on notifications, and the verdict must be written by the top-level agent before its turn ends. Constraining or removing the Agent tool from allowedTools for the reviewer would enforce that mechanically rather than by instruction, which is the stronger form.

Worth checking whether the guard can also treat "final message names background agents" as a distinct outcome from a generic stub, since the retry is unlikely to help and the spend is large.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions