Specify What Undo Restores After an Agent Adds an Action

Drafted and reviewed using AI assistance.

On this page

Specify an Undo action by naming the operation it reverses, the fields it may change, and the later work it must preserve. Then describe what happens if restoration conflicts with another action, fails, or has an unknown result.

“Add Undo after Archive” leaves an important question unanswered: does Undo restore the whole old item, or only reverse its archived status? If someone edits a label after archiving, restoring an old snapshot could erase that useful edit.

This guide works through one harmless fictional list item. All states, event names, messages, and expected outcomes are original teaching materials. They are proposed behavior, not captured software output, a customer incident, or an implemented product feature.

Begin with the item and the operation

The fictional application has active and archived views. Archiving an item moves it out of the active view without deleting it. People can still edit an archived item's label in the archived view.

Our item is N17, titled Outline welcome note. Its initial label is Draft. The archive action changes its archived status; it does not change the title or label.

Here is the shared history before anyone requests Undo:

Revision Event Archived? Label Current archive action Visible result
r0 Initial state No Draft None N17 is in the active list
r1 A1: archive N17 Yes Draft A1 N17 moves to archived items; Undo refers to A1
r2 L1: edit its label in the archived view Yes Ready A1 N17 stays archived and now displays Ready

The revision and action names make the example precise. They describe the history the design must account for; they are not instructions to add those exact database fields or adopt a particular storage architecture.

The requested Undo targets A1 on N17. It does not mean “restore every field to r0” or “unarchive whichever item is selected now.”

Choose the restoration boundary

For this example, choose a field-specific policy: reverse A1's archived status while preserving the latest label and title. Keep the same item identifier. Other items and the list's existing sort policy remain unchanged.

Candidate policy Result after r2 Decision in this example
Restore the full r0 item snapshot Active item with the old Draft label Reject: it loses L1's later edit
Reverse the named archive effect Active N17 with its latest Ready label Choose, if A1 is still the archive action being reversed
Offer a general Unarchive command on the current item Makes a new decision about the item's present state Keep separate from undoing A1

The distinction in the last row matters. A person may choose to unarchive an item again after reviewing its current state. That is a new instruction. An old Undo control should not silently acquire that meaning.

The success branch continues from r2:

Revision Event Archived? Label Current archive action Required visible result
r2 Before recovery Yes Ready A1 N17 is archived with Ready
r3-success U1: Undo A1 is confirmed No Ready None N17 returns to the active list with Ready retained

The complete expected item values are:

{
  "id": "N17",
  "title": "Outline welcome note",
  "label": "Ready",
  "archived": false
}

This JSON is a manually written acceptance example, not a server response. Returning to the active list also does not promise a previous pixel position: the application should use its normal current sort order.

Check whether a later action owns the same field

Preserving an unrelated label edit is only half the problem. A later action may have changed the archived status itself.

Consider this alternative branch from r2. It does not happen after the success branch above:

Revision Event Archived? Label Current archive action Required interpretation
r2 Shared starting point Yes Ready A1 Original archive is still current
r3-conflict R2: someone manually unarchives N17 No Ready None A later action has changed archive membership
r4-conflict A2: someone archives N17 again Yes Ready A2 A2, a new decision, now owns the archived state
r4-conflict, unchanged Someone requests the old Undo A1 Yes Ready A2 Refuse the old reversal; preserve A2

At r2 and r4-conflict, the visible archived flag has the same value. That equality does not make the histories equivalent. Unconditionally changing it to false would override the later decision A2.

The chosen policy therefore checks the relationship between the requested reversal and the current archive action when recovery is applied. If A1 is no longer the applicable action, leave the item unchanged and explain the conflict:

This item was archived again. Review its current state.

If the application cannot establish the needed history, the brief should not invite the agent to guess from the current boolean. Ask it to identify the evidence gap and propose a conservative refusal or another explicit policy for review.

An Undo link appearing on screen is not sufficient evidence that its original action is still eligible. The design must also account for changes occurring between displaying the control and applying recovery.

Give failure and uncertainty different outcomes

A recovery request is not a recovered item. Define the interface state while the request is pending, and distinguish a confirmed rejection from a missing result.

These are two more alternatives starting from r2:

Branch and event Authoritative item state Required feedback Next step
Confirmed failure: recovery is explicitly rejected before any state change Still r2: archived, Ready, A1 “Could not restore. The item is still archived.” Keep the item unchanged; let the person inspect the failure
Unknown outcome: no recovery result is received Unknown; in this isolated example it could remain r2 or have reached r3-success “Restore status unknown. Check the item before another action.” Establish the current item and target-action status before another change

While waiting, show Restoring… and prevent another submission of the same Undo from that control. Do not announce Restored merely because the request was sent.

If the result is missing, the last displayed archived row is only the last confirmed view. It does not establish that restoration failed. Conversely, a disappearing row produced by an optimistic display update is not authoritative confirmation of success.

This example intentionally stops short of defining a retry protocol. The next action is to establish status, not to blindly issue another unarchive operation. If the product cannot resolve that status, keep it unknown and offer a clear way to inspect the item rather than inventing a successful result.

Keep cancellation, Undo, and deployment rollback separate

These actions answer different questions:

Action Question it answers in this example What it does not establish
Cancel a request Can pending work be asked to stop? That an archive already applied has been reversed
Undo A1 Can this particular archive effect be reversed under the chosen current-state rules? That every later edit should be discarded
Roll back a software deployment Which application release should run? That N17's data has returned to a particular historical state

MDN documents AbortController as a way to communicate cancellation to asynchronous work, including fetch-related operations. It does not define the list item's restoration policy. Treat stopping pending work and reversing an applied action as separate application requirements.

Likewise, changing a software release is not evidence that an item was restored. Any intended data restoration needs its own scope and verification. A deployment procedure should not be used as the user-facing meaning of this list's Undo button.

Copy this precise agent brief

Investigate and plan Undo for one archive action in the selected list
application. This first step is a plan and acceptance examples, not edits
or a production operation.

Object and target:
Item N17, title "Outline welcome note".
Undo must refer to archive action A1 on N17, not the current selection
and not any later archive action on the same item.

Shared history:
r0: archived=false, label="Draft".
A1 -> r1: archived=true, label="Draft".
L1 -> r2: archived=true, label="Ready".
Labels may be edited in the archived-items view in this example.

Chosen recovery policy:
Reverse only A1's archive effect if A1 is still the applicable archive
action when recovery is applied. Preserve the latest title and label,
the item ID, other items, and the existing list sort policy.
Do not restore an entire old item snapshot.

Required cases:
1. From r2, confirmed Undo A1 gives N17 archived=false, label="Ready".
2. From r2, a later manual unarchive followed by archive A2 means old
   Undo A1 makes no change. Show:
   "This item was archived again. Review its current state."
3. An explicit rejection before mutation keeps r2 unchanged. Show:
   "Could not restore. The item is still archived."
4. A missing result remains unknown. Show:
   "Restore status unknown. Check the item before another action."
   Establish the item and target-action status before another change.

While pending:
Show "Restoring…" and prevent another submission from the same control.
Show success only on an authoritative result for this item and action.
A cancellation request does not count as reversal or success.

First inspect the current archive operation, item update behavior,
history/status evidence, and feedback states. Cite the relevant files.
Explain how the design preserves later unrelated edits and avoids
overwriting A2, including changes during the recovery request.

If the required history or safe application condition cannot be
established, report that gap and propose a conservative behavior for
review. Do not infer eligibility from archived=true alone.

Return a bounded implementation plan and checks for the four cases.
Mark expected outcomes separately from any actually performed checks.
Do not edit files, add infrastructure, call production services,
restore real items, publish, or deploy in this investigation step.

The request defines observable results while leaving the implementation open. The agent can inspect existing history and update mechanisms before proposing how to enforce the condition. It does not need to invent a general-purpose recovery system for every action in the application.

Use error-prevention guidance within its scope

W3C's explanation of WCAG 2.2 Success Criterion 3.3.6, at Level AAA, discusses reversible submissions, checking input, or review and correction before final submission. It is informative guidance for that specific criterion. It does not prescribe this example's archive-conflict policy or establish overall WCAG conformance.

For the list feature, the practical decision remains concrete: identify the action being reversed, preserve later independent work, refuse a conflicting old reversal, and tell the person whether recovery is confirmed, rejected, or unknown. Those are the requirements an implementation and its checks must address.