Researchers took 336 frozen agent histories, ran every one of them through two orchestration hosts, and scored the result against a provider ledger the recovering application could not see. The best retry design, retained-ledger reconciliation, passed 42 of 42 histories per host. The one most frameworks ship by default passed 30.

The ranking, per host, from "Permission to Retry: A Study of Authorization and Recovery in AI Agent Workflows" by Deekshith Marla and Kushagra Bhatnagar: retained-ledger reconciliation passes all 42, revalidation before retry passes 36, stable-key retry passes 31, cached retry passes 30. Every one of the 168 paired host cells produced identical checked outcomes, on native LangGraph and Temporal hosts, across 14 schedules, three provider contracts and four matched application policies. The host does not save you. The contract does.

The line that follows from it is the one this site keeps repeating: retry safety is a ledger design question, not a prompting question. You cannot prompt your way out of a double charge.

"Your Agent Dies at the Timeout" covered what happens when the clock runs out. This note covers what happens after. The retry, and why almost nobody designs it.

THE FOUR OBLIGATIONS YOUR AGENT IS COLLAPSING INTO ONE

The paper states its spine in one sentence, and it is worth quoting whole: checkpoint state, permission to dispatch, evidence of an external effect and permission to reconcile are four distinct obligations.

Walk each one, because most stacks collapse all four into "try again."

Checkpoint state is where you were. The turn index, the tool call, the arguments, written down before anything leaves the process.

Permission to dispatch is whether you were allowed to fire the action at all. An agent whose token expired mid-run, or whose human revoked access between attempts, is not the same agent that fired the original call. Resuming work it no longer has the right to do is a privilege escalation with extra steps.

Evidence of an external effect is whether the world says it happened. A provider confirmation id, a ticket number, a commit sha. Something issued by the system on the other side, never something your agent wrote into its own memory.

Permission to reconcile is whether your records may be corrected to match the world. That sounds like a formality until you watch an agent overwrite a real double charge with one optimistic row and mark the task green.

An agent that cannot answer all four separately cannot retry safely, because it cannot tell "I do not know if it happened" from "it did not happen." Those two states demand opposite actions and almost every status enum has one slot for both.

The paper also runs a separate 16-case component study of InfinityOS, the enterprise AI platform built by Arya.ai, exercising exported authority, worker, recovery and settlement code over repository fakes. That detail matters more than it looks. It means the contract was checked in code that a team actually shipped, not only in a research harness written for the occasion.

WHY CACHED RETRY IS THE DEFAULT AND WHY IT FAILS

Cached retry is easy to describe: keep the request, fire it again, hope the target is idempotent. Idempotent means doing it twice has the same effect as once. Most engineers assume it, almost nothing guarantees it, and the assumption is why the default is also the worst performer on the board at 30 of 42.

It fails in two ways, and the paper's history categories show exactly what it destroys.

The first is a duplicate external effect. The payment posts twice, the ticket opens twice, the deploy runs twice. Usually the target was not idempotent because the key was minted inside the retry loop instead of before the first dispatch, which is the most common bug in this entire class of system.

The second is lost uncertainty. The original attempt timed out. Nobody knows whether the provider took it. The retry succeeds, the agent records success, and the earlier attempt becomes invisible. Your records now claim one effect while the world holds two, and you find out at reconciliation time, which for a payment means a support ticket and for payroll means a phone call with an angry human on the other end.

Look at what the winning policy had to carry to pass 42 of 42: 21 checked completions, 15 checked denials, and six unknown outcomes with reservations retained. Those last two categories are the whole argument. Fifteen histories where the correct behavior was to not retry, and six where the correct behavior was to hold the reservation open and say "unknown" out loud. Cached retry erases both. It has no vocabulary for a denial that must be respected or an unknown that must be preserved, so it converts each one into another attempt.

THE RETRY DECISION TREE

Here is the contract in four branches, implementable this week. This is retained-ledger reconciliation in practice, and it uses the same four names as the ranking above.

Four-branch retry decision map: a checked completion panel with a do not retry sign, a checked denial panel listing declined card reasons, an unknown outcome panel with a reconciling progress readout, and a no ledger entry panel behind a fail closed barrier, all around a central transaction ledger card reading status unknown
Four branches, four outcomes: completed, denied, unknown, no record.
  1. Branch one: the ledger shows a checked completion. Never retry. Resume from the checkpoint after the effect. The work is done and the only remaining job is to record it.
  2. Branch two: the ledger shows a checked denial. Retry is allowed only if the denial reason is gone. A declined card and a rate limit both surface as failures and they demand opposite handling, so store the reason, not the boolean.
  3. Branch three: the ledger shows an unknown outcome with the reservation still retained. Reconcile first. Ask the external system what happened, by the identifier you minted before dispatch, and only then decide. This is the branch that requires the design work, and it is the one nearly every stack is missing.
  4. Branch four: there is no ledger entry at all. Then you were never safe to dispatch, and the correct action is to fail closed and page a human instead of retrying into the dark.

Now look at what that tree does to the other three candidates in the ranking. Cached retry has a retry branch and no reconciliation branch, so an unknown outcome can only turn into another attempt, and it passes 30 of 42. Stable-key retry covers the dispatch and assumes the target stays idempotent, and it passes 31. Revalidation before retry checks the action before firing but never asks the external system what already happened, and it passes 36. Only retained-ledger reconciliation covers all four branches, which is what 42 of 42 actually means.

Reconciliation means checking the world against your records, and the retained evidence of external effect is what turns branch three from a guess into a query. Without an id you can hand to the provider, "unknown" is permanent, and every retry after it is a coin flip you already lost once.

THE HARNESS CARRIES THE TOLERANCE, NOT THE MODEL

If you are hoping a bigger model fixes any of this, the rest of today's stack closes that door.

"Tool-Calling LLM Agents Under Realistic MCP Faults: Scale Does Not Purchase Fault Tolerance," accepted as a NeurIPS 2026 poster, built MCP-Injector, a protocol-aware fault-injection middleware calibrated against 57,240 issue and pull-request threads mined from 1,774 open-source MCP repositories. The 1,350-cell experiment crossed two gpt-oss backbone sizes, 20B and 120B, with three agent stacks, a custom multi-round plan-and-execute loop, the OpenAI Agents SDK and LangChain, under three fault conditions.

Under that permanent-heavy stress profile, task completion fell by 60 percent, from 8.08 to 3.23 out of 10. The 120B model retained no larger share of its fault-free score than the 20B, with p equal to 0.96, and its completion rate under faults was if anything lower, 91.1 percent against 95.6 percent. The stacks differed from each other. Framework-level error handling is the variable. Model scale is not.

That finding lands on your retry layer directly, because the retry layer is a reader of tool text. Every branch in the tree above is a decision about a string a tool printed, so the harness that carries your fault tolerance is trusting that string to be honest. The formatter is not a presentation detail, it is load-bearing machinery inside the contract, and the third paper, "Who Verifies the Tools? How Warped Formatters Mislead Agents and Their Verifiers" by William Jeffries, shows what happens when it lies.

The author found the failure in a production retrieval system used by the Pilsudski Institute in New York. Every tool computed correctly and every formatter omitted something: search limits, result caps, identifier namespaces. Feeding identical results through two formatter versions, one with the omissions and one with the missing details stated, changed what agents claimed and what verifiers accepted. In one test, verifiers went from accepting incorrect answers 90 out of 90 times to rejecting them 90 out of 90 times. Same model, same verifier, different text.

Now run that through a retry decision. Your branch three reconciliation reads tool output to decide whether an effect landed. If the formatter drops the cap, the limit, the namespace or the error code, your ledger is recording a summary of a lie, and the retry layer inherits every formatter defect upstream of it. The paper's own audit prompt, written with prior knowledge of the authors' system, found twelve more defects in an older version of that system and found warped formatters in OpenClaw and Hermes, with the OpenClaw fix already merged.

Escalation is engineered too. "Knowing When to Stop: The Evidence-Action Gap in Coding Agents" ran ImpasseBench, twelve injected blockers, eight frontier models, 19,371 trajectories, and found that nearly every run needing outside help had already collected enough evidence to know it, while a third still burned their budget. An escalation tool cut budget exhaustion from 34.0 percent to 6.7 percent, and an external monitor for models that ignore the tool nearly tripled task success once the environment was restored. Handing off is a tool call and a report format, not a mood.

WHAT TO DO TODAY

  1. Draw your agent's actions on a ledger before the next release. Every consequential tool call gets an entry with intent, dispatch permission and effect status, written before the call leaves the process.
  2. Separate "unknown" from "failed" in every status enum you own. If your schema has one error state, it cannot express branch three, and your agent will pick the optimistic reading by default.
  3. Pick your retry branch from the tree above in code, not in the prompt. A policy that lives in a system prompt is a suggestion to a model that is already confused about what happened.
  4. Mint the idempotency key before the first dispatch, store it with the intent, and send it on every attempt. A key generated inside the retry loop exists to produce the duplicate you were trying to prevent.
  5. Audit one formatter per critical tool. Does its output state the limits, caps and namespaces the agent needs, and does it print the identifier the agent can reconcile against?
  6. Add a reconcile step after every timeout, before any retry. The timeout is the moment your records stop agreeing with the world, and it is the only moment reconciliation is cheap.
  7. Test it by pulling the network cable mid-dispatch, not by writing a unit test that pretends to. The paper hid the provider ledger from the recovering application, which is the only way to learn whether your agent knows or is guessing.

THE UNCOMFORTABLE QUESTION

Oracle used its AI World conference to argue that agent accuracy fails on semantics more often than on model quality, and shipped a Business Semantic Layer between its Autonomous AI Lakehouse and the agents so that a question about revenue resolves to one definition every time. Every vendor in enterprise data is now making that same bet, and it points at the same conclusion this paper reaches from the opposite direction. The system around the model decides the outcome, and the record of what the system did is the part nobody specs.

So here is the question to put to your team this week. If your agent fired a payment twice tomorrow morning, could you tell from your records which of the two was the retry, or would you have to ask the payment provider what your own system did?

If the answer is the provider, you do not have a reliability problem. You have a bookkeeping problem, and no amount of prompting is going to balance the books.

Enjoyed this article?

☕ Buy Me a Coffee

Support PhantomByte and keep the content coming!

Build Real AI Infrastructure

PhantomByte teaches you to build real AI infrastructure yourself: local AI stacks, autonomous agents, multi-agent orchestration, web scraping, and custom tools. Step-by-step PDF tutorials you download, follow, and deploy. No subscriptions. No fluff. Just skills that ship.