The note says "posted," but where is the receipt?
It is the end of your day, and an eval of a new checkpoint across 16 shards is half done. You write a handoff for a teammate in another time zone, or for the next agent session: shards 1 to 12 are scored and written, shards 13 to 16 are submitted, and the summary has been posted to the team channel. The note is tidy and every field is filled in. The one thing missing is anything the receiver can check. There is no hash of the results file, no scheduler job IDs, and no message ID for the post.
Your teammate picks it up cold, without your terminal history. Should they trust that the summary went out and move on? Or treat "posted" as a claim to check? If they repost to be safe, the channel gets two summaries, perhaps with different numbers. If they wait for shards that were never submitted, the eval sits "in progress" for a day.
A useful handoff lets the receiver tell three things apart: what was planned, what was attempted, and what is confirmed. This matters most when the previous worker is gone and repeating an action creates a duplicate. Chapter 13 of the book shows that a replacement must recover from records rather than ask a model what happened. This article is about writing those records for a person or an agent to receive. It adds a check for every claim, and the arithmetic of why spot-checking is not enough.
Separate claims from evidence
A handoff needs six kinds of information: the goal, the exact current state, evidence, the next permitted action, known failures, and what the receiver may and may not do. Most trouble comes from mixing up two of them. State is a claim: "shards 1 to 12 scored." Evidence lets someone check it: the path of the results file and its SHA-256, or the query that counts the rows. A handoff that reports state without evidence asks to be trusted.
Prithvi Rajasekaran's account of long-running application development describes planner, generator and evaluator roles, with structured artifacts carrying context between sessions. The principle to take from it is to keep state inspectable and acceptance criteria explicit. LangGraph's persistence documentation describes checkpoints that preserve a graph's execution state so a run can resume (LangGraph, "Persistence"). A checkpoint can faithfully record that the agent called the post tool without that call corresponding to a message anyone received. Persistence preserves beliefs. It does not make them true.
Why a long handoff needs checks, in numbers
Suppose a handoff contains 40 claims, and each is independently right with probability 0.98. The chance that all of them are right is
0.98^40 ≈ 0.446More often than not, at least one claim is wrong. These numbers are illustrative, but the structure holds for any long handoff: reliability over many claims multiplies, just as it does over many agent steps.
Can the receiver spot-check? Suppose 2 of the 40 claims are wrong, and the receiver checks k of them chosen at random. The chance of catching at least one wrong claim is
P(catch) = 1 − C(40 − 2, k) / C(40, k)| Claims checked | P(catch at least one wrong claim) |
|---|---|
| 10 | 1 − (30 × 29)/(40 × 39) ≈ 0.442 |
| 20 | 1 − (20 × 19)/(40 × 39) ≈ 0.756 |
| 40 | 1.0 |
Scroll horizontally to view columns.
Checking a quarter of the claims catches the problem less than half the time. Checking by hand is slow, so people check a few. The fix is to make every claim checkable by a machine, so the receiver can check all 40 in seconds.
A handoff whose claims carry their own checks
Here is the handoff above, with a check attached to each claim. It uses only Python's standard library and runs on Colab's Python 3.12. The artifacts live in a dictionary so the example runs anywhere; in practice they are files, table rows and scheduler records.
import hashlib
# Artifacts the receiver can read. In a real handoff these are files, rows or scheduler records.
artifacts = {
"results/shards_01_12.jsonl": b'{"item": 1, "correct": true}\n',
}
def sha256(data: bytes) -> str:
return hashlib.sha256(data).hexdigest()
handoff = {
"run_id": "run-0930",
"status": "in_progress",
"next_action": "Wait for shards 13-16, then write the summary",
"claims": [
{"text": "Shards 1-12 scored and written",
"check": {"path": "results/shards_01_12.jsonl",
"sha256": sha256(artifacts["results/shards_01_12.jsonl"])}},
{"text": "Shards 13-16 submitted",
"check": {"path": "scheduler/run-0930-shards-13-16.json", "sha256": "unknown"}},
],
"external_actions": [
{"type": "post_summary", "status": "claimed_sent"},
],
}
def verify(doc, artifacts):
problems = []
for field in ("run_id", "status", "next_action", "claims"):
if field not in doc:
problems.append(f"missing field: {field}")
for claim in doc.get("claims", []):
check = claim.get("check") or {}
data = artifacts.get(check.get("path"))
if data is None:
problems.append(f"evidence_missing: {claim['text']}")
elif sha256(data) != check.get("sha256"):
problems.append(f"evidence_mismatch: {claim['text']}")
for action in doc.get("external_actions", []):
ref = action.get("receipt_ref")
if action.get("status") in {"claimed_sent", "confirmed_sent"}:
if not isinstance(ref, str) or not ref.strip():
problems.append(f"no_receipt_ref: {action.get('type')}")
elif ref not in artifacts:
problems.append(f"receipt_missing: {ref}")
return problems
for problem in verify(handoff, artifacts):
print(problem)It prints two problems:
evidence_missing: Shards 13-16 submitted
no_receipt_ref: post_summaryThe first claim passes: the file exists and its hash matches. The second has no scheduler record behind it, so the receiver should look up the jobs by their operation IDs before submitting anything. The third is the case this article opened with: a claimed post with nothing to check it against.
An empty problem list from this function is not permission to act. It shows the references resolve and the hashes match. It does not show that a scheduler record says the jobs are running, or that a message record names the right channel and text. That requires reading what the external system recorded.

What each check can and cannot tell you
"The handoff validated" gets used loosely. Be precise about which layer passed.
| Check | What it confirms | What it cannot confirm |
|---|---|---|
| Schema validation | The document is well formed | Whether referenced files exist |
| Artifact resolution and hash | The evidence exists and is the file the writer saw | Whether it belongs to this run and commit |
| Recomputation | A number follows from the evidence, such as accuracy from the results file | Whether an external action tied to it happened |
| External reconciliation | What the scheduler or messaging system recorded for a matching operation | Whether "accepted" means delivered, running or read; interpret the stated status |
Scroll horizontally to view columns.
Recomputing an accuracy from the results file and getting the number in the handoff tells you the arithmetic was right. It says nothing about whether the posted summary contains that number, or whether it was posted at all. "The numbers check out" is not "the handoff checks out."
A variable set to True shows only that an assignment ran. It may have been set before the call, after an error, or with no call at all. A receipt comes from the system that performed the action: a job ID from the scheduler, a message ID from the chat service, a row the results store returned.

Test your handoff format on a stranger
You can find out whether your format supports verification without any production system.
Rewrite your last real handoff so each claim carries a path and hash, a query and its expected count, or an external ID to look up. List each external action with its status and receipt reference.
In a copy, keep a receipt reference but remove the artifact it points to. Give the copy to a colleague, or a fresh agent session, who did not write it, and ask for the next permitted action.
A receiver who reports the missing evidence, leaves the run in its current state and takes no external action is behaving correctly. One who proceeds, or invents plausible values, has shown you a gap in the format or in the habit of checking it.
Run the same test with an agent as the receiver. Chapter 13 found that, handed a transcript and asked to continue, one small local model re-placed an order in 14 of 20 samples without looking it up. Structured claims with checks give an agent receiver something to verify instead of a story to continue.
Check the decision
What would prove this wrong
If receivers still act without resolving references that are present, the format is not driving the behavior; you may need a required verification step that runs before the receiver is allowed to act. If breaking a piece of evidence changes nothing in what receivers do, either they always check the underlying systems regardless of the document, or they never check anything. Both are useful results, and the stranger test above finds them cheaply.
Why this matters in a lab
Research work is handed off constantly: across time zones, between an engineer and an agent, between agent sessions whose context was compacted, and to whoever picks up a paper's experiments six months later. A handoff full of unverifiable claims is how a team ends up rerunning a week of evals, or reporting a number nobody can trace.
An interviewer might ask: "You're taking over a half-finished eval from a colleague who has left for the day. What do you need from their handoff, and what do you check before you touch anything?" A strong answer separates claims from evidence and expects a check per claim. It uses the arithmetic to explain why spot-checks are not enough, treats claimed sends as unknown until reconciled, and names which layer each check covers. The companion article on resuming a crashed job uses the same records when the previous worker is a process rather than a person.
Give each piece of work and each report its own identity, finish and report together, and keep an outbox that says what was sent.

