-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Python: Fix state snapshot to use deepcopy so nested mutations are detected in durable workflow activities #4518
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 2 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
eec0616
Use deepcopy for state snapshot to detect nested mutations (#4500)
moonbox3 8f3655a
Python: Fix state snapshot to use deepcopy so nested mutations are de…
moonbox3 b28c996
Address PR review: remove report, extract testable helpers (#4500)
moonbox3 284574a
Apply pre-commit auto-fixes
moonbox3 f9e9790
Add regression tests proving shallow copy bug and deep copy isolation…
moonbox3 13bbafe
Add integration test exercising full activity code path (#4500)
moonbox3 68e56b0
Address review feedback for #4518: review comment fixes
moonbox3 98ca42c
Merge remote-tracking branch 'origin/main' into agent/fix-4500-1
moonbox3 b7143c6
Address PR review feedback for state snapshot diff
moonbox3 1bf5054
Apply pre-commit auto-fixes
moonbox3 af343c4
fix: remove unused _compute_state_updates from _app.py (#4518)
moonbox3 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| # Reproduction Report — Issue #4500 | ||
| **Python: [Bug]: State updates not propagated to the next activity with durable function and declarative workflow** | ||
|
|
||
| *Generated: 2026-03-06 04:28:49 UTC* | ||
|
|
||
| ## Result | ||
|
|
||
| | Field | Value | | ||
| |-------|-------| | ||
| | Status | `reproduced` | | ||
| | Failure observed | `yes` | | ||
| | Evidence strength | `high` | | ||
| | Confidence | `high` | | ||
| | Failing test | `/Users/evmattso/git/agent-framework-2/.worktrees/agent/fix-4500-1/python/packages/azurefunctions/tests/test_shallow_copy_bug.py` | | ||
|
moonbox3 marked this conversation as resolved.
Outdated
moonbox3 marked this conversation as resolved.
Outdated
moonbox3 marked this conversation as resolved.
Outdated
moonbox3 marked this conversation as resolved.
Outdated
|
||
| | Gate passed | Yes | | ||
|
|
||
| ## Files Examined | ||
|
|
||
| python/packages/azurefunctions/agent_framework_azurefunctions/_app.py, python/packages/core/agent_framework/_workflows/_state.py, python/packages/azurefunctions/agent_framework_azurefunctions/_serialization.py, python/packages/azurefunctions/tests/test_app.py | ||
|
|
||
| ## Tests Run | ||
|
|
||
| python/packages/azurefunctions/tests/test_shallow_copy_bug.py | ||
|
|
||
| ## Finding | ||
|
|
||
| The bug is confirmed: `dict()` at line 303 of `_app.py` creates a shallow copy that shares nested object references with the state. When an executor mutates nested values in place, both `original_snapshot` and `current_state` reflect the same mutation, producing an empty diff and causing state updates to not propagate to downstream activities. The test suite demonstrates this with nested dicts, lists, and contrasts with `copy.deepcopy()` which correctly preserves the original snapshot. | ||
|
|
||
|
moonbox3 marked this conversation as resolved.
Outdated
|
||
| ## Full Analysis | ||
|
moonbox3 marked this conversation as resolved.
Outdated
moonbox3 marked this conversation as resolved.
Outdated
|
||
|
|
||
| Now I can see the bug clearly. Line 303 uses `dict()` (shallow copy). Let me find the `State` class and existing tests.Now I understand the bug. Let me look at `deserialize_value` and the `export_state` method to understand the full flow, then write a test.Now I have a clear understanding of the bug. The issue is at line 303: `original_snapshot = dict(deserialized_state)` creates a shallow copy. When the activity mutates a nested value (like a dict or list) in place, the mutation is reflected in both `deserialized_state` and `original_snapshot`, making the diff at line 334 see no changes. | ||
|
|
||
| Let me write a focused test to reproduce this.Now I clearly see the issue. The `original_snapshot` at line 303 shares references to nested objects with `deserialized_state`, which is then imported into `shared_state` at line 304. When the executor mutates nested state values, the mutations are visible in `original_snapshot` too, making the diff at line 334 produce no updates. | ||
|
|
||
| Let me write a minimal test to demonstrate this.Now let me write a minimal, focused test that demonstrates the shallow copy bug.All 5 tests pass, confirming the bug. The key tests (`test_shallow_copy_loses_nested_mutations`, `test_shallow_copy_loses_new_key_in_nested_dict`, `test_shallow_copy_loses_list_mutations`) pass by asserting `updates == {}` — proving that the shallow copy causes nested mutations to be invisible in the diff. The `test_deep_copy_preserves_nested_mutations` test shows that `copy.deepcopy()` correctly detects changes. | ||
|
moonbox3 marked this conversation as resolved.
Outdated
|
||
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
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
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.
Uh oh!
There was an error while loading. Please reload this page.