Unit 06.01: What belongs in a checkpoint
Checkpoints are written after every step, so what you put in one is multiplied by the number of steps and the number of runs.
Two questions per field
Can it be serialised? And would resuming be wrong without it? The first rules things out; the second rules things in.
The code sorts seven candidate fields.
CANDIDATES = [
("the user's question", "yes", "needed to resume"),
("retrieved document ids", "yes", "small, and re-fetching may differ"),
("full text of 40 documents", "no", "large, and re-fetchable from the ids"),
("an open database connection", "no", "not serialisable, and stale on resume"),
("the API key used", "no", "a secret in a durable store"),
("attempts and charged flags", "yes", "resume is wrong without them"),
("a temp file path", "no", "the file may not exist after a restart"),
]
print(f"{'candidate':34} {'keep':5} why")
for item, keep, why in CANDIDATES:
print(f"{item:34} {keep:5} {why}")
keep = sum(1 for _, k, _ in CANDIDATES if k == "yes")
print(f"\n{keep} of {len(CANDIDATES)} belong in the checkpoint")
# Two questions per field: can it be serialised, and would resuming be wrong
# without it? Anything that fails the first cannot be stored; anything that
# fails the second must be.
The open database connection fails the first question - it cannot be serialised, and a deserialised one would be stale anyway. The API key fails a different test: it could be serialised and should not be, because a checkpoint store is now a place secrets live.
The document text is the interesting case. It serialises fine and resuming works without it, because the ids are enough to re-fetch. Storing it anyway is the most common way a checkpoint store becomes a second copy of the corpus.
The mistake this prevents
Two further consequences follow from state being durable. The first is legal rather than technical: a checkpoint holding a customer's question and the documents retrieved for them is a store of personal data, and it needs the same retention limit, access control and deletion path as any other such store. A run resumed from six months ago is a run whose data you kept for six months.
The second bites during deployments. Saved state was written against the schema your code had at the time, so a run paused before a change and resumed after it can arrive at a node expecting a field that no longer exists, or missing one that now does. Version the state schema, and decide before shipping whether in-flight runs are migrated, drained, or failed cleanly.
The mistake is putting the whole model response object into state because it is convenient. These objects carry metadata, token counts and sometimes the full prompt, and none of it is needed to resume. Extract the field you want and store that.
Takeaway
Store what resuming requires and nothing else. Ids over contents, never secrets, and nothing that cannot be serialised - every field is written once per step per run.
