Add a Verifier and Durable State
Project10 min · Map → Contract → Route → Verify · Updated 2026-09-15
You end this lesson with: That same graph extended with a standalone verifier node and a durable state file that survives a mid-run crash and resumes correctly.
Chapters
- What You'll Do01
- Tools You'll Use02
- Steps03
- How to Measure Results04
- What to Submit05
- Key Takeaways06
Project 02. Add a Verifier and Durable State
Related Lecture: Lecture 07. The Most Valuable Node Produces Nothing
A three-person compliance team's overnight contract batch had run clean for six months: extract each clause, check it against policy, verify the check against the source text, all coordinated by the same process that also tracked which contracts were already done. One night the host machine restarted for a routine security patch, forty minutes into a run of two hundred contracts. Nothing in the batch itself had failed — the process running it was simply gone. Restarting from the top re-ran all two hundred contracts, including the roughly eighty already checked and verified, because the record of what was done had lived only in that process's own memory and vanished with it. The team paid for the same review twice and still couldn't say, from anything written to disk, which of the first eighty had actually cleared before the restart.
Illustrative composite. The team, the two-hundred-contract batch, and the forty-minute mark are a teaching device; the failure it stands in for — progress that exists only inside a running process, gone the moment that process is — is the one this project measures a real fix for.
What You'll Do
Extend the fan/join graph from Project 01 with the two pieces this course spends its second half on: a verifier that checks a generator's output against something external, in a fresh context, and durable state that lets the whole graph survive a crash mid-batch and resume correctly. You'll also split any judgment-and-routing node you have into a classifier and a route table, and write a rough cost estimate for the graph before running it at volume. When you're done, you'll have deliberately crashed your own graph and watched it recover.
Tools You'll Use
- The fan/join graph you built in Project 01
- Claude Code, Codex, or your usual agent harness
- A simple durable store — a JSON file, a SQLite table, or whatever your harness already uses for state; it doesn't need to be a production database for this project
Steps
Prep
- Start from Project 01's graph. If you don't have one, build a minimal fan/join graph first — this project assumes at least one generator node whose output feeds a downstream decision.
- Create a branch for this project's changes so you can compare before and after.
Worked Example First: Verifying and Resuming the Contract Batch
Before wiring your own graph, work through this course's running example once, filled in completely.
The verifier's contract, filled in (Lecture 03's four-line format).
Node: verify liability extraction
Job: confirm the extracted clause against the source
Input: extracted liability clause (from extract liability) + original contract text — never extract liability's reasoning
Output: { verdict: "confirmed" | "unsupported", citedText: string | null }
Failure states: unsupported (clause text not found verbatim in source) — routes to re-extract, not to check liability
Decide now: the verifier is running behind schedule for this batch. Do you let it read extract liability's reasoning trace alongside the source text, to save it re-deriving context, or do you keep its input to the source text alone?
Keeping the reasoning trace out costs a few extra tokens and is the choice that actually verifies anything: a verifier reading the extractor's own reasoning would have agreed with a fabricated liability cap the same way a same-context self-check would, because it would be checking the argument that produced the mistake, not the contract the mistake was supposed to match. The contract above names only the extracted clause and the contract text as inputs for exactly this reason.
The crash-resume trace, filled in.
The batch from this project's opening crashes forty minutes in, with eighty of two hundred contracts already checked and verified.
// state store, keyed by contract ID + node name — the same key on restart overwrites, never duplicates
{ "contract-014": { "currentNode": "checkLiability", "completedNodes": ["fetchContract", "extractLiability", "verifyLiability"], "artifacts": { "verifyLiability": "confirmed" } } }
On restart, the orchestrator reads this store before re-running anything: contract-014 already has verifyLiability written, so extractLiability and verifyLiability are skipped and the batch resumes at checkLiability for that contract, not from fetchContract. If extractLiability fires again anyway — a retry that starts before the orchestrator checks the store — the write for extract:liability:contract-014 overwrites the same key with the same result: one extra model call, not a duplicate artifact or a second, conflicting verdict, because the key is contract ID plus node name, not a fresh ID per write.
Now add a verifier and durable state to the graph you picked in Prep, and run your own crash test in Step 4.
Step 1: Add a Verifier
Following Lecture 07:
- Pick one generator node in your graph whose output another node currently trusts without an independent check.
- Identify what that verifier should check the generated output against — the original source material, a declared schema, a second independently-run path, or an actual executable check (tests, a validator). It must be something the generator's own context doesn't already contain.
- Write the verifier's contract (Lecture 03's four-line format), with special attention to its input: name specifically what it reads that the generator did not have, or did not rely on, when producing its output.
- Wire the verifier onto the edge between the generator and its downstream consumer — not inside the generator's own call. A failed verification should route somewhere explicit: a retry (a controlled cycle, Lecture 04), a different downstream path, or a human.
- Deliberately corrupt one generator output (edit an artifact after generation, or force a wrong extraction) and confirm the verifier catches it before it reaches the downstream node.
Step 2: Split Classification from Routing
If your graph has a node that both judges something and decides what happens next in the same call, apply Lecture 06's split:
- Extract the judgment into a pure classification function that returns a label.
- Write a separate route table mapping every possible label to a path.
- Confirm the table is exhaustive — every label the classifier can produce has a row. Anything it could return that isn't covered is a contract violation (Lecture 03); decide explicitly what happens to it (escalate, error) rather than letting it fall through silently.
Step 3: Add Durable State
Following Lecture 08:
- Design a state schema that can answer, at any moment, the three questions from Lecture 08: what has already happened, why was a given route taken, and where can execution resume.
- Make every write idempotent, keyed by a stable identifier (e.g., item ID + node name), so a retry after a crash overwrites rather than duplicates.
- Wire your fan/join graph to write to this store at every node completion, instead of passing full results only through in-memory handoffs.
Step 4: Crash It on Purpose
- Start a batch run large enough to take a noticeable amount of time (or artificially throttle it).
- Kill the process partway through — deliberately, not by accident.
- Restart from the durable state. Confirm: completed branches are not re-run, in-flight branches resume or restart cleanly, and the batch's final report correctly reflects everything that happened across both halves of the run, including the crash.
Step 5: Price the Graph
Following Lecture 09, write a short cost estimate for your finished graph: which nodes run on which model tier and why, roughly how many node-runs a typical batch triggers, and whether any subset of typical inputs would benefit from a short path that skips the full graph.
How to Measure Results
| Metric | Before this project | After |
|---|---|---|
| Does a corrupted generator output get caught before reaching downstream nodes? | ||
| Can the classifier's judgment and the routing decision be changed independently? | ||
| After a forced mid-run crash, do completed branches avoid re-running? | ||
| Can you answer "what happened, why, and where do we resume" from state alone, without re-reading logs? | ||
| Rough node-runs per batch, by model tier | — |
What to Submit
- The verifier's contract and the corrupted-output test you ran against it, with the result.
- The classify/route split (if applicable to your graph) — the classifier function, the route table, and confirmation the table is exhaustive.
- Your durable state schema and a description of the crash-and-resume test: what you killed, when, and what the state showed on restart.
- Your cost estimate from Step 5: node-runs by tier, and one short-path candidate you identified (built or not).
- Final retro: what actually broke the first time you tried the crash test, and what that told you about a gap in your state design.
Key Takeaways
- Check the verifier's input for anything it shares with the generator; remove it.
- Route judgment failures through the table, not around it.
- Keyed, idempotent writes make "just restart" a safe default.
- Prove crash recovery by killing the process, not by reasoning about it.
- Price the finished graph before it runs at real volume.
What You Have Now
That same graph extended with a standalone verifier node and a durable state file that survives a mid-run crash and resumes correctly. Both live alongside graph.md from Project 01 — the state file as evidence your graph can be killed and restarted without losing progress, the verifier's contract as one more entry in your node-contracts list. Together they close out the Verify stage of this course's Map → Contract → Route → Verify loop.
Write the measurement table and the idempotent-writes/model-tier notes into graph/project-02.md; the lab's checker looks for that file at that path.
Related Lectures
NO-QUIZ
Quiz coming to this lesson
This lesson doesn't have a graded quiz yet — completion is still tracked, just not verified against questions.
Reading is free — your progress isn't being saved
Nothing you did on this page is recorded. Paid students get saved progress and verified completions, recorded quiz answers, the spaced-repetition review queue, labs, and a certificate for each course they finish.
30-day money-back guarantee. One-time payment — lifetime access and updates.