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.
A duplicate delivery, a repeated attachment and a corrected invoice are different events. A worked case model shows how one reviewer can keep them connected without confusing delivery with resolution.
“Manual review” looks reassuringly complete on an invoice-flow diagram. Someone has been assigned the difficult part. But an unmatched purchase order still leaves that person needing to find what arrived, why it stopped and what would count as resolving it. If the process keeps no case record, the reviewer has to assemble that account from email, accounting software and a separate spreadsheet before making the decision they were supposedly brought in to make.
That reconstruction becomes harder when the process confuses a failed message, a document requiring interpretation and an unresolved invoice. They describe related work at different levels. A retry might repeat a delivery; a replacement attachment might change the invoice evidence. Neither should automatically create a new business case. A stable case record lets the reviewer relate those arrivals to the outstanding question and its eventual resolution.
Follow an illustrative supplier, SUP1, and invoice I17 through that queue. The documents, amounts and export references are synthetic; the accompanying Python example exercises their transitions in memory. What matters to the reviewer is how a later arrival relates to the existing disagreement. Does it merely repeat the attachment, supply a correction or confirm that accounting accepted the selected version? Keeping those possibilities separate prevents a busy inbox from becoming a misleading count of outstanding invoices.
The initial rule is that a verified supplier-and-invoice association identifies one case. That association is an input to the model, not an extraction capability it magically possesses. Two suppliers can use the same invoice number; a supplier can make mistakes in a reference. Uncertain grouping needs review rather than a confident merge. The model begins after that question has been established so it can examine what happens inside the case.
The first arrival is message E1 carrying document D1. Its purchase order cannot be matched, so the case needs work. If the delivery mechanism presents E1 again, that is a repeated message. It should not create another case or another document. Amazon SQS documents possible redelivery for standard queues and recommends duplicate-safe processing [1]. The transport can therefore repeat work even when the supplier sent nothing new.
Next comes E2, a different message carrying the same document bytes. The model computes a content digest, recognises the existing document and links E2 to D1. There are now two distinct messages and one document, still belonging to one invoice case. This is a different repetition from E1 being delivered twice. Recording the relationship helps explain the inbox history without asking a reviewer to decide the same missing-order question again.
The digest is useful precisely because its promise is small: it recognises identical bytes. A rescanned PDF, a metadata change or a different rendering can carry the same invoice in different bytes. Matching amounts and references can also appear in genuinely different documents. I would keep exact-byte deduplication as a way to spare the reviewer a repeated attachment, while leaving commercial equivalence open to review. Otherwise a convenient technical comparison starts deciding which evidence the business is allowed to see.
E3 then brings D2, a corrected invoice with a different total and a purchase-order reference. The case records a new document and moves to revision_review. It does not silently make D2 authoritative because its message arrived later. In the model, an assigned reviewer explicitly selects the document under consideration. Arrival order establishes that information appeared; it does not by itself establish that the supplier intended to replace every earlier fact with it.
The case needs more than a status word. Its minimum useful record includes the supplier/invoice key, related message and document identifiers, selected document, owner, blocking reason and resolution history. In an interface, those fields should explain what the reviewer can do next. Waiting on a supplier and unable to contact accounting are different conditions even if both prevent today’s export. Combining them under Failed hides the appropriate next move.
Two colleagues should not both be told they own I17. The example assigns it to OP1 and refuses OP2’s attempt to take the same case. A deployed interface needs an atomic persistent claim, or equivalent coordination, to give both browser sessions that answer. It also needs a deliberate reassignment route when OP1 is unavailable. Ownership is useful because it tells the next colleague who is acting; a label that two screens can award independently would only make the responsibility harder to establish.
For D1, the blocking reason is purchase_order_mismatch, which covers the missing or unverified match in this deliberately small model. Selecting D2 does not clear that requirement: its proposed order still does not match. The case remains waiting. Retrying extraction cannot resolve a reference that was extracted correctly but supplied incorrectly. Showing the reference and its evidence gives the reviewer a basis for seeking the required correction.
A production design may split missing_order, wrong_supplier and amount_disagreement because they require different people or evidence. Add a reason when it changes the work, not simply because more categories are available. Record when waiting began and whether the case is waiting on the business, a supplier or a technical dependency. The opening date and the start of the current wait answer different operational questions and should not be compressed into one unexplained age.
A further correction, D3, supplies a matching purchase order. OP1 selects it, and the proposed validation moves the case to ready. Ready means the prerequisites for the next step have been satisfied. It does not mean the accounting record already exists. That difference matters when a network call fails, when approval is still outstanding or when the reviewer has selected the right document but has not completed the action.
Closure asks for the responsible actor, the currently selected document and an export confirmation reference. The program refuses to close a waiting case, an attempt tied to superseded D2 or an attempt with no reference. Selected D3 and synthetic EXPORT17 satisfy those requirements and produce a recorded resolution. That shows the chosen prerequisites cannot be skipped in this model. Whether those are the right commercial prerequisites remains a decision for the people who own the invoice process.
There is one more important test. D4 arrives after resolution and contains another correction. The case reopens revision review while retaining the earlier D3/EXPORT17 resolution. It neither erases history nor automatically modifies accounting. A person can now investigate whether the new document calls for an adjustment, rejection or another agreed response. The existence of a closed case should not make later evidence vanish, and later evidence should not rewrite the fact that an earlier export occurred.
Several arrivals can still be asking the same purchase-order question. This sequence ends with five message identifiers, four document contents and one case owned by OP1, because repeated delivery and repeated bytes are different from a new invoice. The useful count for the reviewer is the unresolved decision, including the correction that reopened it after export. A queue arranged only by failed messages could send several colleagues back over D1 while giving too little attention to the later document that actually changed the evidence.
A constructed I17 case distinguishes message identity, document content, selected revision and resolution. The local state-model assertions passed; no accounting service was called.
Follow the labelled arrows. On a narrow screen, scroll sideways if needed.
A dead-letter queue can isolate messages that a consumer could not process; AWS describes it as a debugging and recovery facility [2]. That is useful for an unavailable dependency or a malformed payload. It does not supply the document-selection rule, identify a valid purchase order or decide whether a corrected invoice should replace an exported version. Redriving a technical message cannot settle those business questions by itself.
The application should therefore keep technical delivery state distinct from case state. A temporary accounting outage may leave the same case ready with an undelivered export intention. A genuine invoice disagreement may leave it waiting even though every message was delivered successfully. Operations can then investigate the right system without treating a transport retry as evidence that the underlying case has been reviewed.
There is a cost to building this record: an extra interface, retention of related documents, access control and clear ownership. For a handful of invoices, a well-maintained shared register may express the same rules adequately. The design becomes worthwhile when repeated copying, duplicated review or unexplained closure costs more than maintaining the case. That is a judgement about the actual work, not a requirement to purchase an elaborate workflow engine.
Walk I17 through the proposed screen from E1 to the correction after EXPORT17. The reviewer should be able to follow the repeated delivery, identical attachment and changed evidence without treating each as another invoice. They also need to see why the case is waiting and what could settle it now. If that account is available in one place, the extra interface has earned its upkeep: it lets the reviewer decide the invoice rather than first perform an investigation into the automation’s filing habits.
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.