What is approval drift in AI agent tool calls?
Approval drift is the gap between the request a reviewer approved and the request that runs. Where it comes from, the three ways it is caught, and what a bound approval does not cover.
Approval drift is any difference between the operation a reviewer approved and the operation that actually runs, such as a changed amount, recipient, target, action version or provider state between the decision and the call. The reviewer said yes to one thing. Something else ran.
Some writing calls the request-side case approval substitution. This glossary uses approval drift for every way the two can come apart, because they are caught by different mechanisms.
Where does approval drift come from?
An agent's tool call is rarely approved and executed in the same instant. A reviewer may take an hour. In that time:
- The request changes. The agent retries with a different amount, or mutable run state is edited before the call resumes.
- The definition changes. Someone edits the action, so the same input now produces a different HTTP request.
- The credential changes. The key behind the action is revoked or rebound to another host.
- The world changes. The file the reviewer read was edited by someone else, or the payment was partly refunded already.
An approval flag catches none of these. It records "yes" and lets whatever comes next run.
How is each kind caught?
| Drift | How Anlyon handles it on a governed action | Receipt |
|---|---|---|
| A changed request sent with the reviewed preview | Refused at admission with 409 PREVIEW_MISMATCH | None. No effect is created |
| The action was edited after review | Dispatch is refused (action_changed) | refused |
| The approval, or its preview, expired before dispatch | Dispatch is refused | refused |
| A secret is missing or no longer allows the request | Dispatch is refused (credential_unavailable) | refused |
| A GitHub file changed at the provider | GitHub refuses the write on the reviewed blob SHA | failed |
The first four are Anlyon's own state, checked by the bound approval: a digest of the request, target, versions, preconditions and expiry, recomputed before dispatch. The last is the provider's state, and it is caught by the provider's conditional write, not by Anlyon's digest.
Example
A reviewer approves a $20 refund for order 42. Before dispatch, the agent's loop sends the same call with $200 and the reviewed previewId. The request no longer matches the reviewed preview, so Anlyon refuses it at admission and nothing reaches Stripe. Getting the $200 refund requires a new preview and a new decision.
What a bound approval does not cover
- Provider state without a conditional write. Stripe has no compare-and-set, so the refundable amount a reviewer sees is as of review. Resend and a declared action have no stale-state protection.
- Calls outside Anlyon. A tool your own code calls directly is not routed through Anlyon and is not governed by it.
- An action with no declaration and no adapter. It is approved on its request snapshot, which freezes what the approver reviewed.
Related terms
Read next
Frequently asked questions
What is approval drift?
Approval drift is any difference between the operation a reviewer approved and the operation that actually runs, such as a changed amount, recipient, target, action version or provider state between the decision and the call. An approval that is not bound to the exact request cannot detect it.
How do you prevent approval drift for AI agents?
Bind the approval to the exact reviewed request and recompute that binding before dispatch, refusing on any difference. Use the provider's own conditional write where one exists, because a request can be unchanged while the resource behind it has changed.
