An approval schema is good at naming what a human authorized: the tool, the arguments, the reviewer, the timestamp. It is silent about execution. The moment execution begins, two facts start changing in ways the approval record does not capture: how many times the action has been attempted, and whether the outside system has already accepted it.
That gap is where duplicates live. A timeout on a payment API tells you only that the caller stopped waiting, not whether the charge posted, a distinction retry logic has to assume the worst about why classic retry logic misleads you here. In a normal service this ambiguity is manageable. In an agent loop it is worse, because the retried step is a non-deterministic model call that may choose a different action the second time.
The general fix is old: any request that changes state should produce the same result however many times it runs, the property Temporal's write-up on idempotency and durable execution defines as idempotent. For agents the twist is that the thing you must make idempotent is not the model call. It is the tool execution on the other side of a human gate.
So keep two records, separate and linked. The approval record is evidence for the reviewer and the auditor. The execution record is state for the runner: a key, a state, a result, a timestamp. The article on idempotency for agents shows the incident shape that produces four refunds from one approval when the runner wakes four times and finds the approval flag still true.



