LangGraph Run History Is Your Audit Trail
A number arrives in the review pack. Someone asks where it came from. The answer is a thread, a notebook, and an engineer who is on leave.
LangGraph in operations, a 10-part series. ← Part 2
LangGraph run history is the sequence of state snapshots a checkpointer persists for a thread, reached by passing a thread_id in the graph config (LangChain docs, persistence). That sequence is the audit trail. The dashboard, the chart, the signed PDF are renderings of it, and a rendering carries no provenance of its own.
An Instrument Refuses to Print a Zero
When a required input is missing, the correct output is a refusal that names the missing thing. Not zero. Zero passes most downstream checks, because zero is arithmetically valid — it sums, it averages, it produces a variance that looks like a real variance.
Gupta (2026) evaluated two models (Gemini 2.0 Flash and GPT-4o) and two agent architectures across four domains over 1,280 episodes. Semantically equivalent task perturbations alone dropped success from 96.9% at perturbation intensity zero to 88.1% at 0.2. Rate limiting was the most damaging fault injected. ReAct held up better than Reflexion under combined stress, which means architecture choice — not just model choice — changed reliability under stress.
ReliabilityBench measures degradation under stress; it does not measure what a system prints when a required input is absent. Our reading, stated as a judgment rather than a finding: a system that degrades silently under stress has no reason to announce a missing input, because nobody designed the announcement.
A Receipt Is a List of Ingredients, Not a Total
A total is an opinion about arithmetic. A receipt is a set of facts someone else can re-execute. Six fields separate the two: the query text, its parameters, a hash of the query text, the count of records returned, the as-of time of the read, and the command that re-runs that read at the revision it came from. The record count gives a cheap comparison — a rerun returning a different count means the disagreement is about data, not logic. The as-of time handles the case that kills most reproductions: the table was backfilled, the dimension changed, the snapshot moved. Store the query text and hash the record. An edit after the fact then surfaces as a mismatch, instead of being absorbed into the record.
Ma et al. (2026) grounded a benchmark in a study of enterprises building production data agents across six industries, and populated it with 104 queries spanning 17 datasets and 4 database management systems. The best state-of-the-art agent reached only 57% pass@1.
LangGraph supplies the container almost for free. The checkpointer writes a snapshot per step, scoped to the thread. The documentation is blunt: state should hold raw data, not formatted text (LangChain docs, thinking in LangGraph). A formatted string like "Q3 revenue: <formatted>" is hard to recover from. The tuple of query, parameters, hash, count and timestamp is re-executable.
Name the Estimator Before You Read the Number
Four declarations turn a result into a reviewable method: which estimator ran, which version of it, what the unit of analysis is, and the significance level and sides. Revenue per invoice and revenue per invoice line are two different numbers computed from the same table, and both are correct. If the unit is not recorded, a reviewer who disagrees is not disagreeing with the arithmetic. They are disagreeing with a framing nobody mentioned.
Do not expect an off-the-shelf evaluation to settle the rule: Yehudai et al. (2025) survey agent evaluation and name cost-efficiency, safety and robustness among the gaps future research must address.
O'Brien et al. (2022) mined 68,820 self-admitted technical debts from all revisions of 2,641 popular machine-learning repositories on GitHub and built a taxonomy of 23 shades of ML technical debt. Their key distinction is that ML debt can infect the data a model is trained on, affecting the functional behaviour of the system. Our reading: an unnamed estimator and an unnamed dataset are a debt of that kind, and one a reader of the code alone may not see.
Replaying a LangGraph Checkpoint Does Not Reproduce Your Number
Nodes before the chosen checkpoint are not re-executed, because their results are already saved. Nodes after it do re-execute — including LLM calls, API requests and interrupts — and those may return different results (LangChain docs, use time-travel). A replay is a reproduction of the method, not of the number. Because replay runs against live dependencies, the inputs, the method and the figure all have to live in the snapshot, and the code revision has to be pinned so that re-execution at least runs the same logic.
Gupta (2026) had to define consistency under repeated execution as one of three reliability dimensions, and measured it across four domains over 1,280 episodes. So the honest reading of a replay is not proof. It is test. A replay you can fork lets you ask the question a reviewer actually has: would a different rule have produced a different sign?
A LangGraph Fork Is Evidence; an Overwrite Is a Deleted Defence
LangGraph's update_state, applied to a past checkpoint, creates a new branch from that point and does not roll back the thread; the original execution history stays intact (LangChain docs, use time-travel). A later edit sits beside the run it modified instead of replacing it.
get_state_history returns the thread's checkpoints in order with their checkpoint_id, and that identifier is what you fork from. Without it, "we changed the rule" has no address. None of this exists unless a checkpointer is attached: with none, get_state_history has nothing to return. With one, snapshots are scoped to the thread (LangChain docs, persistence). The persistence page is explicit that the in-memory checkpointer loses everything on restart, recommends a persistent one for production, and leaves retention and pruning to you; replication is not covered.
Zhang et al. (2025) argue that temporal attribution methods misdiagnose multi-agent failures because errors propagate across agents, and that the fix is to trace information dependencies rather than temporal order. Their GraphTracer-8B reports up to 18.18% higher attribution accuracy than state-of-the-art models on the Who&When benchmark, and 4.8% to 14.2% performance improvements when integrated into deployed multi-agent frameworks. Better failure attribution made deployed systems work better: diagnosis was a capability, not a reporting cost. A record that keeps only the winning path cannot support that analysis, because you need the rejected dependencies to see what the error propagated through.
A Number Without a Build ID Makes Regression Unfalsifiable
Attribution is what separates a model regression from a rule change. Two fields prevent the collapse: the graph version and the code revision behind it. LangGraph's deterministic parts stay fully predictable and auditable, and LangSmith tracing captures execution paths and state transitions (LangChain docs, overview), with execution metadata kept in state for debugging and recovery (LangChain docs, thinking in LangGraph).
Wang et al. (2026) describe an orchestrator that adapts multi-agent topology density to task difficulty and refines the topology within an instance, outperforming the strongest baseline by up to 14.6% across three competition-level and two foundational code datasets. If the delta belongs to the topology layer, then naming the model without naming the topology leaves that 14.6% unattributable in both directions. Yu, Ding and Sato (2025) report 21–33% reductions in execution time, with larger gains on more complex tasks, a 35.4% improvement in resource utilisation from 65% to 88%, and near-linear throughput scaling up to 16 concurrent agents — a 3.47× gain for a 4× increase in agent count.
Shen et al. (2026) built SciAgentGym, an environment of 1,780 domain-specific tools across four natural-science disciplines, and synthesised training trajectories with SciForge, which models the tool action space as a dependency graph. Fine-tuning on those trajectories produced SciAgent-8B, which outperforms Qwen3-VL-235B-Instruct and shows positive cross-domain transfer. In that work a fine-tuned 8B model outperformed a much larger one, which is one reason to record the whole system and not only the model name (our reading).
The Record Is for the Person Who Signs, Not the Person Who Builds
A debugging artefact is read by the person who wrote the nodes. An audit artefact is read by a finance partner who will never read the code and is being asked to put their name next to the number. If the dashboard renders anything else — a separate aggregate path, a second query, a cached figure computed somewhere the record does not reach — then the record is not the source of truth.
New Computer's account shows the team generating synthetic-user queries across a wide range of intents, then inspecting the global effect of prompt changes in LangSmith's experiment comparison view, which let them identify regressed runs in a highly visual manner. Separately, retrieval experiments run in LangSmith, scored on precision, recall and F1, took their memory retrieval to 50% higher recall and 40% higher precision than a previous baseline implementation of dynamic memory retrieval. LangChain's AppFolio case study makes the design-side version of the point: seeing the assistant's execution flow let the team design workflows that reason before acting.
What a LangGraph Checkpoint Does Not Prove
The persistence documentation makes a narrow commitment: a checkpointer persists graph state snapshots scoped to a single thread (LangChain docs, persistence). Tamper-evidence, retention windows, access control and PII handling are not guaranteed by the checkpointer; they depend on the store you attach.
The record is also only as complete as your node design. An API call that moved money appears in the record if you wrote it into state. Liu et al. (2025) argue that judging agentic systems by final success or failure overlooks how agents reason, plan, act and change strategy, and encode trajectories as graphs instead. Their automated analysis of 4,000 trajectories from two agentic programming workflows — SWE-agent and OpenHands — across four backbone LLMs, completed within four minutes, found that agents using richer prompts or stronger models produce more complex trajectories, with deeper exploration, broader context gathering and more validation before patch submission.
Failures are also not only tool failures. Bandi et al. (2026) evaluated expert-written, human-verified tasks across 36 real MCP servers and 220 tools with 20 frontier models, reporting pass rates up to 82.2% at a 0.75 claim-coverage threshold. Their 11-category diagnostic taxonomy then separates tool-call failures from cognitive ones, and 63.3% of diagnosed failures were cognitive: task understanding, synthesis, parsing, stopping. In our reading, a record that captures tool calls faithfully and reasoning not at all is documenting the smaller half of the problem.
Ask Four Questions Before You Sign the Next Number
The question is not whether to build a dashboard. It is which artefact you are willing to be held to when the number is challenged. Read the table below as a cost schedule, not a maturity model.
| Question | Dashboard-only answer | Record-first answer |
|---|---|---|
| Who can verify it? | Whoever has UI access and trusts the pipeline | Someone with the record and read access to the source |
| What happens on rerun? | A refresh; the previous figure is gone | A replay or fork; the previous figure remains |
| What does an edit look like? | A corrected cell | A new branch beside the original |
| What prints when an input is missing? | Frequently a zero | A named refusal |
| What survives the builder leaving? | Little beyond screenshots | The record |
- Who can re-run it, and from what artefact? If the answer is a person rather than a record, the reproduction is a favour, not a property.
- On what data, as of when? A record count and an as-of time turn a disagreement about logic into a disagreement about data in one step.
- With what code and what graph version? Otherwise a regression and a rule change are indistinguishable.
- What does the system print when it cannot? A system not designed to refuse has likely not been tested on the case that matters.
FAQ
What is run history in LangGraph? Run history is the record of graph executions captured through checkpointers, which persist the state of a thread after each step so past states can be inspected, replayed or forked (LangChain docs, persistence).
Does LangGraph store run history by default? No. Run history exists only when a checkpointer is attached to the compiled graph; with one, snapshots are scoped to a thread (LangChain docs, persistence).
What is a thread in LangGraph run history?
A thread is the lineage the checkpointer writes into. Snapshots are scoped to a single thread, reached by passing a thread_id in the graph config (LangChain docs, persistence), and you list that lineage with get_state_history, which returns each checkpoint with its checkpoint_id (LangChain docs, use time-travel).
Can LangGraph run history be used for compliance auditing? It provides the raw step-by-step state record an audit trail requires, but compliance use also depends on your storage, retention and access controls — which depend on the store you attach and how you configure it.
How do you inspect past runs in LangGraph?
Retrieve a thread's checkpoint history through get_state_history, then inspect, replay from, or fork at a specific checkpoint_id. Replaying re-executes the nodes after that checkpoint, so LLM and API calls fire again and may return different results (LangChain docs, use time-travel).
A Decision You Cannot Re-Run Is a Decision You Cannot Defend
The tempting fix is more dashboards, and it is the wrong fix, because a dashboard is a rendering and renderings do not carry provenance.
What carries provenance: a thread identified by a thread_id, a sequence of snapshots you can list, inputs stored raw rather than formatted, a method declared in the record, one hash over the whole record that makes a later edit visible, a pinned re-run command, a build identifier, and a refusal that names what is missing. LangGraph hands you the first two (LangChain docs, persistence). The rest is node design, which is our reading, not something the documentation promises.
The audit trail is not phase-two hardening bolted onto a working agent; it is a constraint you design under from the first node. No silent imputation. No aggregate computed off-record. No edit that replaces its predecessor. The record is what buys the system the right to run unattended. You can only delegate to a system you can interrogate, and interrogation requires something to read afterwards.
