DYN-10572: Honor per-port Use Levels on variadic DSVarArgFunction nodes#17147
Conversation
There was a problem hiding this comment.
See the ticket for this pull request: https://jira.autodesk.com/browse/DYN-10572
There was a problem hiding this comment.
Pull request overview
Fixes DYN-10572 by ensuring per-port Use Levels and lacing-driven replication guides are applied correctly on variadic zero-touch nodes (DSVarArgFunction) by handling level/replication for variadic inputs before they are packed into a single argument, and preventing the existing post-pack pass from double-wrapping.
Changes:
- Added a
NodeModelvirtual hook (LevelAndReplicationGuideInputCount) to bound the post-packUseLevelAndReplicationGuidepass. - Updated
ZeroTouchVarArgNodeController.BuildOutputAstto applyAtLeveland replication guides per variadic input prior to packing. - Added regression tests and new
.dynfixtures coveringString.Concat,String.Join, andList.Joinvariadic use-level behavior.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| test/DynamoCoreTests/Nodes/StringTests.cs | Adds NUnit regression tests for variadic String.Concat/String.Join per-port Use Levels and rank independence. |
| test/DynamoCoreTests/Nodes/ListTests.cs | Adds NUnit regression test for List.Join honoring Use Levels on variadic ports. |
| test/core/string/TestJoinStringUseLevelsOnVariadicPort.dyn | Fixture graph exercising bounded post-pack + pre-pack variadic handling for String.Join. |
| test/core/string/TestConcatStringUseLevels.dyn | Fixture graph validating Use Levels on a non-first variadic port for String.Concat. |
| test/core/string/TestConcatStringNestedListIndependence.dyn | Fixture graph validating rank/replication independence across variadic ports for String.Concat. |
| test/core/list/TestListJoinUseLevelsOnVariadicPort.dyn | Fixture graph validating variadic Use Levels for List.Join with lacing disabled. |
| src/DynamoCore/PublicAPI.Unshipped.txt | Declares the new NodeModel.LevelAndReplicationGuideInputCount API addition. |
| src/DynamoCore/Graph/Nodes/ZeroTouch/DSVarArgFunction.cs | Implements the bounded post-pack behavior via override and applies pre-pack per-variadic-port level/replication handling. |
| src/DynamoCore/Graph/Nodes/NodeModel.cs | Introduces the virtual hook and bounds UseLevelAndReplicationGuide to the intended subset of inputs. |
jasonstratton
left a comment
There was a problem hiding this comment.
Approved after code review ... no changes required
…ing.Concat Add two failing NUnit tests under StringTests.cs and their .dyn fixtures to lock in the desired post-fix behavior of per-port Use Levels and rank independence on variadic DSVarArgFunction nodes (String.Concat). These tests are expected to fail on master and pass after TASK 3 (the pre-pack per-port AtLevel/replication-guide wiring in ZeroTouchVarArgNodeController.BuildOutputAst). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds a protected virtual hook so variadic nodes (DSVarArgFunction) can scope the post-pack UseLevelAndReplicationGuide pass to non-variadic prefix ports. Default returns the raw input count, preserving existing behavior for all non-variadic nodes.
ZeroTouchVarArgNodeController.BuildOutputAst now wraps each variadic input with AtLevel and lacing-driven replication guides BEFORE packing them into an ExprListNode, since those annotations are inert when carried inside the list literal. DSVarArgFunction overrides LevelAndReplicationGuideInputCount so the post-pack NodeModel pass scopes to the non-variadic prefix only, preventing double-wrap. Fixes per-port Use Levels and per-port replication-rank independence for String.Concat, String.Join, List.Join and any other DSVarArgFunction.
…r variadic nodes Adds regression tests for String.Join (separator prefix port + variadic port) and List.Join (pure-variadic over IList) confirming the per-port Use Levels fix generalizes across DSVarArgFunction shapes. The String.Join test also exercises the bounded post-pack UseLevelAndReplicationGuide pass with LevelAndReplicationGuideInputCount == 1, while the List.Join test exercises the count == 0 path on a [IsLacingDisabled] variadic node.
dfd2226 to
31926a9
Compare
|



Closes https://autodesk.atlassian.net/browse/DYN-10572
Purpose
Fixes per-port
Use Levelson every variadicDSVarArgFunctionnode (e.g.,String.Concat,String.Join,List.Join).Root cause:
ZeroTouchVarArgNodeController.BuildOutputAstpacks all variadic inputs into a singlestring[]/IListargument beforeNodeModel.UseLevelAndReplicationGuideruns, so per-portUse Levels/Level/ lacing settings beyond the first variadic slot were silently dropped. As a consequence, a nested list on one variadic port would also reshape the replication rank applied to other ports.Fix:
NodeModel.LevelAndReplicationGuideInputCountthat bounds the post-pack level/replication-guide pass. Default is a no-op (returns the raw input count), preserving behavior on non-variadic nodes.ZeroTouchVarArgNodeController.BuildOutputAst, applyAtLeveland lacing-driven replication guides to each variadic input before packing them intoargPack.DSVarArgFunctionto scope the post-pack pass to non-variadic prefix ports only, preventing double-wrap.Declarations
Check these if you believe they are true
API additions:
virtual Dynamo.Graph.Nodes.NodeModel.LevelAndReplicationGuideInputCount(int rawInputCount) -> int(entry added tosrc/DynamoCore/PublicAPI.Unshipped.txt).Release Notes
Variadic nodes (e.g.,
String.Concat,String.Join,List.Join) now honorUse Levelson every variadic port, and per-port replication is now independent of other ports' rank. Previously, only the first variadic port'sUse Levelssetting was applied and a nested list on one port would unintentionally reshape the replication of other ports.Reviewers
(FILL ME IN) Reviewer 1
FYIs
(FILL ME IN, Optional)
Implementation plan & task tracking
h1. DYN-10572 Per-port {{Use Levels}} on {{DSVarArgFunction}} — Implementation Plan
h2. Overview
Fix {{String.Concat}} (and every other variadic zero-touch node — {{String.Join}}, {{List.Join}}, …) so per-port {{Use Levels}} works on every variadic port and so a nested list on one port no longer reshapes the replication of other ports. Root cause: {{ZeroTouchVarArgNodeController.BuildOutputAst}} packs all variadic inputs into a single {{string[]}} argument before {{NodeModel.UseLevelAndReplicationGuide}} runs, so per-port level/lacing settings beyond the first variadic slot are silently dropped.
Port naming ({{string0/string1/…}}) is intentionally left unchanged — see "What We're NOT Doing".
h2. Current State Analysis
h3. Key Discoveries
h2. Desired End State
Verify by running {{dotnet test src/DynamoCoreTests/DynamoCoreTests.csproj --filter "Name
ConcatString|NameVarArgFunction|Name~AtLevel"}} and by reproducing the reporter's graph in DynamoSandbox.h2. What We're NOT Doing
h2. Implementation Approach
Override-style pre-pack handling in {{ZeroTouchVarArgNodeController.BuildOutputAst}}: apply {{AtLevel}} and lacing-driven replication guides to each variadic input AST individually, then pack.
Add a virtual hook on {{NodeModel}} so the post-pack {{UseLevelAndReplicationGuide}} operates only on non-variadic prefix ports, preventing double-wrap.
New tests on {{String.Concat}} (pure variadic), {{String.Join}} (prefix + variadic), {{List.Join}} (pure variadic over {{IList}}) to prove the fix is general.
Manual verification in Sandbox against the reporter's screenshots.
h3. TASK 1: Reproduce the bug with failing tests [HIGH PRIORITY]
Status: DONE
Milestone: Two new NUnit tests fail on {{master}}, proving the bug.
h3. TASK 2: Add a virtual hook to scope level/lacing pass on packed variadic nodes [HIGH PRIORITY]
Status: DONE
Milestone: {{NodeModel}} exposes an extension point bounding the range of inputs touched by {{UseLevelAndReplicationGuide}}; default is a no-op.
h3. TASK 3: Apply per-port levels and replication guides on variadic inputs before packing [HIGH PRIORITY]
Status: DONE
Milestone: {{ZeroTouchVarArgNodeController.BuildOutputAst}} applies {{Use Levels}} + lacing replication guides per variadic element pre-pack; {{DSVarArgFunction}} overrides the new hook to scope the post-pack pass to non-variadic prefix ports.
h3. TASK 4: Generalize verification across {{DSVarArgFunction}} nodes [MEDIUM PRIORITY]
Status: DONE
Milestone: Sister variadic nodes ({{String.Join}}, {{List.Join}}) honor per-port {{Use Levels}} and replicate independently, with regression tests.
h3. TASK 5: Manual verification against the reporter's repro [MEDIUM PRIORITY]
Status: DONE
Milestone: DynamoSandbox reproduces the reporter's expected behavior.
h3. TASK 6: PR + repo conventions [LOW PRIORITY]
Status: DONE
Milestone: PR is review-ready and conforms to repo conventions.