{"slug": "why-an-ai-agent-can-execute-the-same-action-twice", "title": "Why an AI Agent Can Execute the Same Action Twice", "summary": "A developer argues that AI agents acting as execution systems can trigger duplicate real-world side effects — such as issuing a refund twice — when a tool call succeeds but the acknowledgement is lost, leaving the agent with an ambiguous outcome. The writeup proposes distinguishing transport identity (which attempt) from a stable logical operation identity bound to the effect-bearing payload, and modeling outcomes as CONFIRMED, ABSENT, or UNKNOWN, with UNKNOWN treated as a block-or-reconcile state rather than permission to retry.", "body_md": "AI agents are becoming execution systems.\n\nThey no longer just answer questions. They send messages, create tickets, issue refunds, make bookings, update customer records, trigger deployments, provision resources, and call tools that change external state.\n\nThat creates a failure mode distributed-systems engineers already know well — but agent loops make it unusually easy to trigger:\n\n**a tool call can succeed and still look like a failure to the agent.**\n\nConsider a refund:\n\nAt step 6, the important question is no longer:\n\nDid the request fail?\n\nIt is:\n\n**Did the external effect already happen?**\n\nThat distinction is where ordinary retry logic can become dangerous.\n\nA timeout describes what the caller observed. It does not prove what the external provider did.\n\nAfter a lost acknowledgement, at least two realities may be consistent with the evidence the agent has:\n\nThis is an **ambiguous outcome**.\n\nIf the agent cannot distinguish those realities, blind retry is not merely a reliability mechanism. It can create a second real-world action.\n\nThe same pattern applies far beyond payments:\n\nThe underlying problem is not \"AI hallucination.\" It is distributed-systems uncertainty at the boundary between **intent** and **external effect**.\n\nTraditional applications already retry failed network operations. Agent systems add more ways for repetition to occur.\n\nA tool may be repeated because:\n\nThese mechanisms can all be individually reasonable.\n\nThe danger appears when they cross a side-effecting boundary without preserving the identity and outcome of the **logical action**.\n\nA request ID, tool-call ID, trace ID, retry counter, or timestamp usually identifies an **attempt**.\n\nBut a retry of the same refund is not a new business intention just because it has a new tool-call ID.\n\nFor safe retry handling, we need a stable **logical operation identity**.\n\nFor example:\n\n```\nrefund / order_123\n```\n\nshould identify the same intended refund across all retries of that action.\n\nAttempt 1 might have one request ID.\n\nAttempt 2 might have another.\n\nBut if both represent the same intended refund, the logical operation identity should remain stable.\n\nThis gives us an important distinction:\n\n``` php\ntransport identity -> which attempt is this?\n\nlogical identity   -> which real-world action is this?\n```\n\nThose are not the same question.\n\nThere is another failure mode.\n\nSuppose an application reuses the same logical operation ID but changes a value that affects the real-world action.\n\n```\noperation: send_invoice_4821\nattempt 1 destination: alice@example.com\nattempt 2 destination: bob@example.com\n```\n\nThose should not be treated as equivalent retries.\n\nThe operation identity therefore needs to be bound to the **effect-bearing payload**.\n\nIf a field can change the external effect — amount, destination, message body, booking details, resource configuration, recipient, etc. — changing it should produce a conflict or a new intentional operation.\n\nOtherwise a deduplication mechanism can become a different kind of bug: incorrectly collapsing two distinct actions into one.\n\nA useful execution model has at least three outcome states:\n\n| State | Meaning | Safe default | \n|---|---|---|\n| `CONFIRMED` | Authoritative evidence says the effect happened | Return/replay the known result; do not execute again | \n| `ABSENT` | Authoritative evidence says the effect did not happen | Execution may proceed | \n| `UNKNOWN` | The effect may have happened, but available evidence cannot prove which state is true | Reconcile or block | \n\nThe critical rule is:\n\n**UNKNOWN is not permission to execute again.**\n\nThis sounds conservative because it is.\n\nIf duplicate execution could be expensive or irreversible, safety sometimes requires giving up immediate progress.\n\nThat is the classic tradeoff between **safety** and **liveness**:\n\nIf provider truth is unavailable, a high-impact operation may have to remain blocked until a human or a trusted system can resolve it.\n\nWhen an outcome is ambiguous, the strongest recovery path is often **reconciliation**.\n\nInstead of retrying the mutation, perform a read-only check against an authoritative system.\n\nFor a refund, that could mean asking the provider whether the refund exists.\n\nFor a booking, check whether the reservation was created.\n\nFor a message, query the provider-side message ledger if such a facility exists.\n\nThe flow becomes:\n\n```\nexternal effect may have committed\n            |\n            v\n         UNKNOWN\n            |\n            v\n   authoritative lookup\n       /          \\\n      /            \\\nCONFIRMED          ABSENT\n   |                 |\n   v                 v\ndo not repeat      execution may proceed\n```\n\nThe phrase **authoritative** matters.\n\nA missing local database row is not automatically proof that the external effect did not happen.\n\nNeither is a timeout.\n\nNeither is an empty cache.\n\n`ABSENT` should require evidence strong enough to justify repeating the action.\n\nThere is an obvious counterargument:\n\nDo we really want every search, calculation, and read operation going through durable execution coordination?\n\nNo.\n\nThat would add latency and complexity where there is little duplicate-effect risk.\n\nA better model is selective routing.\n\n| Route | Meaning | \n|---|---|\n| `DIRECT` | No consequential external mutation identified | \n| `PROTECT` | Duplicate execution could create an undesirable external effect | \n| `BLOCK` | The system cannot establish that execution is safe | \n\nA web search is usually `DIRECT`.\n\nA local calculation is usually `DIRECT`.\n\nA refund, message send, booking, order creation, or deployment trigger may be `PROTECT`.\n\nA tool with conflicting or insufficient safety information may be `BLOCK`.\n\nThe asymmetry matters:\n\nFor consequential tools, conservative classification is often the rational choice.\n\n\"Exactly once\" sounds attractive, but it is easy to overstate when independent systems are involved.\n\nA client generally cannot atomically commit both:\n\nunless the systems share an appropriate transaction, deduplication, or reconciliation contract.\n\nSo the defensible target is narrower:\n\n**One intended consequential operation should produce at most one corresponding external effect across retries — under explicit assumptions — or the system should block rather than guess.**\n\nThose assumptions include:\n\nThat is a safety property, not a promise that every operation will eventually succeed.\n\nWe have been building **Once**, an open-source execution-safety layer for AI agent tools and MCP integrations, around this model.\n\nThe project separates attempt identity from logical action identity, preserves ambiguous outcomes, binds effect-bearing input to protected operations, and increasingly classifies toolsets so harmless calls can remain direct while consequential calls receive stronger protection.\n\nThe current public implementation includes:\n\n`DIRECT / PROTECT / BLOCK` routing;\nThe important part is the boundary of the claim.\n\nOnce does **not** claim universal exactly-once execution across arbitrary providers and arbitrary deployments.\n\nIf authoritative truth is unavailable, the correct state may remain `UNKNOWN`.\n\nThat limitation is part of the design rather than something to hide.\n\nI have now published the deeper technical treatment as a citable technical paper:\n\n**Reliable Execution of Consequential AI Agent Actions Under Retries and Ambiguous Outcomes**\n\n**Jamie Oswald — Once Research**\n\n**Published:** 26 September 2026\n\n**DOI:** [10.5281/zenodo.22969881](https://doi.org/10.5281/zenodo.22969881)\n\nThe paper covers:\n\n`CONFIRMED / ABSENT / UNKNOWN`;\nIf you are building agents that can change external state, the question I would ask is simple:\n\n**If this tool times out after the external effect commits, what prevents the retry from doing it again?**\n\nIf the answer is only \"the framework retries carefully,\" there is probably another reliability boundary worth examining.", "url": "https://wpnews.pro/news/why-an-ai-agent-can-execute-the-same-action-twice", "canonical_source": "https://dev.to/stringsofthemindoss/why-an-ai-agent-can-execute-the-same-action-twice-2mb7", "published_at": "2026-09-26 02:24:54+00:00", "updated_at": "2026-09-26 03:00:00.197224+00:00", "lang": "en", "topics": ["ai-agents", "artificial-intelligence", "ai-safety"], "entities": [], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/why-an-ai-agent-can-execute-the-same-action-twice", "markdown": "https://wpnews.pro/news/why-an-ai-agent-can-execute-the-same-action-twice.md", "text": "https://wpnews.pro/news/why-an-ai-agent-can-execute-the-same-action-twice.txt", "jsonld": "https://wpnews.pro/news/why-an-ai-agent-can-execute-the-same-action-twice.jsonld"}}