Skip to content
Back to journal

An Undo Is a Product Contract

For consequential changes, decide what can be reversed, what needs confirmation, and how customers can prove the outcome without guessing.

Deleting a document, removing a teammate, disconnecting an integration, cancelling an order, or changing a billing setting may take one tap. The consequence is rarely that small.

When a product treats every dangerous action as a modal with a red button, it asks people to slow down without actually helping them understand the decision. When it treats every action as harmless, it turns ordinary slips into support requests, lost work, and mistrust.

The better question is not “Should we show a confirmation dialog?” It is: what recovery promise can this product honestly keep?

A dependable product makes consequential change predictable: it shows the real scope, uses reversal when it can, asks for deliberate confirmation when it cannot, and leaves a receipt people can return to.

That is a product contract. It needs decisions from product and design, an honest data model from engineering, and tests that prove the result is recoverable in the ways the interface promises.

Start by classifying the consequence

Not every action deserves the same interruption. Saving a draft, muting a notification, and removing a file forever have different costs of being wrong.

Before choosing an interaction, write down what changes and who can be affected:

  • Object: Is it one comment, a whole workspace, a payment method, or an integration with data flowing in both directions?
  • Reach: Does the change affect only the person acting, or colleagues, customers, billing, and connected systems too?
  • Recoverability: Can the exact prior state be restored? Can it be restored by the person, support, or nobody?
  • Time: Is a short grace period safe, or does the action have to take effect immediately?
  • Evidence: What should a person be able to see later to understand what happened?

The goal is not to make a taxonomy for its own sake. It is to stop the interface from promising an “undo” that only puts an item back in a list while background cleanup, access removal, or a third-party API call has already made the original outcome impossible.

This is also an accessibility requirement for many important web actions. WCAG 2.2 Success Criterion 3.3.4 requires legal, financial, and user-controlled data changes to be reversible, checked for errors with a chance to correct them, or confirmed before finalization. Its intent is practical: serious mistakes are harder for everyone to detect and recover from under real conditions.

Prefer a real reversal to a ritual warning

If an action is common and genuinely reversible, a lightweight undo is often better than a confirmation. It lets people keep moving while preserving control.

But “genuinely” does important work. Define the policy before the interface:

  • What exact state is restored: the object, its contents, memberships, related settings, and permissions?
  • How long is the action reversible, and where can someone find it after a toast disappears?
  • What is intentionally not restored, such as a new edit made after the removal or a remote action that already completed?
  • What happens when two people act on the same thing during the recovery window?

The implementation needs the same precision. A soft-delete marker, a versioned record, or an append-only change log may support restoration; a hard delete cannot. Side effects need their own plan. If deleting a workspace revokes access, cancels jobs, and tells another service to remove records, “restore” must either restore those capabilities safely or say plainly that it cannot.

Apple’s undo guidance makes an often-missed point: people should be able to predict what undo targets and see its result. A control that silently changes an off-screen record invites repeat actions and confusion. Name the thing that will return, then make the returned state visible.

Confirm the irrecoverable decision, not every click

When a result cannot be reversed reliably, confirmation is appropriate. It should add information and choice—not just friction.

A useful confirmation answers four questions before the person commits:

  1. What will happen? Use the action’s real verb: delete, cancel, disconnect, publish, or remove access.
  2. What is in scope? Name the workspace, file, plan, or affected people. If a count matters, show it.
  3. What will not be recoverable? Be concrete about retained records, removed data, external effects, or the absence of a restore path.
  4. What can happen instead? Offer a safe alternative only when it is real: archive, disable, export, save as draft, or cancel.

Avoid confirmation copy that sounds certain while the server may reject the action, queue it, or complete only part of it. A confirmation is permission to attempt a state transition; it is not a receipt that the transition happened.

Apple’s alert guidance draws the right distinction: do not interrupt people for common actions that are undoable, but do use an alert when an uncommon destructive action cannot be undone. That keeps warnings meaningful. A product that asks “Are you sure?” after every routine deletion teaches people to dismiss the one warning that mattered.

Make the backend contract match the screen

The customer-facing choice is only trustworthy if the service enforces the same rules.

Model a consequential action as an explicit transition, not as an unguarded request. The server should determine whether the actor still has authority, whether the target is in a state that can change, and whether the requested change was already processed. That protects the outcome when a person double-clicks, a mobile connection retries, or two administrators act at once.

For a reversible deletion, a compact model might be:

| State | Customer promise | Engineering guard | | --- | --- | --- | | Active | Available to use | Normal authorization and version checks | | Pending removal | Hidden or paused; restore is available until a stated time | Record the actor, timestamp, recovery deadline, and idempotency key | | Restored | Available again with the documented scope | Restore only if the recovery policy still allows it; show the resulting state | | Finalized | Permanently removed or detached | Run irreversible cleanup once, with an auditable result |

The exact states vary by product. The discipline does not. Keep the user-visible status, service state, background work, and audit entry connected by a stable identifier. Then support can answer “what happened?” without reconstructing a story from logs, and customers can tell whether they need to do anything next.

For actions with money, access, or compliance implications, be especially careful with partial success. If a cancellation succeeds locally but a provider still has work in flight, say that. If a removed member retains access until a session expires, do not show “access removed immediately.” Honest intermediate states are better than a confident false result.

Give people a durable receipt

The action is not complete from a customer’s perspective when the button changes. They need a result they can find later.

That receipt may be an activity entry, confirmation email, account history row, or a clearly labeled state in the relevant screen. It should name the action, target, time, and next available recovery step. It should not expose internal IDs, security-sensitive details, or a wall of implementation language.

This is where product quality and operational quality meet. A durable receipt reduces repeated submissions, makes handoffs to support faster, and gives engineering evidence when an edge case violates the promised lifecycle. It also lets the team distinguish an intentional customer action from a failed request that merely looked successful.

Test the promise across the unhappy paths

The happy path proves a button works. The contract is proven in the paths that create uncertainty.

For each consequential action, test at least:

  • Scope: one item, many selected items, nested content, and shared content.
  • Authority: a permitted actor, a recently removed actor, and a person who only has read access.
  • Timing: one submission, a double submission, an expired undo window, and a restore immediately before finalization.
  • Concurrency: a second administrator changes the target while the first person is confirming or undoing.
  • Failure: a network interruption, a queued worker failure, and a partially completed external side effect.
  • Proof: the final visible state and history match the service record without leaking sensitive data.

Put the decision in release criteria as well. Product should approve the recovery boundary. Design should check that the consequence is understandable without relying on color or a fleeting toast. Engineering should verify authorization, idempotency, and cleanup. Quality should test the matrix using realistic roles and data.

Make change feel safe because it is legible

People will make mistakes. The product does not earn trust by pretending otherwise or by surrounding every button with a warning. It earns trust by letting people understand the consequence, reverse the changes that can be reversed, and find a truthful outcome when they return.

Choose a recovery policy before drawing the dialog. Implement the policy as a state transition, not as decorative UI. Then test the moments when timing, permissions, and external systems disagree.

That makes an undo more than a convenience. It makes every consequential change a promise the product can keep.

If your product needs strategy, design, engineering, and quality to agree on the consequences behind a critical action, bring BugSquad the challenge.