Repository navigation
.NET: fix(dotnet): persist workflow scope aliases consistently #9749
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
Draft
Vincent Biret (baywet)
wants to merge
12
commits into
main
Choose a base branch
from
fix/workflow-scope-alias-persistence
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+2,140
−79
Draft
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
0313abb
fix(dotnet): persist workflow scope aliases consistently
baywet 41207a5
fix(dotnet): migrate legacy workflow scope state
baywet a4d5d07
fix(dotnet): complete workflow state migration before resuming
baywet 7a089de
fix(dotnet): restore interpreter state before checkpoint hooks
baywet cdc5ef0
fix(dotnet): align plain state helpers and restore rollback
baywet bbcd6f6
fix(workflows): preserve legacy helper state and clean up failed rest…
baywet 3bdf741
fix(workflows): keep expression snapshots read-only and guard scope c…
baywet 8ca1b34
fix(workflows): track canonical scope ownership explicitly
baywet cb2c029
Merge branch 'main' into fix/workflow-scope-alias-persistence
baywet fc62baa
Refactor legacy ownership filtering into two phases
baywet 2bb948e
fix(workflows): preserve managed initialization ownership
baywet 56f5385
fix(workflows): retain native payloads during initialization migration
baywet 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
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,77 @@ | ||
| --- | ||
| status: proposed | ||
| contact: baywet | ||
| date: 2026-10-28 | ||
| deciders: westey-m | ||
| --- | ||
|
|
||
| # Explicit ownership for .NET declarative Local state | ||
|
|
||
| ## Context and Problem Statement | ||
|
|
||
| Declarative `Local` and `Topic` variables share canonical `Local` storage and a sensitivity sidecar. Older | ||
| checkpoints can instead contain declarative values in physical `Topic` storage. Code-first executors can also use | ||
| physical `Topic` independently, including the same key as a declarative variable. | ||
|
|
||
| Sensitivity metadata alone cannot identify which physical value it describes. A preflight check cannot prevent | ||
| this ambiguity when different fan-out executors queue raw `Topic` and canonical `Local` writes in the same | ||
| superstep: each executor sees only its own pending updates. | ||
|
|
||
| ## Decision Drivers | ||
|
|
||
| - Preserve unrelated code-first state and the native representation of canonical values. | ||
| - Continue reading and selectively migrating older checkpoints without guessing assignment order. | ||
| - Keep declarative storage conventions out of the language-neutral workflow state manager. | ||
| - Avoid full-scope scans for individual reads and writes. | ||
| - Preserve read-only expression snapshots and the existing checkpoint restoration publication boundary. | ||
|
|
||
| ## Considered Options | ||
|
|
||
| ### Infer ownership from sensitivity metadata and visible keys | ||
|
|
||
| Good: no additional persisted metadata or core API changes. | ||
| Bad: executor-private pending updates defeat the preflight, and committed sensitivity metadata cannot distinguish | ||
| canonical ownership from an older declarative `Topic` value. | ||
|
|
||
| ### Validate combined updates before publication | ||
|
|
||
| Good: a validator can inspect updates from every executor before they are committed. | ||
| Bad: this needs a new language-neutral validation extension point or declarative scope knowledge in core | ||
| publication. Rejecting every same-key pair would also prevent independently owned raw and canonical values. | ||
|
|
||
| ### Persist versioned canonical ownership separately | ||
|
|
||
| Good: plain helpers, wrapped contexts, and restoration can distinguish ownership after concurrent publication, | ||
| without changing native values or public workflow APIs. | ||
| Bad: writes and checkpoints include one additional private entry per canonical Local key. Older runtimes do not | ||
| understand that ownership when both physical scopes contain the same key. | ||
|
|
||
| ## Decision Outcome | ||
|
|
||
| Chosen option: "Persist versioned canonical ownership separately", because the ambiguity belongs to declarative | ||
| storage interpretation and does not require changing core publication semantics. | ||
|
|
||
| For each new canonical `Local` assignment or migrated legacy entry, persist integer version `1` under the same key | ||
| in the private `__Microsoft_Agents_AI_Workflows_Declarative_Ownership:Local` scope, alongside the existing value and | ||
| sensitivity sidecar. No ownership entry is needed for other scopes. | ||
|
|
||
| A recognized ownership entry means the sensitivity sidecar describes canonical `Local` state. Any same-key raw | ||
| `Topic` value remains independent and must not be read as a legacy value, migrated, or deleted by declarative | ||
| helpers or restoration. This permits mixed fan-out writes to coexist. Unsupported ownership versions are rejected | ||
| when consulted to disambiguate a `Topic` entry. | ||
|
|
||
| Without ownership metadata, preserve the existing conservative compatibility rules: a metadata-marked `Topic` key | ||
| without a `Local` value is legacy; overlapping marked values are rejected before migration writes; unmarked raw | ||
| `Topic` entries remain untouched. Visible unmarked collisions still reject new canonical assignments unless | ||
| canonical ownership is already recorded. Missing ownership alone does not trigger a write during restoration. | ||
|
|
||
| Migration records canonical ownership before removing only the migrated legacy key. Plain helper null updates | ||
| physically delete the canonical value, sensitivity, and ownership entries. Wrapped declarative clears retain the | ||
| existing stored blank representation with its sensitivity and ownership. | ||
|
|
||
| Point operations use key-level `PortableValue` existence probes, including for metadata with an explicit `None` | ||
| value. Scope enumeration remains appropriate for whole-state restoration and read-only snapshots, but not for | ||
| each point operation in a growing batch. Ad hoc expression snapshots never persist migration or ownership updates. | ||
|
|
||
| Checkpoint stores must preserve these private entries together with workflow values. This format is | ||
| backward-readable by the new runtime; resuming mixed-scope checkpoints on older runtimes is not supported. |
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
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
Oops, something went wrong.
Oops, something went wrong.
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.