Skip to content

The 202 Pattern: Why Agentic AI Needs a Pause Button, Not Just a Policy

8 min read Fullmakt Team

  • governance
  • agents
  • traceability
  • authentication
  • credentials

Most policy engines built for AI agents answer one question with one of two words: allow, or deny. That works for the large majority of calls an agent makes — read this record, call this read-only endpoint, run this query against data it’s already scoped to touch. It stops working the moment an action is genuinely ambiguous: a refund above a threshold, a schema change, an email to an external domain, a payout. Those calls aren’t wrong often enough to blanket-deny, and they’re consequential enough that blanket-allow is a bet a governance program shouldn’t be making on an LLM’s behalf. They need a third answer that neither allow nor deny can express: pause, and ask a person.

The failure: a binary gate wearing a governance costume

Teams that bolt human oversight onto an agent pipeline usually do it with a log line and a Slack alert — the agent acts first, and a human finds out after the fact, if a monitoring rule happens to catch it. That isn’t oversight, it’s observability applied to a decision that already executed. The record shows what happened; it doesn’t give anyone the chance to have said no before it did.

The alternative teams reach for next is a static allowlist: “this agent may never call the payout endpoint,” full stop. That’s a real control, but it’s a blunt one — it can’t distinguish a payout that’s routine from one that’s suspicious, so it either blocks the workflow the agent exists to run, or someone quietly widens the allowlist under deadline pressure until the control has evaporated. Binary policy can express “always” and “never.” It has no vocabulary for “usually, but not this one, and I want to see it first.”

Why “just add a review queue” doesn’t close the gap

A review queue that a human checks periodically looks like it solves this, but it inherits every weakness of after-the-fact monitoring plus a new one: staleness. An agent’s context — the data it read, the arguments it composed, the reason it decided this call was the right next step — is freshest at the instant it tried to act. A queue a human clears an hour later is reviewing a decision, not gating one; by the time anyone looks, the workflow has usually already moved on without the answer, or timed out and retried blind.

There’s a sharper failure mode underneath that: an approval with no expiry and no binding to the exact call it was granted for is a standing credential wearing a governance label. If “approved” just flips a long-lived flag, nothing stops that flag from covering a different call than the one a human actually looked at — the same confused-deputy shape that shows up everywhere a decision outlives the specific action it was made for. An approval that doesn’t expire fast and doesn’t bind to the exact arguments it was granted for is not meaningfully different from a standing “allow.”

Where the fix actually has to live

  • The gate has to sit in the execution path, not beside it. A policy rule that flags a call as needing approval has to actually block that call from completing — returning a “pending” response the caller must wait on — not just emit an alert while the action proceeds. Pause has to be a real state the call can be in, not a label applied after the fact.
  • The pending decision needs its own identity, separate from the call that triggered it. A human approving or rejecting has to be acting on something specific and referenceable — not “the last suspicious thing this agent tried,” which is ambiguous the moment two risky calls land close together.
  • An approval has to expire fast, and has to be single-use. A human saying yes to this refund, right now, is not a standing yes to every refund this agent proposes for the next hour. The approval should collapse to a short window — minutes, not hours — the instant it’s granted, and consuming it once should retire it, the same way a decision token is good for exactly one use.
  • The retry has to prove it’s the same call, not just a call from the same agent. If an approval is bound to a specific set of arguments and the agent comes back with different ones — a bigger refund, a different recipient — that’s not the action anyone approved, and the system should treat it as a fresh request, not a shortcut through an existing yes.
  • The decision itself has to be a human’s, provably. In a multi-agent system, one agent proposing an action and another agent “approving” it on a human’s behalf isn’t oversight, it’s two agents agreeing with each other. Whatever grants the approval needs to be a surface an autonomous caller — including another agent acting over A2A — is structurally barred from touching.
  • Both halves — the pause and the resolution — belong in the same audit trail as the call itself, so an incident review can reconstruct not just what an agent did, but what it asked permission for, who granted or refused it, and how long that gap took. Traceability that only records the executed action and skips the request for permission is missing exactly the part a reviewer asks about first.

The business case: this is the approval loop Fullmakt already runs

This isn’t a proposal — it’s the shape of the requireApproval policy rule in Fullmakt’s broker, and the reason the approval flow is built the way it is:

  • A policy rule can mark specific tool calls as requiring approval, and when one fires, the call doesn’t execute — it comes back as a pending result carrying its own approval id, and the agent (or the human driving it) has to wait on a decision before anything downstream happens.
  • Approving is a human-only action. The same capability gate that keeps vault access and credential setup out of an agent’s reach also blocks any agent — including one calling in over A2A on another agent’s behalf — from resolving an approval. A pending action can only be waved through by a person looking at it through the console.
  • An approval collapses to a five-minute window the moment it’s granted, and it’s consumed exactly once — the next matching call uses it up and turns it from pending into resolved. There’s no lingering “yes” for a second, different call to ride on.
  • The retry has to match what was actually approved — the same arguments, tied back to the same request — or it gets treated as a new action requiring a fresh decision. Change what the agent is asking for and you don’t get to reuse an old yes.
  • Every step lands in one connected audit record: the call that triggered the pause, the pending approval it created, who resolved it and when, and the execution that finally ran (or didn’t). An incident review doesn’t have to stitch together a policy log, an alerting tool, and a ticketing system to answer “did a human actually see this before it happened” — it’s one trail.

The commercial case is the same one behind every piece of this series: a policy engine that can only say allow or deny is cheaper to build, and it’s also the reason teams end up either over-blocking their own agents or quietly widening an allowlist until governance is theater. Fullmakt puts the pause where the call actually happens, gives it a human-only resolution path, and makes the approval itself expire — so “we require human sign-off on payouts” is an enforced state in the execution path, not a policy document nobody’s agent actually reads.

FAQ

Isn’t this just a webhook to Slack with a manual retry? A Slack alert tells a human something happened or is about to. It doesn’t stop the call, doesn’t give the approval its own expiring identity, and doesn’t prevent a different, unapproved call from riding on the same “someone said yes” moment. The pause has to be enforced in the execution path, not bolted on beside it.

Doesn’t waiting on a human defeat the point of an autonomous agent? Only for the calls it’s applied to, which should be the minority — the ones with real financial, legal, or irreversible consequence. Everything else still runs through ordinary allow/deny policy at full agent speed; the pause is a scalpel, not a universal brake.

What stops one agent from approving another agent’s action? A capability gate that treats approval decisions as human-only, structurally, the same way vault access and credential binding are — no API path exists for an agent, including one acting over A2A, to resolve a pending approval.

What happens if nobody approves in time? The approval expires — Fullmakt’s default pending window is one hour, not left open indefinitely — and the call fails closed rather than silently executing once the window lapses. A stale, unanswered request is not treated as a yes.

Can the same approved decision be reused for a similar call later? No — it’s bound to the specific arguments it was granted for and consumed on first use. A similar call with different arguments is a different request and needs its own approval.

An allow/deny policy answers “is this the kind of thing this agent may generally do.” It was never built to answer “should this specific action, with these specific arguments, happen right now” — that’s a judgment call, and the only honest way to make an agentic system respect it is to give a human a real pause button, wired into the path the action actually takes, not a notification sent after the button’s already been pressed for them.