Distinguish Timeout and TooComplex from Denied in permission outcomes

Status Open
Maintainer reply None cached
Activity 0 comments · opened Aug 15, 2026

Context

I run long unattended sessions (8–12 h overnight) in auto mode. Two related failure modes are already well documented:

  • Unanswered prompts hang forever with no timeout — #78487, #85820, #86915, #73394.
  • The classifier balks at compound commands whose every constituent is individually allowed — #16561, #76718, #79930, #30213.

This issue is about neither mechanism. It's about what the model is told when they fire. Today all roads lead to Denied, and that single signal is wrong for both cases.

Problem

Denied means the user considered this and does not want it done. The model reads it that way and it should — it abandons the goal, or pivots to something it thinks I'd prefer. That's correct behavior for a real denial.

But it's also what the model gets when:

  1. Nobody was there. No human judgment was rendered at all. The model concludes I refused something I never saw. Note that #78487 proposes auto-deny-on-timeout as the fix, which bakes this conflation in permanently — the session stops hanging, but the model still learns the wrong thing.
  1. The command shape was unclassifiable, not the intent. Models have gotten fonder of compound one-liners lately — presumably to save round trips and tokens — and those are exactly what trips the classifier. Something like:
for i in 1 2 3; do out=$(gh pr checks 123); if echo "$out" | grep -q pending; then sleep 45; fi; done

Every primitive there is benign and individually approvable. Bundled into a loop with command substitution and a pipe, it needs a human. The model is told Denied and reasonably concludes I don't want the PR checked — when what I actually want is for it to ask again in smaller pieces.

The cost lands squarely on unattended runs. A 12-hour session dies two hours in, or limps along having quietly given up on half its objectives, and I find out in the morning.

Proposed Solution

Give the permission layer more than one way to say no, and pass the distinction through to the model.

  • Timeout — semantics: no human judgment was rendered. Whatever timeout mechanism lands from #78487 et al., have it return this rather than Denied. The model should be free to note it, skip the blocked call, and continue with unblocked work.
  • TooComplex — semantics: the shape blocked this, not the intent. Returned when auto mode declines because it can't classify a compound/chained/substituted/looping call. The appropriate response is decomposition into individually-approvable calls, and the model currently has no way to know that's what's wanted.

Optionally, fire the existing notification hook on Timeout so an unattended run can page me instead of failing silently.

On gaming

Naming the obvious risk: TooComplex tells the model something about the classifier, and a model seeking approval could learn to salami-slice a command that should have been refused into pieces that individually pass.

The exposure looks small and is already present — a model that gets Denied on a compound command can retry the pieces today, and does. What's missing is only the signal that decomposition is the appropriate response to this specific failure. If it's still a concern, scope TooComplex to calls where every constituent operation is independently on the allowlist. That's exactly the set where decomposition is provably safe and the current prompt is a pure false positive — and it overlaps neatly with what #16561 proposes parsing for anyway.

Acceptance Criteria

  • [ ] A permission outcome caused by timeout is distinguishable by the model from a user denial.
  • [ ] A permission outcome caused by classifier complexity is distinguishable by the model from a user denial.
  • [ ] On Timeout, the model continues with remaining unblocked work rather than treating the objective as refused.
  • [ ] On TooComplex, the model's default recovery is to re-issue the call decomposed, not to abandon the goal.
  • [ ] A genuine user denial keeps today's semantics and remains unambiguous.

View original on GitHub ↗