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.
Bind an assistant’s approval to the action, target and material revision, then enforce that binding when the write happens.
The reviewer approved moving a delivery from morning to afternoon at the address shown. Before execution, someone changes that address. The old approval still exists, but it now sits beside a different practical decision. The service has to decide whether the change matters before applying it to the new order revision. The person’s ability to edit deliveries is not an answer to what they actually agreed to change.
Permission checks are often presented as a question about who may use a tool. That is necessary and incomplete. A person may be allowed to edit delivery instructions without having approved this particular revision, destination or effect. Reusing that approval for a different proposal would widen the permitted effect beyond the decision the colleague saw on screen.
Consider a fictional order O-52 at revision 12. The assistant proposes changing its delivery window from morning to afternoon at the existing address. The reviewer approves proposal P-9. Before execution, the address changes and the order becomes revision 13. The old approval should not silently authorise a change against this newly edited order. It should require the application to establish what is still valid.
The model may notice the changed address, but the execution service needs to catch it whether or not the assistant does. Give it a stored proposal tied to the material order state and check current permission when the write happens. A useful refusal test then asks the assistant to proceed confidently with the stale proposal. The outcome should depend on the service’s checks, rather than the persuasiveness of the request it receives.
A proposed action record can include the authenticated actor, tenant, target order, expected revision, operation and proposed values. Add an expiry and a unique approval identity if the workflow needs them. The reviewer sees the relevant current values and the exact delta. The execution request refers to that stored proposal rather than supplying a fresh collection of model-generated arguments beneath an old approval badge.
For P-9, the stored record identifies O-52, revision 12 and the delivery-window change. It does not grant permission to change the address, refund the order or apply the afternoon window to every open order. Those are different actions. A broad tool such as update_order may expose several fields, but the approved envelope should constrain which ones can be used for this decision.
A checksum can show that proposal content changed. It cannot tell the service who approved it or whether their permission still applies. Retrieve the trusted proposal and check the authenticated actor’s current rights. A caller sending modified values with a hash has supplied two pieces of data, not a new basis for authority. Keep the approval binding where the application can enforce it rather than delegating trust to the shape of the submitted arguments.
Keep the actor identity out of the model’s discretion. A tool argument saying approved_by=manager is data supplied by a caller. It is not an authenticated manager session. OWASP’s authorisation guidance recommends validating permissions on every request and denying access by default. For assistant actions, that request is the actual execution, including a resumed job after the original conversation has ended.
Suppose the service reads O-52 revision 12, checks P-9 and then performs an unconditional update. A concurrent edit can occur between the read and the write. Checking once at the beginning did not ensure that the approved revision was still current when the change happened.
A local database can enforce the expected revision through an appropriate transaction. An illustrative update requires the order identity and revision, advancing that revision only when one row matches. No changed row means a conflict requiring refreshed evidence, rather than successful completion. Consuming the approval belongs in the same transaction so a guarded order update cannot succeed while leaving its authorisation available for another use.
Approval consumption must also be conditional. Two callers can present P-9 concurrently; both must not pass a separate “unused” read and then write. The transaction needs to establish one valid use, apply the guarded change and commit both together, rolling back if either precondition fails. The short sketch below shows the revision rule, not every required statement in that transaction.
At an HTTP boundary, a provider may offer a conditional request using a strong entity tag and If-Match. MDN describes its use in preventing lost updates and the failed-precondition response when the tag does not match. That is a provider capability to verify, not a feature an integration can assume exists because it would be convenient.
Choose the revision’s scope carefully. A new internal note might invalidate a review unnecessarily; a changed delivery destination that leaves the checked revision untouched would escape the protection. Cover the facts material to this action with the version or fingerprint, and say which changes require a fresh decision. The check should track what the reviewer relied on, so a conflict has a reason the colleague can understand instead of merely another number to refresh.
Illustrative local transaction, not production code:
UPDATE orders
SET delivery_window = :approved_window, revision = revision + 1
WHERE id = :approved_order AND revision = :approved_revision;
if affected_rows != 1: reject_conflict_and_refresh_review()
else: consume_approval_in_same_transaction()An illustrative approval for order O-52 revision 12 encounters a later address change.
Follow the labelled arrows. On a narrow screen, scroll sideways if needed.
A local transaction cannot make an unrelated provider participate in the same atomic decision. If the final update happens through a courier or booking API, determine whether that receiver supports conditional changes, stable operation identities or another concurrency contract. A local approval record can govern whether to send. It cannot guarantee which external state remains current at arrival.
For O-52, the application might first re-read the provider’s current object and then send a conditional change tied to its version. If the receiver offers no conditional operation, the gap remains. The product may need a narrower action, a manual route or an explicitly accepted risk for a reversible change. Describe the actual boundary rather than calling the whole operation atomic because its first step used a transaction.
After the local use of P-9 is consumed, a lost external response can still leave the courier outcome unknown. Do not solve that by issuing a fresh approval identity and sending again. The original change may already have happened. Reconcile that result while preserving the revision binding and local consumption record. Those protections answer different parts of the problem: the authorised proposal, its permitted local use and what the external receiver actually did.
Revoked authority matters too. A colleague who approved the proposal may lose access before the queued action runs. Decide whether the policy requires current authority at execution, and enforce that rule in the service. For consequential actions, an old approval should not become a way to preserve privileges after the organisation has deliberately removed them.
The approval-consumption race is separate from the order-revision conflict.
Follow the labelled arrows. On a narrow screen, scroll sideways if needed.
Starting with valid proposal P-9, vary one material fact at a time: order identity, tenant, proposed window, material revision, expiry, required role or prior consumption. Each expected rejection should identify which boundary applies without revealing private state belonging to another tenant. These variations examine the permission actually enforced at execution, including whether a plausible model explanation can widen the stored action.
Include the legitimate case as well. A system that rejects everything is not a useful permission model. Verify that the permitted action succeeds against the intended revision, records the resulting revision and cannot be widened through extra fields. If a conflict occurs, the interface should show the changed facts and ask for the necessary new decision rather than silently retrying with an updated revision number.
This last point is easy to overlook. Automatically fetching the new revision and resubmitting defeats the purpose of making the reviewer’s decision version-bound. The conflict is evidence that the basis of approval changed. Sometimes application policy can establish that the change is irrelevant; otherwise the decision must return to the person with the material difference visible.
Keep an audit record linking proposal, approval, execution attempt and resulting object. Protect sensitive values and retain only what is needed to explain the action. A log saying “assistant updated order” is too broad to distinguish a legitimate change from an altered or stale proposal.
P-9 authorised the window change on O-52 as represented by revision 12. If revision 13 changes the address, show that difference and either apply an explicit policy that makes it irrelevant or return the decision to the reviewer. Quietly fetching the newer revision would make the guard easy to satisfy by removing the condition it was meant to protect. Keep the conflict visible until the next action has the same informed basis as the original approval.
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.