Symptom
Approving a parked call does not make the call happen. The agent is asked to do it again.
Mechanism
Documented in src/harness/policy.rs and worth quoting because the shape is not obvious:
openhuman's ToolPolicy returns RequireApproval, and the session turn loop treats that fail-closed — it blocks the tool call and feeds the model a refusal, rather than suspending the call and resuming it once a verdict arrives. By the time the operator sees the card, the blocked call is gone.
So approval cannot resume anything. Instead it re-issues: approving mints a single-use GrantedCall scoped to that agent, tool and exact arguments, and HarnessBrain re-dispatches the granting agent with an instruction to make the call again unchanged. An unredeemed grant expires on a TTL and the operator is told the agent did not act.
Consequences the operator actually experiences:
- The turn visibly dead-ends. Work stops, output is partial, and the model may narrate a refusal it was handed.
- Approval costs a full re-dispatch — more tokens, more latency, and a model free to make different choices the second time even though the grant pins the arguments.
- A turn that parks several calls loses all of them, not just the first.
MAX_APPROVAL_REQUESTS_PER_TURN is 8 and the rest of a turn's parked calls are discarded, so beyond eight the operator is not merely delayed — they never see the request at all.
Why this is the deep one
The block sits in openhuman's turn loop, not here. Options, roughly in ascending cost:
- Reduce how often we land here. The other sub-issues do this; it does not fix the mechanism.
- Batch the re-dispatch. Approve N cards, re-issue once with all N grants live, rather than a round trip per card.
- Suspend and resume properly — an await point in the turn loop, upstream in openhuman. The real fix, and the expensive one.
Worth scoping option 3 before committing to it, and worth noting that option 2 alone would remove most of the felt pain.
Also worth fixing regardless
The silent discard past 8 requests per turn. Whatever the cap is, exceeding it should tell the operator that requests were dropped — a queue that quietly truncates reads as "nothing else needed approving", which is the opposite of true.
Symptom
Approving a parked call does not make the call happen. The agent is asked to do it again.
Mechanism
Documented in
src/harness/policy.rsand worth quoting because the shape is not obvious:openhuman's
ToolPolicyreturnsRequireApproval, and the session turn loop treats that fail-closed — it blocks the tool call and feeds the model a refusal, rather than suspending the call and resuming it once a verdict arrives. By the time the operator sees the card, the blocked call is gone.So approval cannot resume anything. Instead it re-issues: approving mints a single-use
GrantedCallscoped to that agent, tool and exact arguments, andHarnessBrainre-dispatches the granting agent with an instruction to make the call again unchanged. An unredeemed grant expires on a TTL and the operator is told the agent did not act.Consequences the operator actually experiences:
MAX_APPROVAL_REQUESTS_PER_TURNis 8 and the rest of a turn's parked calls are discarded, so beyond eight the operator is not merely delayed — they never see the request at all.Why this is the deep one
The block sits in openhuman's turn loop, not here. Options, roughly in ascending cost:
Worth scoping option 3 before committing to it, and worth noting that option 2 alone would remove most of the felt pain.
Also worth fixing regardless
The silent discard past 8 requests per turn. Whatever the cap is, exceeding it should tell the operator that requests were dropped — a queue that quietly truncates reads as "nothing else needed approving", which is the opposite of true.