Skip to content

fix(designer): scope Set Variable dropdown for pasted scopes#9403

Merged
lambrianmsft merged 2 commits into
Azure:mainfrom
lambrianmsft:lambrian/scope-paste-fix-followup
Jul 18, 2026
Merged

fix(designer): scope Set Variable dropdown for pasted scopes#9403
lambrianmsft merged 2 commits into
Azure:mainfrom
lambrianmsft:lambrian/scope-paste-fix-followup

Conversation

@lambrianmsft

Copy link
Copy Markdown
Contributor

Commit Type

  • feature - New functionality
  • fix - Bug fix
  • refactor - Code restructuring without behavior change
  • perf - Performance improvement
  • docs - Documentation update
  • test - Test-related changes
  • chore - Maintenance/tooling

Risk Level

  • Low - Minor changes, limited scope
  • Medium - Moderate changes, some user impact
  • High - Major changes, significant user/system impact

What & Why

Customers reported that after copy-pasting a scope (for example a Condition containing a Set Variable) into another scope, the pasted Set Variable's Name dropdown showed the wrong variables: empty for nested Conditions, or leaking out-of-scope / parallel-branch variables when pasting into a For each. That let a user reference an uninitialized variable and break scope, even though code view showed the variable correctly.

Root cause is broken graph metadata on the pasted node. Two coordinated defects:

  1. copypaste.ts (pasteScopeOperation) seeded the pasted top node's parentNodeId with the relationship parentId, which for a branch-top paste is an edge-placement card id (e.g. Condition-elseActions-#subgraph), not a nodesMetadata key. The parent-chain walk in getUpstreamNodeIds dead-ends there and never climbs to the ancestor scope where the variable is initialized.
  2. pasteScopeInWorkflow.ts reducer copied each pasted node's metadata into state by reference, then reassigned a new corrected object to the local nodesMetadata[nodeId]. Because state still held the old reference, the correction never reached state, so the final updateAllUpstreamNodes recompute read the stale card-id parentNodeId.

Approach

  • Seed the pasted top node's parentNodeId with the containing graph id (graphId, or undefined at root) so it references a real nodesMetadata key that the parent-chain walk can climb.
  • Persist the corrected metadata back into state in the reducer (state.nodesMetadata[nodeId] = nodesMetadata[nodeId]) so the fix survives to the upstream-node recompute.
  • Restore strict variable scoping in the VARIABLE_NAME editor branch (getEditorAndOptions) so the dropdown only offers variables that are genuinely upstream, instead of falling back to all variables.

Both the designer (v1) and designer-v2 copies are updated in lockstep.

Impact of Change

  • Users: The Set Variable Name dropdown now shows exactly the in-scope variables for pasted scopes: ancestor-scope variables resolve correctly, and out-of-scope / parallel-branch variables no longer leak in. Prevents accidentally referencing an uninitialized variable.
  • Developers: parentNodeId on a pasted scope node is now guaranteed to be a valid nodesMetadata key (or undefined at root). No API changes.
  • System: No performance or architectural impact; metadata and resolution paths unchanged apart from the fix.

Test Plan

  • Unit tests added/updated
  • E2E tests added/updated
  • Manual testing completed
  • Tested in: standalone designer (repro from customer screenshots), Vitest

Added a paste-matrix scope-correctness suite (pasteScopeMatrix.spec.ts, v1 + v2) that drives the real pasteScopeInWorkflow reducer, then resolves the nested Set Variable via getUpstreamNodeIds + getAvailableVariables. It covers the full matrix of Set Variable nested in a copied {Condition, Scope} pasted into {Condition, Scope, For each}, asserting the in-path Initialize Variable appears and a separate-path Initialize Variable is excluded, plus positive cases where a target downstream of both vars sees both. Verified these tests fail when the reducer persist line is removed, so they genuinely guard the fix. Also added reducer metadata tests and copypaste helper tests. Targeted Vitest is green and Biome is clean.

Contributors

Screenshots/Videos

N/A

Copilot AI review requested due to automatic review settings July 16, 2026 06:22
@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

🤖 AI PR Validation Report

PR Review Results

Thank you for your submission! Here's detailed feedback on your PR title and body compliance:

PR Title

  • Current: fix(designer): scope Set Variable dropdown for pasted scopes
  • Issue: None — valid fix: prefix with scope, and descriptive of the actual change.
  • Recommendation: No changes needed.

Commit Type

  • Exactly one type selected: fix — correct for this bug fix.
  • No note needed; matches the title prefix.

Risk Level

  • Exactly one box selected (Low) and the risk:low label matches the body selection.
  • This matches the advised estimate: the change is a targeted bug fix confined to the designer/designer-v2 paste + variable-dropdown logic. It does not touch logic-apps-shared, extension distribution, auth/security, or repo governance, so low is correct.

What & Why

  • Current: Clear customer-reported repro, precise root-cause analysis of the two coordinated defects (card-id parentNodeId seeding and by-reference metadata copy), and an Approach section.
  • Issue: None.
  • Recommendation: No changes needed.

Impact of Change

  • All three audiences addressed (Users, Developers, System).
  • Recommendation:
    • Users: Well described — in-scope variables now resolve correctly for pasted scopes.
    • Developers: Well described — parentNodeId guaranteed valid; no API changes.
    • System: Well described — no perf/architecture impact.

Test Plan

  • Unit tests added/updated (confirmed in diff): copypaste.spec.ts, pasteScopeInWorkflow.spec.ts, pasteScopeMatrix.spec.ts, and getEditorAndOptions.spec.ts in both designer and designer-v2, including a mutation check that the tests fail without the fix. Manual testing also noted.

⚠️ Contributors

  • Section is blank. If any PMs, designers, or reviewers contributed (e.g., the customer repro), credit them. Non-blocking.

⚠️ Screenshots/Videos

  • Marked N/A. The index.tsx change alters dropdown option content/scoping (logic), not visual styling, so screenshots aren't required. A short before/after clip of the Set Variable dropdown would still help reviewers. Non-blocking.

Summary Table

Section Status Recommendation
Title No changes needed
Commit Type No changes needed
Risk Level Low is correct and matches label
What & Why No changes needed
Impact of Change No changes needed
Test Plan Unit tests present and verified
Contributors ⚠️ Credit contributors if any
Screenshots/Videos ⚠️ Optional clip of dropdown behavior

All required checks pass. This PR is compliant and ready to merge. Consider addressing the two non-blocking nudges (Contributors, optional screenshot).


Powered by: Copilot CLI (claude-opus-4.8) | Last updated: Fri, 17 Jul 2026 06:15:58 GMT

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.

Pull request overview

This PR fixes incorrect variable scoping after copy/pasting scoped actions (e.g., a Condition containing Set Variable) by ensuring pasted nodes have valid parentNodeId/graph metadata, recomputing upstream metadata reliably, and making the variable-name dropdown strictly honor upstream scope (v1 + v2), with new unit coverage to prevent regressions.

Changes:

  • Correct pasted scope metadata so parentNodeId points at a real nodesMetadata key (and persist the corrected metadata into reducer state).
  • Remove the “fallback to all variables” behavior so VARIABLE_NAME dropdown only shows genuinely upstream variables.
  • Add targeted Vitest suites (including paste-matrix coverage) to validate scoping across paste targets and nesting patterns.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
libs/designer/src/lib/ui/panel/nodeDetailsPanel/tabs/parametersTab/index.tsx Removes all-variables fallback; dropdown options now come strictly from upstream-scoped variables.
libs/designer/src/lib/ui/panel/nodeDetailsPanel/tabs/parametersTab/test/getEditorAndOptions.spec.ts Updates tests to assert strict upstream-only variable dropdown behavior.
libs/designer/src/lib/core/parsers/pasteScopeInWorkflow.ts Persists corrected graphId/parentNodeId back into reducer state to avoid stale metadata references.
libs/designer/src/lib/core/parsers/test/pasteScopeMatrix.spec.ts Adds end-to-end paste matrix tests validating variable scoping for pasted scopes.
libs/designer/src/lib/core/parsers/test/pasteScopeInWorkflow.spec.ts Adds regression tests asserting corrected parentNodeId persistence in state.
libs/designer/src/lib/core/actions/bjsworkflow/copypaste.ts Fixes pasted top-node parentNodeId seeding; extends upstream token seeding for scope paste; triggers upstream recompute after paste.
libs/designer/src/lib/core/actions/bjsworkflow/test/copypaste.spec.ts Adds unit tests for upstream extension helper used during scope paste token seeding.
libs/designer-v2/src/lib/ui/panel/nodeDetailsPanel/tabs/parametersTab/index.tsx Mirrors v1: strict upstream-only variable dropdown options.
libs/designer-v2/src/lib/ui/panel/nodeDetailsPanel/tabs/parametersTab/test/getEditorAndOptions.spec.ts Mirrors v1: asserts strict upstream-only variable dropdown behavior.
libs/designer-v2/src/lib/core/parsers/pasteScopeInWorkflow.ts Mirrors v1: writes corrected metadata back into state to avoid stale references.
libs/designer-v2/src/lib/core/parsers/test/pasteScopeMatrix.spec.ts Mirrors v1: paste matrix tests for variable scoping correctness.
libs/designer-v2/src/lib/core/parsers/test/pasteScopeInWorkflow.spec.ts Mirrors v1: regression tests for corrected parentNodeId persistence.
libs/designer-v2/src/lib/core/actions/bjsworkflow/copypaste.ts Mirrors v1: metadata seeding + upstream token seeding extension + upstream recompute after paste.
libs/designer-v2/src/lib/core/actions/bjsworkflow/test/copypaste.spec.ts Mirrors v1: unit tests for upstream extension helper.

Comment thread libs/designer/src/lib/core/actions/bjsworkflow/copypaste.ts
Comment thread libs/designer-v2/src/lib/core/actions/bjsworkflow/copypaste.ts
When a Condition (or any scope) containing a Set Variable was copy-pasted
into another scope — a Condition branch or a For each body — the pasted
Set Variable's Name dropdown showed the wrong set of variables: empty in
nested Conditions, or leaking out-of-scope variables (including ones from a
parallel branch) when pasted into a For each. Selecting such a variable let
the user reference an uninitialized variable and break scope.

Root cause (two coordinated defects in the scope-paste path):

1. pasteScopeOperation seeded the pasted top node's `parentNodeId` with the
   relationship `parentId`, which is an edge-placement node (e.g. a
   `<scope>-#subgraph` card) and is not a nodesMetadata key. The parent-chain
   walk in getUpstreamNodeIds therefore could not climb to ancestor scopes.

2. pasteScopeInWorkflow recomputed the correct `parentNodeId` (the containing
   graph id) but assigned it to a detached object: the earlier metadata copy
   loop had already written the pasted node's entry into state by reference, so
   the correction never reached state.nodesMetadata. The final upstream
   recompute (updateAllUpstreamNodes -> getTokenNodeIds) then read the stale
   placeholder parentNodeId and mis-scoped the dropdown.

Fix:
- copypaste.ts: set the pasted scope node's `parentNodeId` to the containing
  `graphId` (undefined at root) instead of the edge-placement `parentId`.
- pasteScopeInWorkflow.ts: write the corrected metadata back into
  state.nodesMetadata so the recomputed graphId/parentNodeId persist.
- Restore strict upstream scoping in the Set Variable editor (getEditorAndOptions)
  and add extendUpstreamNodeIdsForScopePaste so token initialization seeds the
  enclosing scope's upstream tokens.

Tests:
- pasteScopeInWorkflow.spec.ts (v1 + v2): the pasted node's parentNodeId is
  persisted as the containing graph id (not the subgraph card) and stays
  undefined at root.
- copypaste.spec.ts (v1 + v2): extendUpstreamNodeIdsForScopePaste surfaces
  ancestor variables while excluding parallel-branch variables.
- getEditorAndOptions.spec.ts (v1 + v2): strict scoping — empty upstream yields
  no options; scoped upstream yields only in-scope variables.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: af9ea0d5-71e4-45d9-9790-0edc869beadd
@lambrianmsft
lambrianmsft force-pushed the lambrian/scope-paste-fix-followup branch from 73f93da to 5ba5f13 Compare July 16, 2026 23:41
@lambrianmsft lambrianmsft added the risk:low Low risk change with minimal impact label Jul 17, 2026
@lambrianmsft
lambrianmsft merged commit c5ac424 into Azure:main Jul 18, 2026
64 of 67 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr-validated risk:low Low risk change with minimal impact

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants