<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Once</title>
    <description>The latest articles on DEV Community by Once (@stringsofthemindoss).</description>
    <link>https://dev.to/stringsofthemindoss</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4143698%2F6c965390-c871-4ba8-b1ea-39606da64a62.png</url>
      <title>DEV Community: Once</title>
      <link>https://dev.to/stringsofthemindoss</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/stringsofthemindoss"/>
    <language>en</language>
    <item>
      <title>Why an AI Agent Can Execute the Same Action Twice</title>
      <dc:creator>Once</dc:creator>
      <pubDate>Sat, 26 Sep 2026 02:24:54 +0000</pubDate>
      <link>https://dev.to/stringsofthemindoss/why-an-ai-agent-can-execute-the-same-action-twice-2mb7</link>
      <guid>https://dev.to/stringsofthemindoss/why-an-ai-agent-can-execute-the-same-action-twice-2mb7</guid>
      <description>&lt;p&gt;AI agents are becoming execution systems.&lt;/p&gt;

&lt;p&gt;They 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.&lt;/p&gt;

&lt;p&gt;That creates a failure mode distributed-systems engineers already know well — but agent loops make it unusually easy to trigger:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;a tool call can succeed and still look like a failure to the agent.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Consider a refund:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An agent decides to issue the refund.&lt;/li&gt;
&lt;li&gt;The request reaches the payment provider.&lt;/li&gt;
&lt;li&gt;The provider commits the refund.&lt;/li&gt;
&lt;li&gt;The response is lost, delayed, or times out.&lt;/li&gt;
&lt;li&gt;The agent sees an error.&lt;/li&gt;
&lt;li&gt;The framework retries the tool.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At step 6, the important question is no longer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Did the request fail?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Did the external effect already happen?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That distinction is where ordinary retry logic can become dangerous.&lt;/p&gt;

&lt;h2&gt;
  
  
  A timeout is not proof of failure
&lt;/h2&gt;

&lt;p&gt;A timeout describes what the caller observed. It does not prove what the external provider did.&lt;/p&gt;

&lt;p&gt;After a lost acknowledgement, at least two realities may be consistent with the evidence the agent has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the refund did not happen, so retrying is necessary;&lt;/li&gt;
&lt;li&gt;the refund did happen, so retrying may create a duplicate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is an &lt;strong&gt;ambiguous outcome&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If the agent cannot distinguish those realities, blind retry is not merely a reliability mechanism. It can create a second real-world action.&lt;/p&gt;

&lt;p&gt;The same pattern applies far beyond payments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;sending the same email twice;&lt;/li&gt;
&lt;li&gt;creating the same booking twice;&lt;/li&gt;
&lt;li&gt;submitting the same order twice;&lt;/li&gt;
&lt;li&gt;provisioning the same paid resource twice;&lt;/li&gt;
&lt;li&gt;firing the same deployment twice;&lt;/li&gt;
&lt;li&gt;updating an account more than once;&lt;/li&gt;
&lt;li&gt;triggering the same webhook-backed action twice.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The underlying problem is not "AI hallucination." It is distributed-systems uncertainty at the boundary between &lt;strong&gt;intent&lt;/strong&gt; and &lt;strong&gt;external effect&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why agent systems amplify the problem
&lt;/h2&gt;

&lt;p&gt;Traditional applications already retry failed network operations. Agent systems add more ways for repetition to occur.&lt;/p&gt;

&lt;p&gt;A tool may be repeated because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the model decides to retry after an error;&lt;/li&gt;
&lt;li&gt;the framework has retry logic;&lt;/li&gt;
&lt;li&gt;a workflow resumes from a checkpoint;&lt;/li&gt;
&lt;li&gt;a process crashes and restarts;&lt;/li&gt;
&lt;li&gt;a supervisor redispatches work;&lt;/li&gt;
&lt;li&gt;a sub-agent is re-run;&lt;/li&gt;
&lt;li&gt;an MCP tool call is attempted again;&lt;/li&gt;
&lt;li&gt;a user asks the agent to "try that again."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These mechanisms can all be individually reasonable.&lt;/p&gt;

&lt;p&gt;The danger appears when they cross a side-effecting boundary without preserving the identity and outcome of the &lt;strong&gt;logical action&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tool-call IDs are usually the wrong identity
&lt;/h2&gt;

&lt;p&gt;A request ID, tool-call ID, trace ID, retry counter, or timestamp usually identifies an &lt;strong&gt;attempt&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;But a retry of the same refund is not a new business intention just because it has a new tool-call ID.&lt;/p&gt;

&lt;p&gt;For safe retry handling, we need a stable &lt;strong&gt;logical operation identity&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;refund / order_123
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;should identify the same intended refund across all retries of that action.&lt;/p&gt;

&lt;p&gt;Attempt 1 might have one request ID.&lt;/p&gt;

&lt;p&gt;Attempt 2 might have another.&lt;/p&gt;

&lt;p&gt;But if both represent the same intended refund, the logical operation identity should remain stable.&lt;/p&gt;

&lt;p&gt;This gives us an important distinction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;transport identity -&amp;gt; which attempt is this?

logical identity   -&amp;gt; which real-world action is this?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those are not the same question.&lt;/p&gt;

&lt;h2&gt;
  
  
  Identity alone is not enough
&lt;/h2&gt;

&lt;p&gt;There is another failure mode.&lt;/p&gt;

&lt;p&gt;Suppose an application reuses the same logical operation ID but changes a value that affects the real-world action.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;operation: send_invoice_4821
attempt 1 destination: alice@example.com
attempt 2 destination: bob@example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those should not be treated as equivalent retries.&lt;/p&gt;

&lt;p&gt;The operation identity therefore needs to be bound to the &lt;strong&gt;effect-bearing payload&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If 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.&lt;/p&gt;

&lt;p&gt;Otherwise a deduplication mechanism can become a different kind of bug: incorrectly collapsing two distinct actions into one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The state many systems are missing: UNKNOWN
&lt;/h2&gt;

&lt;p&gt;A useful execution model has at least three outcome states:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;State&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;Safe default&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CONFIRMED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Authoritative evidence says the effect happened&lt;/td&gt;
&lt;td&gt;Return/replay the known result; do not execute again&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ABSENT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Authoritative evidence says the effect did not happen&lt;/td&gt;
&lt;td&gt;Execution may proceed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;UNKNOWN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The effect may have happened, but available evidence cannot prove which state is true&lt;/td&gt;
&lt;td&gt;Reconcile or block&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The critical rule is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;UNKNOWN is not permission to execute again.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This sounds conservative because it is.&lt;/p&gt;

&lt;p&gt;If duplicate execution could be expensive or irreversible, safety sometimes requires giving up immediate progress.&lt;/p&gt;

&lt;p&gt;That is the classic tradeoff between &lt;strong&gt;safety&lt;/strong&gt; and &lt;strong&gt;liveness&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;safety: do not accidentally create the duplicate effect;&lt;/li&gt;
&lt;li&gt;liveness: eventually complete the requested action.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If provider truth is unavailable, a high-impact operation may have to remain blocked until a human or a trusted system can resolve it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reconciliation: ask reality before repeating it
&lt;/h2&gt;

&lt;p&gt;When an outcome is ambiguous, the strongest recovery path is often &lt;strong&gt;reconciliation&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of retrying the mutation, perform a read-only check against an authoritative system.&lt;/p&gt;

&lt;p&gt;For a refund, that could mean asking the provider whether the refund exists.&lt;/p&gt;

&lt;p&gt;For a booking, check whether the reservation was created.&lt;/p&gt;

&lt;p&gt;For a message, query the provider-side message ledger if such a facility exists.&lt;/p&gt;

&lt;p&gt;The flow becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;external effect may have committed
            |
            v
         UNKNOWN
            |
            v
   authoritative lookup
       /          \
      /            \
CONFIRMED          ABSENT
   |                 |
   v                 v
do not repeat      execution may proceed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The phrase &lt;strong&gt;authoritative&lt;/strong&gt; matters.&lt;/p&gt;

&lt;p&gt;A missing local database row is not automatically proof that the external effect did not happen.&lt;/p&gt;

&lt;p&gt;Neither is a timeout.&lt;/p&gt;

&lt;p&gt;Neither is an empty cache.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ABSENT&lt;/code&gt; should require evidence strong enough to justify repeating the action.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not every agent tool needs this
&lt;/h2&gt;

&lt;p&gt;There is an obvious counterargument:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Do we really want every search, calculation, and read operation going through durable execution coordination?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;p&gt;That would add latency and complexity where there is little duplicate-effect risk.&lt;/p&gt;

&lt;p&gt;A better model is selective routing.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Route&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;DIRECT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No consequential external mutation identified&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PROTECT&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Duplicate execution could create an undesirable external effect&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;BLOCK&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The system cannot establish that execution is safe&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A web search is usually &lt;code&gt;DIRECT&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A local calculation is usually &lt;code&gt;DIRECT&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A refund, message send, booking, order creation, or deployment trigger may be &lt;code&gt;PROTECT&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A tool with conflicting or insufficient safety information may be &lt;code&gt;BLOCK&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The asymmetry matters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a false positive mostly costs latency or integration friction;&lt;/li&gt;
&lt;li&gt;a false negative can permit an unintended duplicate real-world action.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For consequential tools, conservative classification is often the rational choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  This is not a universal "exactly once" claim
&lt;/h2&gt;

&lt;p&gt;"Exactly once" sounds attractive, but it is easy to overstate when independent systems are involved.&lt;/p&gt;

&lt;p&gt;A client generally cannot atomically commit both:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;an arbitrary external provider's state; and&lt;/li&gt;
&lt;li&gt;its own local acknowledgement state&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;unless the systems share an appropriate transaction, deduplication, or reconciliation contract.&lt;/p&gt;

&lt;p&gt;So the defensible target is narrower:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;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.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those assumptions include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;stable logical operation identity;&lt;/li&gt;
&lt;li&gt;complete effect binding;&lt;/li&gt;
&lt;li&gt;durable safety state;&lt;/li&gt;
&lt;li&gt;controlled execution concurrency;&lt;/li&gt;
&lt;li&gt;an execution boundary that cannot simply be bypassed;&lt;/li&gt;
&lt;li&gt;authoritative reconciliation where ambiguity cannot otherwise be resolved.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is a safety property, not a promise that every operation will eventually succeed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Once fits
&lt;/h2&gt;

&lt;p&gt;We have been building &lt;strong&gt;Once&lt;/strong&gt;, an open-source execution-safety layer for AI agent tools and MCP integrations, around this model.&lt;/p&gt;

&lt;p&gt;The 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.&lt;/p&gt;

&lt;p&gt;The current public implementation includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TypeScript and Python SDKs;&lt;/li&gt;
&lt;li&gt;MCP support;&lt;/li&gt;
&lt;li&gt;deterministic cross-language operation identity;&lt;/li&gt;
&lt;li&gt;local durable protection;&lt;/li&gt;
&lt;li&gt;tool discovery and classification;&lt;/li&gt;
&lt;li&gt;selective &lt;code&gt;DIRECT / PROTECT / BLOCK&lt;/code&gt; routing;&lt;/li&gt;
&lt;li&gt;framework integrations;&lt;/li&gt;
&lt;li&gt;hostile-retry evidence across multiple agent frameworks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important part is the boundary of the claim.&lt;/p&gt;

&lt;p&gt;Once does &lt;strong&gt;not&lt;/strong&gt; claim universal exactly-once execution across arbitrary providers and arbitrary deployments.&lt;/p&gt;

&lt;p&gt;If authoritative truth is unavailable, the correct state may remain &lt;code&gt;UNKNOWN&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That limitation is part of the design rather than something to hide.&lt;/p&gt;

&lt;h2&gt;
  
  
  We published the full systems model
&lt;/h2&gt;

&lt;p&gt;I have now published the deeper technical treatment as a citable technical paper:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reliable Execution of Consequential AI Agent Actions Under Retries and Ambiguous Outcomes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jamie Oswald — Once Research&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Published:&lt;/strong&gt; 26 September 2026&lt;br&gt;&lt;br&gt;
&lt;strong&gt;DOI:&lt;/strong&gt; &lt;a href="https://doi.org/10.5281/zenodo.22969881" rel="noopener noreferrer"&gt;10.5281/zenodo.22969881&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The paper covers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the formal one-effect safety property;&lt;/li&gt;
&lt;li&gt;trust assumptions;&lt;/li&gt;
&lt;li&gt;ambiguous-outcome failure states;&lt;/li&gt;
&lt;li&gt;logical identity versus attempt identity;&lt;/li&gt;
&lt;li&gt;effect binding and payload drift;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CONFIRMED / ABSENT / UNKNOWN&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;reconciliation;&lt;/li&gt;
&lt;li&gt;selective tool protection;&lt;/li&gt;
&lt;li&gt;related techniques including idempotency keys and durable workflow systems;&lt;/li&gt;
&lt;li&gt;hostile-retry evidence;&lt;/li&gt;
&lt;li&gt;threats to validity;&lt;/li&gt;
&lt;li&gt;falsifiable failure criteria.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are building agents that can change external state, the question I would ask is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If this tool times out after the external effect commits, what prevents the retry from doing it again?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If the answer is only "the framework retries carefully," there is probably another reliability boundary worth examining.&lt;/p&gt;




&lt;h3&gt;
  
  
  Links
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Technical paper:&lt;/strong&gt; &lt;a href="https://doi.org/10.5281/zenodo.22969881" rel="noopener noreferrer"&gt;https://doi.org/10.5281/zenodo.22969881&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Once research page:&lt;/strong&gt; &lt;a href="https://onceexec.com/research/" rel="noopener noreferrer"&gt;https://onceexec.com/research/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Once:&lt;/strong&gt; &lt;a href="https://onceexec.com/" rel="noopener noreferrer"&gt;https://onceexec.com/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/stringsofthemind-oss/once" rel="noopener noreferrer"&gt;https://github.com/stringsofthemind-oss/once&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>devops</category>
      <category>security</category>
    </item>
  </channel>
</rss>
