ai-agentsreliabilityarchitecturerollbacksdurable-workflowssafety

Designing Reversible AI Agents: Rollbacks, Compensating Actions, and Safe Failure

By John Babich10/15/202610 min read
Advanced
Designing Reversible AI Agents: Rollbacks, Compensating Actions, and Safe Failure

Designing Reversible AI Agents: Rollbacks, Compensating Actions, and Safe Failure

An agent does not need to be malicious to cause damage. It only needs to be helpful in the wrong order.

Imagine a customer-operations agent that issues a refund, updates the account, cancels a shipment, and sends a confirmation. The first three steps succeed. The notification tool times out. The agent retries the whole workflow because it cannot tell what committed.

Now the customer has two refunds, an uncanceled replacement order, and an email confidently describing a state that does not exist.

The model did not hallucinate. The system failed to manage side effects.

Production agents need more than retries. They need reversibility: a deliberate architecture for knowing what changed, deciding whether it can be undone, and restoring a safe business state when a multi-step plan breaks.


TL;DR

  • Classify every tool action as read-only, naturally reversible, compensatable, or effectively irreversible.
  • Record intent before execution and record a durable receipt after execution.
  • Give every write an idempotency key, a verification function, and a recovery owner.
  • Register compensation before performing the action it may need to undo.
  • Compensation restores business consistency; it does not necessarily erase history.
  • Put approval gates before irreversible actions, not after the agent has already committed them.
  • Test failures between every pair of steps. The unhappy path is the product.

Retry is not rollback

Retries answer one question:

Should we attempt the same operation again?

Rollback answers another:

How do we return the system to an acceptable state after some operations already succeeded?

Those are different problems.

If a read-only inventory lookup times out, retrying is usually harmless. If a payment call times out after the processor accepted it, retrying without an idempotency key may charge twice. If an agent publishes a confidential document, no API can make every recipient forget it.

A reliable agent must reason about effects, not just tool responses.

This is familiar territory in distributed systems. The saga pattern coordinates a sequence of local transactions and runs compensating actions when later steps fail. Temporal's documentation describes each step as having a compensation that reverses its effect, while durable workflow state tracks progress and recovery. (Temporal design patterns)

Agents make the need more urgent because the sequence is often chosen at runtime. The workflow is not always a static graph. A model may select a tool, inspect the result, revise the plan, and create a path that no developer explicitly wrote down.

The runtime therefore has to enforce reversibility as a contract.

Start with an effect taxonomy

Do not give an agent a flat list of tools. Give it an effect-aware catalog.

Action class Example Recovery approach
Read-only Search orders Retry with bounded backoff
Naturally reversible Add a label Remove the exact label
Compensatable Capture a payment Issue a refund and reconcile fees
Time-bounded reversible Schedule a campaign Cancel before dispatch time
Irreversible Send secrets externally Prevent, contain, and escalate

The distinction between reversible and compensatable matters.

Removing a newly added label can restore the exact prior state. Refunding a payment does not. Fees may remain. Settlement may take days. A customer may have seen the charge. The ledger must preserve both transactions.

Compensation means restoring an acceptable business invariant, not pretending the action never happened.

Add effect metadata to every write-capable tool:

type EffectProfile = {
  class: "reversible" | "compensatable" | "irreversible";
  approval: "none" | "policy" | "human";
  idempotency: "required" | "supported" | "none";
  compensationTool?: string;
  verificationTool: string;
  reversalWindowSeconds?: number;
};

The model can use that metadata while planning, but the runtime must enforce it. A prompt instruction is not a transaction coordinator.

The reversible execution loop

A safe agent write should pass through seven stages.

1. Plan

The agent proposes an action and identifies the business goal. "Call refund_payment" is not enough. The plan should state the invariant it is trying to restore, such as "customer balance equals the amount paid for delivered items."

2. Validate preconditions

Re-read the current state immediately before execution. The account may have changed since the agent planned the action.

Useful checks include:

  • expected object version
  • current workflow status
  • available balance or inventory
  • permission scope
  • reversal-window deadline
  • absence of an existing operation with the same idempotency key

3. Record intent

Write a durable intent record before the external side effect:

{
  "runId": "run_814",
  "stepId": "step_refund_3",
  "operation": "refund_payment",
  "target": "payment_392",
  "amount": 84.50,
  "idempotencyKey": "run_814:step_refund_3",
  "compensation": "reverse_refund_credit",
  "status": "prepared"
}

If the process crashes after this record but before the call, recovery can determine that execution is uncertain rather than blindly starting over.

4. Register compensation

Register the recovery action before performing the side effect. This ordering sounds backward until the process dies one millisecond after the write succeeds.

Temporal's saga guidance uses the same principle: compensations are stored before the corresponding activity so a crash cannot leave a successful action without a known recovery path. (Temporal saga pattern)

5. Execute

Call the tool with a stable idempotency key. Never derive the key from the model's wording or a timestamp alone. It should represent the business operation and survive retries, restarts, and worker changes.

6. Store the receipt and verify

Do not equate an HTTP 200 with business success. Store the provider's receipt, then verify the resulting state through an independent read when the risk justifies it.

The receipt should include:

  • provider operation ID
  • exact arguments or a protected hash
  • committed timestamp
  • resulting object version
  • cost or financial amount
  • verification result

7. Continue, compensate, or escalate

If the next step fails, policy chooses among three paths:

  • retry forward because success remains likely
  • compensate completed steps in dependency-aware order
  • pause for a human because neither path is safely automatic

Compensation order is a graph problem

Simple tutorials say to undo actions in reverse order. That works for a linear sequence:

reserve inventory -> charge payment -> create shipment

If shipment creation fails, refund the payment and release inventory.

Real agent plans branch. An agent may update a CRM record and create a support task in parallel, then use both results to modify an account. Recovery must follow dependencies, not wall-clock completion order.

Represent committed effects as a graph. A compensation can run only when every effect that depends on it has been handled. Independent compensations may run concurrently, but financial or rate-limited operations may need serialization.

The rule is:

Reverse causal order, not merely chronological order.

Idempotency is non-negotiable

Agents retry for many reasons: timeouts, worker restarts, lost acknowledgments, model revisions, and humans clicking "resume." Every one can duplicate a side effect.

An idempotent operation produces one business effect when requested repeatedly with the same key.

Good idempotency requires more than attaching a header:

  • The key must be stable across the entire retry lifetime.
  • The server must store the result associated with the key.
  • Reuse with different arguments must fail loudly.
  • The retention window must exceed the workflow's recovery window.
  • The caller must be able to retrieve the prior result.

When a third-party API lacks idempotency, place a command ledger in front of it. The ledger cannot eliminate every ambiguous network failure, but it can serialize intent, detect duplicates, and route uncertain outcomes to reconciliation.

Design for three kinds of uncertainty

The action definitely failed

No external effect occurred. Retry or choose another route.

The action definitely succeeded

Persist the receipt and proceed.

The outcome is unknown

This is the dangerous state. A timeout means "no answer," not "no effect."

The recovery policy should query by idempotency key or business identifier. If verification is impossible, stop autonomous execution. A human should reconcile the external system before the agent continues.

Do not let the model guess which reality is more likely.

Irreversible actions need a different architecture

Some effects cannot be meaningfully compensated:

  • disclosing a secret
  • deleting the only copy of data
  • sending a legal notice
  • publishing market-moving information
  • transferring an asset outside a recoverable network
  • triggering physical machinery

The answer is not a more creative rollback. The answer is a stronger boundary before execution.

Use one or more of these controls:

  • generate a draft instead of sending
  • write to a reversible staging area
  • enforce a cooling-off delay
  • require two-person approval
  • limit values and destinations
  • replace destructive deletion with quarantine
  • use expiring links instead of raw data transfer

This aligns with the broader principle in Agent Permissions Are Product Design: a capability should be shaped so the safe path is also the easiest path.

Make recovery visible to users

Users do not need the raw saga log, but they do need an honest status.

Avoid collapsing every incomplete run into "failed." Distinguish:

  • Paused: waiting for input or approval
  • Retrying: no unsafe partial state detected
  • Reconciling: outcome of an external action is uncertain
  • Compensating: restoring business consistency
  • Needs attention: automated recovery is unsafe
  • Recovered: safe state restored, with residual effects disclosed

For long-running work, this status model belongs in the product interface, not only in operations logs. The Agent Harness should expose checkpoints and receipts so a human can understand what happened without reconstructing the run from chat history.

Test the spaces between steps

Happy-path tests prove almost nothing about reversibility.

For a workflow with N write steps, inject failures:

  • before each step
  • after the external commit but before receipt storage
  • during verification
  • during every compensation
  • after compensation commits but before acknowledgment
  • while a human approval is pending
  • during process and region restarts

Then assert business invariants, not internal status codes.

For an order workflow, useful invariants might be:

captured payment <= fulfillable order value
reserved inventory belongs to an active order
every refund references one captured payment
every external effect has a durable receipt
no terminal run remains in an unknown state

Also test the ugly case: compensation fails. Recovery actions use the same unreliable networks and services as forward actions. They need idempotency, retries, observability, and an escalation path too.

Metrics that reveal recovery quality

Track more than completion rate:

  • ambiguous-outcome rate
  • duplicate-effect rate
  • compensation success rate
  • median time to safe state
  • percentage of writes with verification receipts
  • manual reconciliation rate
  • irreversible actions attempted and blocked
  • residual-cost rate after compensation

An agent that completes 95% of runs but leaves 2% in an unknown financial state may be worse than one that completes 85% and fails cleanly.

Implementation checklist

  • Classify every tool's side effects.
  • Define a business invariant for each workflow.
  • Require stable idempotency keys for writes.
  • Persist intent before execution.
  • Register compensation before the corresponding action.
  • Store provider receipts and verify consequential effects.
  • Model ambiguous outcomes explicitly.
  • Reverse by dependency order.
  • Put approvals before irreversible effects.
  • Make compensation status visible.
  • Inject failures between every workflow step.
  • Alert when recovery exceeds its time budget.

The bottom line

The most trustworthy agent is not the one that never makes a mistake. That agent does not exist.

It is the one that knows what it changed, can prove which effects committed, and has a tested path back to a safe state.

Retries make an agent persistent. Reversibility makes it responsible.


Further reading

Related Tools

Useful tools for this topic

If you want to turn this article into a concrete next step, start with one of these.

Subscribe to AgentForge Hub

Get weekly insights, tutorials, and the latest AI agent developments delivered to your inbox.

No spam, ever. Unsubscribe at any time.

Loading conversations...