The Close Report That Could Not Say Who Was Wrong

The problem

I built a four-agent month-end close workflow for a finance back office: a data-extraction agent that pulls general-ledger entries, a matching agent that reconciles them against bank statements, a variance-explanation agent that drafts explanations for discrepancies over a threshold, and an approval-routing agent that finalizes the close package. Each agent hands its output to the next. Only the final close report gets persisted anywhere: reconciled, some number of variances explained, approved.

I ran twenty-five synthetic GL-and-bank-statement pairs through this workflow, five of them carrying an error I injected at a specific, known agent. Then I asked the question an auditor would actually ask: for a wrong variance explanation sitting in the final package, which agent produced it. I measured a handoff attribution loss rate, the share of erroneous entries where the originating agent and step couldn't be identified from stored output alone. All five injected errors came back unattributable. Every single one. The close report showed a clean, finished-looking package, and buried inside it were five discrepancies that nobody, looking only at what the system had stored, could trace back to their source.

Every individual agent likely did its own job correctly on most of the twenty-five pairs. Extraction did what extraction does. Matching reconciled what it was handed. The variance-explanation agent wrote a plausible explanation for whatever discrepancy landed in front of it. The error might have originated in extraction and simply carried forward untouched through matching and explanation, or it might have started somewhere else entirely. There was no way to tell which, because the only thing the workflow ever wrote down was the end state. The handoffs themselves left no trace.

The pattern

The fix has every agent log a structured provenance record at its own step: agent name, timestamp, the input it received, the output it produced, and the handoff target it sent that output to. Every one of those records gets assembled into a full cross-agent trail for the run.

Running the same twenty-five pairs through the provenance-emitting version of the pipeline, the five injected errors now trace to the exact agent and handoff step that introduced them. Attribution loss goes from total to zero. Nothing about the agents' actual reasoning changed. The extraction, matching, and explanation logic runs exactly as it did before. What changed is that the workflow now keeps a record of the sequence of custody a piece of data passed through, agent by agent, on top of the final state it already remembered.

That distinction, between where something ended up and how it got there, is the entire value of the pattern. A coordinated multi-agent workflow now reads as a traceable sequence of accountable handoffs, each one on the record. When a wrong variance explanation shows up in an audit, the trail names the exact agent that produced it, and the input it was working from when it got it wrong.

Design considerations

A provenance trail makes a fault attributable after the fact. Preventing the fault from happening in the first place is a different job, and it's easy to blur the two together. Knowing that the matching agent introduced a specific discrepancy on a specific pair still leaves the discrepancy sitting there, uncorrected. Somebody has to look at that trail and act on what it reveals. A team that builds the provenance mechanism and stops there has built a postmortem tool. Whether the error rate actually goes down from there is a separate question, one the trail by itself never answers.

The logging itself isn't free. Every agent, at every handoff, is now writing a structured record on top of doing its actual job. In a four-agent pipeline processing twenty-five pairs, that overhead is trivial. In a workflow running thousands of records a day through a dozen agents, the storage and the discipline required to keep every one of those records complete and consistent turns into a real engineering commitment.

There's also a granularity question I underestimated at first. I logged input, output, timestamp, and handoff target at each step, which answers "which agent" and "what did it see." Answering why the agent produced the output it did requires the reasoning itself captured alongside the input and output, and I didn't build that in. A provenance trail tells you where to look. Finding out what actually happened once you get there takes a separate kind of digging, one that gets harder for a failure that's a subtle misjudgment: the kind that produces a plausible-looking output with nothing obviously wrong on its face.

The last limit is that a provenance trail assumes each error has one clean point of origin, one agent, one handoff, where the thing went wrong. That assumption holds for a lot of real failures, including the injected-error scenario I built to demonstrate this. A compounding fault breaks it: two agents each contribute a partial error that only produces a wrong final outcome in combination, neither one wrong enough on its own to trip anything. A trail built to answer "which single agent caused this" can misattribute or split the difference when a fault has no single clean origin, and that's a real gap in what this pattern covers.