How to stop an automation that still has work to do
Retire intake, accepted jobs and external authority in a deliberate order, so a late event cannot revive an obsolete process.
Follow a purchase request whose destination changes while the reviewer is reading it, and the server rule that keeps the final action tied to the decision.
The reviewer has approved £450 to destination A. The system is about to send £450 to destination B, and its audit trail may still look complete. In this example, nobody has tried to deceive anyone: the requester corrected the destination while the reviewer was reading. An approval attached only to request P42 cannot tell the server which of those two purchases the person meant to authorise.
That ordinary edit is the part worth following. The screen can be accurate when opened and stale when its button is pressed. A live notification may help the reviewer notice, but it cannot guarantee that they saw the change. Approval needs to identify the particular values considered, then keep execution attached to those values. Otherwise the person and the application can both do what they think is right and still disagree about what was approved.
OWASP’s transaction-authorisation guidance asks that people can identify significant transaction data and that the process protect it against modification. It also describes invalidating or restarting authorisation when that data changes. [1] For P42, this means identifying the values the reviewer saw and checking that they still define the proposed purchase when approval is accepted. A button alone supplies neither relationship.
We will use an original synthetic purchase request, P42. Its material fields are currency, amount, destination and whether the commitment recurs. Its internal note is separate. This is a policy for the example, not a universal definition of financial materiality or a recommendation about a particular payment product. The point is to make the decision’s object explicit enough that a concurrent edit can be detected.
Version 7 contains GBP 450.00, destination A and a one-off purchase. Store an immutable review snapshot with those values and a material-version identifier. The screen renders that snapshot and includes its identifier with the eventual decision. A request ID alone names the ongoing conversation; the snapshot names the proposed action the person is currently considering.
Then destination B is saved as material version 8. The pending review of version 7 can no longer authorise the current purchase. If the reviewer submits the old snapshot, the server rejects it before creating an execution command. Show what changed and retain any comment they typed. They should not have to reconstruct a whole review to learn that the destination, rather than the amount, was amended.
The old screen can remain available while the reviewer reads, provided the server detects the changed material version when the decision is submitted. A live update may warn them earlier, but notifications can be delayed or missed. The server must therefore enforce the condition independently of browser updates. This preserves a clear outcome for an ordinary stale screen as well as for an altered submission.
PostgreSQL’s conditional UPDATE mechanism illustrates the shape of this guard: update the permitted request state only where the expected material version still matches, and inspect the affected-row result. [2] A failed match means this decision did not acquire the state it expected. Reloading is appropriate; removing the condition so the approval can succeed is not. A real design must also coordinate approval creation and request transition in the chosen transaction.
A synthetic purchase request changes its payment destination between review and submission. The server rejects approval of the old material version.
Follow the labelled arrows. On a narrow screen, scroll sideways if needed.
Invalidating every approval after every edit is simple, but it can create unnecessary work. In a separate branch of our example, someone adds an internal note while the four material values remain unchanged. The application could preserve the material version and allow the existing review to complete, provided the note truly has no effect on the proposed action or the reviewer’s decision under the agreed policy.
The apparently harmless note needs a closer look. If it contains the only explanation of a recurring obligation, a delivery restriction or a new concern, changing it can change the decision just as surely as changing the amount. Calling a database field nonmaterial does not settle that. Work out what the reviewer needs to know, then include that information in the snapshot or require another review when it changes.
Use the policy to compare other edits. Changing £450 to £500 is material. Changing GBP to another currency is material even if the digits stay 450. Turning a one-off purchase into a subscription changes the commitment. Correcting harmless formatting in an internal reference may not. Put these examples beside the implementation so future changes do not quietly widen what an old decision is taken to cover.
There is a trade-off between broad snapshots that are easy to reason about and selective material versions that reduce repeated review. A small process may reasonably invalidate on any request change. A busier one may need a more precise boundary. Either approach should be explainable to the reviewer, and neither should silently reuse approval merely because the request still has the same ID.
The snapshot needs to supply the execution command, too. Suppose the server accepts version 7 at destination A and saves its approval. Before the executor runs, someone changes the request to B. If command construction rereads that mutable request, the accurate approval history now sits beside the wrong purchase. Build the command from the reviewed values instead. The version check protects acceptance of the decision; carrying the snapshot into execution keeps a later read from reopening the destination choice. An attachment showing A would help an investigator explain the mistake, but it would not prevent B entering the command.
Give that command an identity and record its approval reference, actor and intended effect. A duplicate click should not create a second independent command. A background executor can then claim the named work and establish its result. Where an external service is involved, its retry and outcome rules still matter; freezing the right payload does not by itself make the remote effect exactly once.
Check the acting person’s current permission as well. An approval snapshot describes what was approved, but the application may also need to establish that the reviewer remains authorised when the decision is accepted, and that the executor is allowed to perform the resulting action. OWASP’s authorisation guidance recommends validation on requests rather than assuming an earlier check covers every later path. [3] Keep those checks distinct from snapshot matching.
Similarly, state what expiry means. A time limit might require renewed review because prices, destinations or business circumstances may change. It should not be a decorative timestamp the execution path ignores. Bind the execution to the valid decision and its policy, with a clear outcome when the decision is stale, withdrawn or no longer eligible. The operator needs to know which question must be reopened.
P42’s reviewed material snapshot must also be the source of its execution command.
Follow the labelled arrows. On a narrow screen, scroll sideways if needed.
The screen should foreground the fields that affect judgement: what is being purchased, why, the amount and currency, the destination and any continuing commitment. Include the source request and material differences from a previous version. A dense page of every stored field is not automatically better context. Reviewers need a clear account of this decision, with a route to evidence when they need to inspect it.
Make refusal and return useful outcomes. A reviewer asking for confirmation of a destination should leave a reason, a responsible person and a next step. Pending is not enough if everyone reads it as somebody else’s work. When the request returns, show the relevant changes rather than expecting the reviewer to remember precisely what was doubtful in the previous version.
Try the destination race alongside a note-only edit, an amount change and a duplicate submission. Then follow the interval after approval, before the external executor runs. Can a later value slip into the command there? Can the operator trace the actual payload to the screen the reviewer saw? These questions reveal what the control protects. The number of approval prompts tells us rather less, even if every one was duly clicked.
A review screen cannot supply specialist purchasing judgement or independently verify a destination just by displaying it neatly. Those jobs may still need a person and a separate process. What this application can do is preserve the values considered and prevent a later edit from substituting a different purchase. For P42, the record should answer the plain question a reviewer would ask afterwards: did the command use A or B, and which decision covered it?
Working on a workflow like this? Hamsa helps finance and operations teams connect their tools and handle the exceptions, starting with one workflow.
See the Payment Operations PilotPrimary sources behind this article. Living documentation may change.

Practical engineering. A human perspective.
More about Hamsa Software and the person behind it. Editorial notes.