Skip to content

[BREAKING] Python: Reject unsafe functional step replay - #9391

Draft
Atharva Vichare (atty57) wants to merge 2 commits into
microsoft:mainfrom
atty57:fix/python-functional-replay-9385
Draft

Atharva Vichare (atty57) wants to merge 2 commits into
microsoft:mainfrom
atty57:fix/python-functional-replay-9385

Conversation

@atty57

@atty57 Atharva Vichare (atty57) commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

Motivation & Context

Bypassing a cached outer @step skips its inner call counters. A later nested or top-level call can then silently reuse an earlier invocation's result from an order-only cache. Legacy checkpoints remain unsafe even when current arguments are fingerprintable or callers supply explicit replay keys; opaque arguments could also produce unsafe new checkpoints.

Description & Review Guide

  • What are the major changes? Reject checkpointed calls without a stable replay identity before executing their bodies, reject every unverified legacy order-only cache hit, and prevent opaque results from being retained for response-only replay. Preserve versioned cache lookup precedence, add regression coverage, and clarify the step docstrings.
  • What is the impact of these changes? Opaque arguments require an explicit replay_key for checkpoint/HITL replay. Legacy order-only checkpoints are no longer replayable, including flat sequential checkpoints, and must be regenerated in a new run. Existing versioned checkpoints continue to replay. Sequential execution without replay still supports opaque arguments. With explicit keys, nested crash recovery returns [['A', 'B']] and only reruns b.
  • What do you want reviewers to focus on? Rejecting unverified legacy fallback at every execution depth, including direct calls after a cached outer step; keeping verified versioned cache hits ahead of the legacy guard; and the documented checkpoint compatibility change.

This chooses the fail-loud fix from issue option #3 over automatically scoping counters (option #1), keeping the fix focused and requiring explicit invocation identity for opaque inputs.

Related Issue

Fixes #9385

Maintainer agreement on this direction is pending; no competing open PR was found before opening this PR.

AI Assistance

  • No material AI assistance was used.
  • This is an AI-assisted contribution. I reviewed, understood, and verified all submitted content and accept responsibility for it.

AI assistance details: Issue analysis, implementation, tests, docstrings, and this PR description.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR links to an agreed issue with no competing open PR, or the Related Issue section documents a trivial-change or repository-automation exception.
  • This is not a breaking change. If it is a breaking change, add the breaking change label (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 title flags the intentional compatibility change for legacy order-only checkpoints. All 168 functional workflow tests pass, including the nested and mixed nested/direct legacy replay regressions. Ruff lint/format, source and test Pyright, and test mypy checks pass on the touched files. The full poe check is left to CI; maintainer agreement is pending.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Nested legacy replay can still silently return the wrong cached result when arguments are fingerprintable.

1 open finding
What changed in this PR

Adds fail-loud safeguards for functional workflow replay when step arguments lack stable identities.

Changes:

  • Rejects unsafe checkpoint and HITL replay for opaque arguments.
  • Validates legacy cache hits and replayable results.
  • Adds regression tests and updates replay documentation.
File Description
python/​packages/​core/​agent_framework/​_workflows/​_functional.py Adds replay-safety guards and documentation.
python/​packages/​core/​tests/​workflow/​test_functional_workflow.py Adds opaque-argument replay regression tests.

🧠 Review effort: Balanced


💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment thread python/packages/core/agent_framework/_workflows/_functional.py Outdated
@atty57 Atharva Vichare (atty57) changed the title Python: Reject unsafe functional step replay [BREAKING] Python: Reject unsafe functional step replay Oct 14, 2026
@agent-framework-automation agent-framework-automation Bot added the breaking change Usage: [PRs], Target: all PRs that introduce changes that are not backward compatible label Oct 14, 2026

This branch was successfully deployed

1 active deployment
github-app-auth — 9bb14b35 Deployed Oct 14, 2026 by atty57 via add_label #25394
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking change Usage: [PRs], Target: all PRs that introduce changes that are not backward compatible python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: [Bug]: Functional workflow checkpoint replay returns a wrong cached result when a @step calls another @step

2 participants