Who Approves, and How
Your agent finishes a discharge summary and stops to ask. The question appears exactly where you built it to appear: a prompt in the terminal that launched the run, waiting on a keypress. The person allowed to answer is a consultant who does not have that terminal, is not in the building, and will read the case tomorrow morning. The ward is waiting and the run is holding a connection open, so the engineer watching the logs presses y. The gate fired on schedule and blocked nothing. It collected a signature from the one person in the story with no authority to give it.
A bank does not have one window
Walk into a branch and count the places a decision can be made. Cash under a couple of hundred comes out of the machine in the lobby: a fixed rule, applied to every request, no person involved at all. A few thousand and the teller settles it in front of you, in seconds, because the amount sits inside what she is trusted to sign for. Above that she turns and needs the manager, still in the building but holding a different key. Open a mortgage and nothing is decided in that room at all — the file leaves for a department you will never see, and you go home with a reference number and a date.
Four decisions, four routes, and not one of them was bolted on after the branch opened. An agent has the same four. A hook applies one central policy to every tool call before it runs. A tool checks the role of whoever is calling against the capability being asked for. A protocol like MCP elicitation puts a structured question to the operator inside the session they are already sitting in. And an asynchronous workflow hands the decision to somebody outside the run entirely. Three things pick the window: how long the answer takes, who is trusted to give it, and how finely the thing being approved needs to be sliced.
The review has to outlive the run
The asynchronous route is where designs break, because it looks like the others right up until you build it. A two-day decision pushed through a prompt that expects an answer now has two endings, and both are bad. Either the run sits there holding state and paying for it, which is why waiting is its own engineering problem, or somebody nearer the keyboard answers on the absent person’s behalf and your gate quietly becomes a stamp.
The alternative is to stop treating the approval as something the agent owns. A service can hold it instead. The agent posts the request and gets back 202 Accepted with a case id, a review URL and a poll URL, then hands the human the link and polls. The person opens a page, sees the actual thing — five supplier offers, say — selects the three that are acceptable, and the agent sends requests for those three only. The decision never lived in the context window. It lived on the service, which is why it survives a restart, crosses channels, and works for an agent somebody else wrote. The subtle failure is treating that review URL as a notification: if the action proceeds regardless, you have built an elaborate way of telling people what you already did.
The layout comes before the first gate
None of this is a switch you flip later. Asynchronous approval needs durable state, a case id and something to resume into; a keypress has none of those, and retrofitting them means rewriting the workflow rather than adding a condition. Granularity is structural too: a route that can only carry approve this run will never carry approve three of these five, no matter how the question is worded.
One agent usually needs several routes at once. Reading a folder of records goes through the global hook and never reaches a person. Editing a clinical record sits behind a role check in the tool itself. The discharge waits on a consultant who is not in the building, which means it waits properly, as a pause the workflow knows about rather than a process held open. Pick those routes while the risks are still on paper, because every one of them is cheap to draw and expensive to move. A gate is only a gate when the question reaches the one person who can say no.