When "it arrived" is not the same as "it worked"
An orchestrator dispatches a subagent to reproduce a paper's baseline on a held-out test set. Some minutes later a message comes back: "Done. Baseline reproduced, numbers look right." The message arrived. By any dashboard that counts completed subtasks, this handoff worked.
Then the orchestrator tries to act on it. Which split? Which data version? Which seeds ran? Where is the results file? Did every case get scored, or did the run stop partway? The subagent knew all of this when it wrote the message. None of it crossed the boundary, so the orchestrator has to ask again or redo the work.
The same thing happens when an eval worker crashes partway through a run and a replacement picks it up. The replacement starts. Whether it can continue, rather than rescore everything or score some cases twice, depends on what the first worker left behind. In both cases, ask: did the handoff transfer a message, or the ability to act?
Defining acceptance from the receiver's side
The thesis is simple to state and easy to violate: acceptance of a handoff is defined by what the receiver can diagnose and recover, not by what the sender reports as delivered. A system that measures "message delivered" is measuring the sender's success, not the receiver's.
To continue the work rather than restart it, the receiver needs at least four things:
- Confirmation that the sender still held the task when it wrote, and when that was last true.
- The current task state and the data or code revision it belongs to, not a summary to reconstruct.
- What remains unresolved, stated plainly rather than implied.
- What the receiver is being asked, and allowed, to do next.
Anthropic's engineering writing on long-running application harnesses describes combining planning, generation and evaluation stages so a system can work over extended tasks without losing track of what it decided and why (Prithvi Rajasekaran, Anthropic, "Harness design for long-running applications," https://www.anthropic.com/engineering/harness-design-long-running-apps, March 2026). That is about one system's internal continuity. The handoff problem asks a related question: when control passes to a different agent or worker, does that continuity survive the boundary, or must it be rebuilt from evidence someone kept?
LangGraph's persistence documentation addresses a neighboring mechanism: checkpoints that preserve execution state so a graph-based agent can resume where it left off (LangGraph, "Persistence," https://docs.langchain.com/oss/python/langgraph/persistence, retrieved 2026-09-10). A checkpoint tells you the state was saved. It does not tell you whether a side effect tied to that state (a job submitted to a cluster, a result posted to a tracker) happened exactly once, or whether the party picking it up may act on what it contains. Persistence and authorization are separate concerns, and mixing them up is where handoffs quietly fail.
Building the handoff envelope
The fix is a typed handoff envelope: a structured object that travels with the report, carrying what a free-text message leaves out. For a subagent it is the return message's schema. For a resumed worker it is the record the replacement reads before touching the job. For a human reviewer it is the record they open before approving anything. The channel differs; the contract does not.
Here is a minimal version in Python's standard library, so the shape is checkable without dependencies. The fixture is the baseline reproduction above, stopped after 312 of 500 cases on the first seed:
from dataclasses import dataclass, replace
from datetime import datetime, timedelta, timezone
@dataclass
class HandoffEnvelope:
task_id: str
lease_renewed_at: datetime
lease_validity: timedelta
task_revision: str
task_state: dict
unresolved_issue: str
evidence_refs: list[str]
requested_next_action: str
def check_handoff(envelope, received_at, current_revision, authorize):
# Assume authenticated envelope provenance and aware timestamps.
age = received_at - envelope.lease_renewed_at
fresh = timedelta(0) <= age < envelope.lease_validity
current = envelope.task_revision == current_revision
has_context = bool(envelope.task_state) and bool(envelope.evidence_refs)
permitted = fresh and current and has_context and authorize(
envelope.task_id, envelope.requested_next_action
)
return {
"lease_fresh": fresh,
"task_current": current,
"context_present": has_context,
"next_action_eligible": bool(permitted),
}
renewed_at = datetime(2026, 1, 1, 10, 0, tzinfo=timezone.utc)
envelope = HandoffEnvelope(
task_id="baseline-repro-3", lease_renewed_at=renewed_at,
lease_validity=timedelta(minutes=5), task_revision="data-v4",
task_state={"split": "test", "seed": 0, "scored": 312, "total": 500},
unresolved_issue="cases 313 to 500 not scored; seeds 1 and 2 not run",
evidence_refs=["results/seed0-partial.jsonl"],
requested_next_action="resume_from_case_313",
)
allow = lambda task, action: (task, action) == ("baseline-repro-3", "resume_from_case_313")
now = renewed_at + timedelta(minutes=3)
assert check_handoff(envelope, now, "data-v4", allow)["next_action_eligible"]
for received, revision, policy, candidate in [
(renewed_at + timedelta(minutes=5), "data-v4", allow, envelope),
(renewed_at + timedelta(minutes=6), "data-v4", allow, envelope),
(renewed_at - timedelta(seconds=1), "data-v4", allow, envelope),
(now, "data-v5", allow, envelope),
(now, "data-v4", lambda task, action: False, envelope),
(now, "data-v4", allow, replace(envelope, evidence_refs=[])),
]:
assert not check_handoff(candidate, received, revision, policy)["next_action_eligible"]
print("Fresh current authorized fixture accepted; six boundary cases denied")Run on Python 3.12, it prints Fresh current authorized fixture accepted; six boundary cases denied.
At three minutes, the authorization function permits resuming from case 313. At exactly five minutes
the sender's lease has expired: the window includes its start and excludes its end. A future
timestamp, a changed data version, a denied action or missing evidence references also block
eligibility. These are local predicate tests on a synthetic fixture, not observed eval runs.
The lease is the Chapter 13 idea: a worker holds a job only while its lease is current. A report that arrives after the lease lapsed may come from a worker the orchestrator has already replaced, so accepting it could score the same cases twice or overwrite a newer result.
The fields deliberately avoid claiming completed or evidence_valid. The function does not open
the referenced results file; nonempty references prove presence only. A receiver must authenticate
the envelope, resolve evidence under its own permissions, and check the specific next action against
current state. Dataclass annotations do not enforce types at runtime, so validate untrusted input
before building this object.
Eligibility is not execution. The example requests a resume and asks a separate authorization function. In a real system, resuming needs its own atomic claim on the job, because state can change after this predicate returns.

What the receiver actually checks
A sender tends to validate that fields exist. A receiver has to validate that fields are still true. A handoff acceptance test needs both. The receiver should distinguish at least four states, none of which collapses into another: whether the message arrived, whether context arrived, whether the attached evidence is still valid, and whether a next action is currently authorized. A report can arrive with full context while its evidence is stale; treating that as success hands the receiver an authorization it should not use.
A second fixture earns its place here. The lease stays fresh, but the task state moves between
building the envelope and reading it: the dataset is re-versioned, or another worker scores some of
the same cases. A receiver that trusts a stale task_state can resume against facts that are no
longer current. The revision marker is checked like the lease timestamp, so staleness in either
dimension blocks the same gate.
How often human reviewers agree an envelope "looks complete" is a different quantity from how often state is stale at transfer. Treating one threshold as evidence for the other hides exactly the failures this design is meant to catch.

Rehearsing the handoff before it matters
List every field the receiver says it needs to avoid restarting, not every field the sender finds convenient to log.
Build one case where the lease has expired and one where the data version has moved, and confirm the gate tells them apart rather than treating both as generic failures.
Have a fresh agent with no shared context, or a colleague, receive a report with a deliberately incomplete envelope and state what it would do next.
If the receiver can act on incomplete information because the interface let it, that is a defect in the gate, not a gap in the receiver.
Checking the acceptance boundary
Check the decision
Why this matters in a lab
Multi-agent systems and long eval runs live or die at their handoffs. An orchestrator that accepts a subagent's "done" without evidence, a resumed job that trusts a checkpoint without checking which revision it belongs to, and a teammate who inherits an evaluation harness without the list of known issues all fail the same way. Chapter 13 of the book makes the worker-recovery version concrete: a replacement must recover from records, not by asking the model what happened. Resuming an agent job without repeating its side effects covers the side-effect half of the problem.
An interviewer for an AI agents or research engineer role could ask: design the message a subagent returns to the agent that dispatched it. A strong answer lists the envelope's fields (state, revision, evidence references, what is unresolved, what the subagent was not allowed to decide), says how the receiver checks freshness and revision, and names the failure the design prevents.
What would prove this wrong
If receivers that get a bare "done" recover the context themselves as reliably and as cheaply as receivers that get an envelope, the envelope is overhead. That is testable: run the same research tasks through subagents that return free text and subagents that return the envelope, and count reruns, repeated questions and wrong merges. This site has not run that comparison yet. Until someone does, treat the envelope as the safer default, not a measured win.
The book shows how an assignment outlives the process that holds it, and how a replacement worker recovers from records.

