Python: raise instead of silently returning a stale checkpoint from get_latest - #7832
Open
Oleg Solozobov (dev404ai) wants to merge 3 commits into
Open
Conversation
Oleg Solozobov (dev404ai)
temporarily deployed
to
github-app-auth
August 23, 2026 11:28 — with
GitHub Actions
Inactive
Oleg Solozobov (dev404ai)
temporarily deployed
to
github-app-auth
August 23, 2026 11:28 — with
GitHub Actions
Inactive
Oleg Solozobov (dev404ai)
temporarily deployed
to
github-app-auth
August 23, 2026 11:29 — with
GitHub Actions
Inactive
Oleg Solozobov (dev404ai)
temporarily deployed
to
github-app-auth
August 23, 2026 11:29 — with
GitHub Actions
Inactive
Oleg Solozobov (dev404ai)
requested a review
from Jose Alvarez (jpalvarezl)
as a code owner
September 6, 2026 07:33
Oleg Solozobov (dev404ai)
deployed
to
github-app-auth
September 6, 2026 07:33 — with
GitHub Actions
Active
Copilot started reviewing on behalf of
Oleg Solozobov (dev404ai)
September 6, 2026 07:33
View session
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The implementation introduces an inconsistent flat-directory contract and performs synchronous decoding on the event loop.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Updates file-backed checkpoint recovery to raise when the newest checkpoint cannot be decoded instead of returning stale state.
Changes:
- Selects the latest checkpoint from JSON metadata before decoding.
- Adds filesystem consistency and corruption checks.
- Expands tests for decoding, metadata, concurrency, and filesystem edge cases.
File summaries
| File | Description |
|---|---|
python/packages/core/agent_framework/_workflows/_checkpoint.py |
Implements metadata-based latest-checkpoint selection and validation. |
python/packages/core/tests/workflow/test_checkpoint.py |
Adds comprehensive get_latest behavior tests. |
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 3
- Review effort level: Balanced
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
Oleg Solozobov (dev404ai)
deployed
to
github-app-auth
September 6, 2026 07:54 — with
GitHub Actions
Active
Oleg Solozobov (dev404ai)
deployed
to
github-app-auth
September 6, 2026 08:27 — with
GitHub Actions
Active
Oleg Solozobov (dev404ai)
deployed
to
github-app-auth
September 6, 2026 08:29 — with
GitHub Actions
Active
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation & Context
Before this change,
FileCheckpointStorage.get_latest()selected from the results oflist_checkpoints(), which logs read errors and skips the affected files. If the newest saved checkpoint could not be decoded, recovery silently returned an older checkpoint orNone.This is reachable with the existing reader security policy:
save()can encode a value that a later reader refuses to deserialize underallowed_checkpoint_types. The review also identified a metadata variant: an invalidtimestampcan be saved successfully, then skipped during selection. Both cases must surface as recovery errors rather than silently discard newer state.Description & Review Guide
workflow_name,timestampandcheckpoint_idfields, validate the selection, and decode only that checkpoint. Read and decode in one worker thread, using the same JSON captured during selection and a shared private helper that also servesload(). This preserves the reader's security policy without reopening a path that could now contain different data.WorkflowCheckpointException, preserving the file context or the decoder's actionable error. ID redirection, duplicate JSON keys, root pickle envelopes, unreadable files, non-regular checkpoint paths, and observed changes during a scan also raise instead of permitting silent fallback.Unreadable JSON or a file without an identifiable workflow blocks selection for every workflow sharing the directory, because it might hide the requested workflow's newest checkpoint. Invalid selection fields for a clearly different workflow are ignored. Older payloads are not decoded merely to find the newest checkpoint.
The scan includes nested directories, so checkpoint IDs accepted by
save()andload()remain discoverable. Readable directories without checkpoint files do not cause an error. Directory aliases within the storage root are visited once, including links to ancestors; paths resolving outside the root are rejected. Temporary.json.tmpfiles remain ignored, and existing empty and relative checkpoint ID aliases remain supported.File versions are checked before and after reading, then checked again with file membership and the versions of every visited directory before the scan is accepted. These checks rely on filesystem change reporting and atomic writers such as the existing
save(). They detect observed concurrent changes and allow the caller to retry; they do not provide transactional locking. A write after validation belongs to a later snapshot. Equal timestamps retain directory iteration order.Two alternatives would change the wrong contract. Enforcing the reader's allowed types during
save()would prevent a writer and a later reader from using different policies. Makinglist_checkpoints()raise would remove its existing tolerance. This change preserves both behaviors while making recovery errors explicit. Public signatures, the stored format, write behavior and other storage backends are unchanged. The Azure Cosmos backend remains outside this PR and was not tested locally.Regression tests cover the original undecodable-payload failure, malformed timestamps with and without an older checkpoint, missing or invalid selection fields, ID redirection, mixed naive/aware dates, JSON ambiguity, file errors, concurrent writers, and decoding the selected snapshot once. Compatibility tests cover tolerant listing, older undecodable payloads, allowed custom types, timestamp offsets, ID aliases, temporary files, nested paths, shared file names across directories, directory links and relative storage roots. A synchronized regression requires another async task to run while decoding is paused; it fails if decoding returns to the event-loop thread. Additional tests cover nested corruption, access failures and changes during both scans.
Local verification on macOS with Python 3.13.7: 214 checkpoint tests passed. The complete workflow test directory produced 1046 passed, 2 skipped and 2 xfailed, with two warnings from unchanged tests. Ruff lint and formatting passed; scoped Pyright, mypy, Pyrefly, ty and Zuban checks passed. Linux, Windows and Azure integrations were not run locally. These results are from the local follow-up on b5d9ec7; they do not claim an upstream CI pass or verification against current main.
Related Issue
Closes #7831
Contribution Checklist
breaking changelabel (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.The complete build and unit-test checklist items remain unchecked pending upstream CI. The non-breaking checkbox remains unchecked for maintainer review of the stricter recovery error policy: unreadable or unidentified JSON now stops recovery instead of being silently skipped. The flat-directory restriction has been removed.