A write that times out has two possible histories and the agent cannot see which one it is in. Six services with realistic contracts, twelve injected fault modes and a ledger of committed effects, over 25,930 episodes: where an immediate read-back can settle it, a frontier model told to act exactly once duplicates 0.5% of the time. Where it cannot — the request is still in flight, or the transport delivered it twice — the same models duplicate in 56% and 74% of episodes, and the tool contract explains 81% of the variance. Offering an idempotency key on every write takes duplicates from 28% to 4%. The agents reported success in 90% of the episodes where they had duplicated an effect.
Your agent calls create_charge and the call times out. Two worlds are consistent with that: the charge never happened, or it happened and the acknowledgement was lost on the way back. Retry and you may bill the customer twice. Do not retry and the order never gets paid. There is no prompt that resolves this, because the information the agent needs is not in anything it can see.
The sandbox here makes that concrete. Six services — social, billing, tickets, mail, data, deploy — each with a write path and a read-back path, and each read-back either strongly consistent, lagging by two or three minutes, or simply absent. Twelve faults are injected at the service boundary, and every episode is graded against a ledger of what actually committed, not against what the agent says it did.
Step through the faults. The first column is all the agent gets.
Split the faults into the ones where an immediate read-back reveals the outcome and the ones where it does not, and the question “whose job is exactly-once” gets two different answers. Where looking works, the model’s judgement carries the episode: it has to think to check before retrying, and better models do. Where looking cannot work, the model is almost irrelevant and the interface decides.
The same split shows up directly in duplicate rates. On a lost acknowledgement the three frontier models never duplicate and the cheap one duplicates on nearly half its episodes — that is a model gap, and buying a better model closes it. On a late commit the frontier models spread from 25% to 68%, and on double delivery all four sit at roughly three episodes in four. Model choice has stopped mattering.
The paper proves the obvious thing carefully, and it is worth stating plainly: a policy that decides only from what it can observe cannot be exactly-once on a write that might still be in flight. Suppose the agent finishes the task within some time T in the world where the write never executed. Then in the world where it executes at any moment later than T, the same policy duplicates — with certainty. Verification does not fail because the agent verified badly. It fails because the evidence arrives after the decision.
Which means waiting is the only observation-based repair, and waiting is a bet on a bound. Set the delay distribution and pick a strategy.
A known, short bound makes waiting work: 120 seconds of patience against a 90-second delay takes duplicates to 1%. Nothing about production looks like that. Once the tail is unbounded, an hour of waiting per episode still leaves more duplicates than a key does in ninety seconds.
An idempotency key is a caller-supplied string the service promises to execute at most once, returning the original outcome for repeats. Given that, “re-issue under the same key until acknowledged” is exactly-once in every outcome state the sandbox can produce, including the late commit that defeats verification. The useful empirical finding is that you do not have to teach agents to use keys: they use them when they exist. Flip the contract.
The other half of the result is where it does not live. Nine models, four harnesses, and the harness barely registers: a small guard that attaches keys to outbound writes transferred across a minimal scaffold and three production agent CLIs unchanged, and every one of them ran clean. That is the sign you are fixing the right layer — the fix does not care what is above it.
Put your own numbers in. The duplicate rates are the paper’s; the volumes, the fault rate and the cost of a duplicated write are yours, so the totals are labelled illustrative. The fault rate is the share of writes that hit a timeout, a 500, a rate limit or a redelivery — whatever your error budget already says it is.
One more number decides whether you will ever find out. In the episodes that produced a duplicate, the agent reported the task complete anyway nine times out of ten, and flagged nothing as uncertain in four out of five. Your monitoring cannot be the agent’s own summary.