Skip to content

DYN-10572: Honor per-port Use Levels on variadic DSVarArgFunction nodes#17176

Merged
johnpierson merged 2 commits into
masterfrom
eamiri/DYN-10572-variadic-uselevels
Jun 23, 2026
Merged

DYN-10572: Honor per-port Use Levels on variadic DSVarArgFunction nodes#17176
johnpierson merged 2 commits into
masterfrom
eamiri/DYN-10572-variadic-uselevels

Conversation

@eamiri

@eamiri eamiri commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Purpose

Fixes DYN-10572. On variadic zero-touch nodes (String.Concat, String.Join, List.Join, ...) per-port Use Levels were silently ignored, and a nested list on one port reshaped the replication of the other ports.

Root cause: ZeroTouchVarArgNodeController.BuildOutputAst packs the variadic inputs into a single ExprListNode argument before the function call. AtLevel / replication-guide annotations carried inside a list literal are inert at runtime, and DesignScript cannot call a params method with separate arguments — so per-port level/lacing settings were dropped on every variadic port.

A prior attempt (the previous commit on this ticket) applied the annotations to each input and then packed them right back into the inert list literal, so it did not actually take effect (its own three new tests failed). This PR supersedes that approach.

Fix: when any port has Use Levels enabled, the node is routed through a generated wrapper function whose formal parameters are the individual ports:

def __vararg_<guid>_<n>(p0, p1, ...) { return = DSCore.String.Concat(p0, [p1, ...]); }

The per-port AtLevel and the node's lacing replication guides land on the wrapper-call arguments, where they are honored exactly like a non-variadic node (the binary + operator), and the wrapper body packs the already-replicated values per invocation. Graphs with no Use Levels keep the original pack-then-call path, so their behavior — including their lacing — is unchanged.

The earlier NodeModel.LevelAndReplicationGuideInputCount hook and its PublicAPI.Unshipped.txt entry are reverted, as they are no longer needed.

Declarations

Check these if you believe they are true

Release Notes

Variadic nodes (e.g. String.Concat, String.Join, List.Join) now honor Use Levels on every variadic port, and each port's replication is independent of the other ports' list rank.

Reviewers

@QilongTang

Note for testers: the two updated test fixtures reflect the corrected, lacing-faithful semantics. TestJoinStringUseLevelsOnVariadicPort no longer sets Use Levels on the scalar separator (which is meaningless and truncated the result under lacing); TestListJoinUseLevelsOnVariadicPort now expects [[1,3],[2,4]], the result of honoring @L1 on the variadic port, rather than the old inert [1,2,3,4].

FYIs

N/A

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings June 18, 2026 18:53

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

See the ticket for this pull request: https://jira.autodesk.com/browse/DYN-10572

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

Fixes DYN-10572 by ensuring variadic zero-touch nodes (e.g., String.Concat, String.Join, List.Join) honor per-port Use Levels instead of losing AtLevel/replication annotations when variadic inputs are packed into a single list argument.

Changes:

  • Adds a wrapper-function code path for variadic zero-touch nodes when any input port has Use Levels enabled, so replication/AtLevel is applied at call-argument positions (where DesignScript honors them).
  • Keeps the original “pack-then-call” behavior when no Use Levels are enabled to preserve existing lacing/replication semantics.
  • Removes the previously introduced NodeModel.LevelAndReplicationGuideInputCount hook and its PublicAPI.Unshipped.txt entry; updates/adjusts test expectations and test graphs accordingly.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
test/DynamoCoreTests/Nodes/StringTests.cs Updates test commentary to reflect corrected Use Levels semantics for String.Join variadic ports.
test/DynamoCoreTests/Nodes/ListTests.cs Updates expectations for List.Join to assert replicated (non-flattened) results when Use Levels are enabled on a variadic port.
test/core/string/TestJoinStringUseLevelsOnVariadicPort.dyn Adjusts the test graph so the separator port does not use levels (broadcasts), matching intended semantics.
src/DynamoCore/PublicAPI.Unshipped.txt Removes the unshipped API entry for the reverted hook.
src/DynamoCore/Graph/Nodes/ZeroTouch/DSVarArgFunction.cs Implements wrapper-function routing for variadic nodes when Use Levels are present; preserves old behavior otherwise.
src/DynamoCore/Graph/Nodes/NodeModel.cs Reverts the bounded “hooked” behavior so UseLevelAndReplicationGuide applies across all inputs again.

Comment thread src/DynamoCore/Graph/Nodes/NodeModel.cs Outdated
Comment thread src/DynamoCore/Graph/Nodes/NodeModel.cs Outdated
Comment thread src/DynamoCore/Graph/Nodes/NodeModel.cs Outdated
Comment thread src/DynamoCore/Graph/Nodes/NodeModel.cs Outdated
Variadic zero-touch functions (String.Concat, String.Join, List.Join, ...)
pack their variadic inputs into a single ExprList argument before the
function call. AtLevel / replication-guide annotations inside that list
literal are inert at runtime, and DesignScript cannot call a params method
with separate arguments, so per-port Use Levels and lacing were silently
dropped on every variadic port.

When any port has Use Levels enabled, route the node through a generated
wrapper function whose formal parameters are the individual ports. The
per-port AtLevel and the node's lacing replication guides land on the
wrapper-call arguments -- replicating exactly like a non-variadic node --
and the wrapper body packs the already-replicated values per invocation.
Graphs with no Use Levels keep the original pack-then-call path, so their
behavior is unchanged.

This replaces the earlier pre-pack approach (and its NodeModel
LevelAndReplicationGuideInputCount hook), which wrapped inputs that were
then re-buried inside the inert packed list literal.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@johnpierson johnpierson force-pushed the eamiri/DYN-10572-variadic-uselevels branch from 80ec5c0 to 6db7c0f Compare June 23, 2026 20:47
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@johnpierson johnpierson merged commit f9361f1 into master Jun 23, 2026
26 checks passed
@johnpierson johnpierson deleted the eamiri/DYN-10572-variadic-uselevels branch June 23, 2026 20:58
@sonarqubecloud

Copy link
Copy Markdown

❌ The last analysis has failed.

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants