Skip to content

background-agent stub recurred with the deny rule deployed: all 4 spawns omitted run_in_background, so Agent(run_in_background:true) could not match #756

Description

@d-morrison

What happened

review / claude-review on #755 (c6ccf92) ended with no verdict after spawning four background agents. Run 33285247998:

executed_background_spawns=4 (tool_use with run_in_background != false: 4; denied: 0)
permission_denials_count=0 (max_denials=5)
failure_kind=background-agent
total_cost_usd=3.2225

Why this is new rather than a duplicate of #392 / #532 / #551

Those three are closed, and the mitigation they produced is deployed: run-claude-review-attempt/action.yml:531 carries Agent(run_in_background:true),Task(run_in_background:true) in --disallowedTools.

denied: 0 is the evidence that it did not fire. Not that it was absent, and not that it failed to parse — that it had nothing to match. CLAUDE.md states the reason, as a known limitation accepted when the rule was added:

It closes one of two routes, and the prompt still covers the other. "A parameter the model omits is never matched", and Agent's run_in_background defaults to true — so a call that omits the parameter still backgrounds and this rule does not see it.

All four spawns took the uncovered route. So this is not the mitigation regressing; it is the residual behaving exactly as documented, at a measured cost.

#532's title is "recurred despite gha#393's run_in_background:false mitigation" — that was the prompt mitigation. This is the first recorded recurrence with the permission-rule mitigation also in place, which is what makes it a distinct data point rather than a repeat.

Why it is worth reopening an accepted tradeoff

The tradeoff was accepted without a price attached. This run supplies one:

  • $3.22 spent, no verdict produced.
  • A PR blocked whose diff had already passed an adversarial self-review that found and fixed a blocking defect. The review infrastructure contributed nothing while costing more than the reviewed change was worth.
  • The automatic retry is deliberately withheld for this failure_kind (gha#551), correctly — gha#536 records 8 stub attempts for 2 recoveries. So the failure is terminal per run, not self-healing.

The asymmetry to note: the prompt instruction is the only thing covering the omitted-parameter route, and a prompt is a request rather than a constraint. CLAUDE.md's own section on this is titled exactly that. Relying on it means the failure rate is whatever the model's compliance rate happens to be, with no floor.

Options, none obviously right

  1. Accept and document the price. Add the measured cost to the existing note so the tradeoff is re-readable with a number attached. Zero risk, no reduction in failure rate.
  2. Deny Agent and Task outright. Closes both routes completely. Rejected once before, for a good reason: it breaks the code-review plugin's legitimate synchronous fan-out, so it trades this failure for a different capability loss. Worth re-pricing only if synchronous fan-out turns out to be unused in practice — which is checkable from execution outputs rather than guessable.
  3. Ask whether the parameter can be made explicit. If a deny rule could match "absent or true" rather than only "true", the gap closes with no capability loss. I do not know whether Claude Code's permission matcher supports that, and CLAUDE.md records only that an omitted parameter is unmatched — which is a statement about the current matcher, not necessarily about what is expressible. Worth one check against the permissions documentation before assuming it cannot be done.
  4. Treat background-agent as retryable after all, once. Contradicts gha#551's reasoning and the 2/8 recovery figure. Noted for completeness, not recommended.

🧭 My read: (3) first, because it is cheap and would close the gap outright if the matcher supports it; (1) as the fallback if it does not; (2) only with usage evidence in hand.

Not acting on any of these unilaterally — the deny-rule scope was a deliberate decision, and re-opening it is the owner's call.

Scope note

Filed from #755's CI failure per this repo's "file every noticed issue" rule. #755 itself is unaffected in substance: its failure is this, not its diff, and the standing-down comment plus the one permitted re-run are recorded on that PR.


Posted by Claude Code (AI agent) --- not written by a human.

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