From c0ed04321f533e3ffe1afa4a9e99991ff888f7a0 Mon Sep 17 00:00:00 2001 From: Ken Simpson Date: Fri, 30 Oct 2026 13:10:22 -0700 Subject: [PATCH 1/4] Fix dynamic image boundary validation --- remote_graph_analysis.py | 19 ++++++++++++++++++- tests/test_remote_graph_analysis.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/remote_graph_analysis.py b/remote_graph_analysis.py index 4ef847c..7d6943b 100644 --- a/remote_graph_analysis.py +++ b/remote_graph_analysis.py @@ -578,7 +578,24 @@ def _remote_output_io_type( output_types, _, _ = _normalize_output_metadata(node_class) if output_index < 0 or output_index >= len(output_types): return None - return str(output_types[output_index]) + io_type = str(output_types[output_index]) + if io_type != "COMFY_MATCHTYPE_V3": + return io_type + + # V3 dynamic nodes expose a generic output in their class metadata. Resolve + # the concrete type from the linked input before validating a component edge. + for input_value in (prompt_node.get("inputs") or {}).values(): + if not _is_link(input_value): + continue + resolved_type = _remote_output_io_type( + prompt=prompt, + node_id=str(input_value[0]), + output_index=int(input_value[1]), + nodes_module=nodes_module, + ) + if resolved_type is not None and resolved_type != "COMFY_MATCHTYPE_V3": + return resolved_type + return io_type def _remote_output_is_list( diff --git a/tests/test_remote_graph_analysis.py b/tests/test_remote_graph_analysis.py index c2a08f3..4a75660 100644 --- a/tests/test_remote_graph_analysis.py +++ b/tests/test_remote_graph_analysis.py @@ -4,6 +4,35 @@ from __future__ import annotations from api_intercept_test_support import * # noqa: F401,F403 + +def test_dynamic_match_type_output_resolves_from_linked_image( + remote_graph_analysis_module: Any, +) -> None: + """V3 dynamic resize outputs should cross boundaries as their concrete image type.""" + class ImageSource: + RETURN_TYPES = ("IMAGE",) + + class DynamicResize: + RETURN_TYPES = ("COMFY_MATCHTYPE_V3",) + + prompt = { + "1": {"class_type": "ImageSource", "inputs": {}}, + "2": {"class_type": "ResizeImageMaskNode", "inputs": {"input": ["1", 0]}}, + } + nodes_module = SimpleNamespace( + NODE_CLASS_MAPPINGS={ + "ImageSource": ImageSource, + "ResizeImageMaskNode": DynamicResize, + } + ) + + assert remote_graph_analysis_module._remote_output_io_type( + prompt=prompt, + node_id="2", + output_index=0, + nodes_module=nodes_module, + ) == "IMAGE" + def test_remote_partition_preserves_dag_around_ssh_only_llm( api_intercept_module: Any, remote_graph_analysis_module: Any, From 7944260d7a965e400a4ac2d84c0b1d78744ef572 Mon Sep 17 00:00:00 2001 From: Ken Simpson Date: Fri, 30 Oct 2026 13:17:22 -0700 Subject: [PATCH 2/4] Resolve dynamic boundary output types --- component_planning.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/component_planning.py b/component_planning.py index 7ac0911..e7da7f0 100644 --- a/component_planning.py +++ b/component_planning.py @@ -178,10 +178,16 @@ def _build_component_plan( if source in boundary_outputs_by_source: continue output_name = output_names[output_index] + effective_io_type = _remote_output_io_type( + prompt=prompt, + node_id=node_id, + output_index=output_index, + nodes_module=nodes_module, + ) or str(io_type) boundary_outputs_by_source[source] = BoundaryOutputSpec( proxy_output_name=f"{node_id}_{output_name}", source=source, - io_type=str(io_type), + io_type=effective_io_type, is_list=bool(output_is_list[output_index]), preview_target_node_ids=_preview_target_node_ids( prompt=prompt, From 69a33e3a84bfad52088a828904d9ca9025c37a80 Mon Sep 17 00:00:00 2001 From: Ken Simpson Date: Fri, 30 Oct 2026 13:19:48 -0700 Subject: [PATCH 3/4] Resolve wildcard dynamic output types --- remote_graph_analysis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/remote_graph_analysis.py b/remote_graph_analysis.py index 7d6943b..2993d75 100644 --- a/remote_graph_analysis.py +++ b/remote_graph_analysis.py @@ -579,7 +579,7 @@ def _remote_output_io_type( if output_index < 0 or output_index >= len(output_types): return None io_type = str(output_types[output_index]) - if io_type != "COMFY_MATCHTYPE_V3": + if io_type not in {"*", "COMFY_MATCHTYPE_V3"}: return io_type # V3 dynamic nodes expose a generic output in their class metadata. Resolve From 52a33c61c7480a8cdba96622b34cf9c13dd19862 Mon Sep 17 00:00:00 2001 From: Ken Simpson Date: Fri, 30 Oct 2026 13:25:34 -0700 Subject: [PATCH 4/4] Allow V3 dynamic image boundaries --- remote_graph_analysis.py | 1 + tests/test_remote_graph_analysis.py | 3 +++ 2 files changed, 4 insertions(+) diff --git a/remote_graph_analysis.py b/remote_graph_analysis.py index 2993d75..e870d1b 100644 --- a/remote_graph_analysis.py +++ b/remote_graph_analysis.py @@ -85,6 +85,7 @@ _LOCAL_ONLY_REMOTE_CLASS_TYPES = frozenset( _TRANSPORTABLE_OUTPUT_TYPES = frozenset( { "*", + "COMFY_MATCHTYPE_V3", "AUDIO", "BOOLEAN", "FLOAT", diff --git a/tests/test_remote_graph_analysis.py b/tests/test_remote_graph_analysis.py index 4a75660..4912e2c 100644 --- a/tests/test_remote_graph_analysis.py +++ b/tests/test_remote_graph_analysis.py @@ -32,6 +32,9 @@ def test_dynamic_match_type_output_resolves_from_linked_image( output_index=0, nodes_module=nodes_module, ) == "IMAGE" + assert remote_graph_analysis_module._is_transportable_output_type( + "COMFY_MATCHTYPE_V3" + ) def test_remote_partition_preserves_dag_around_ssh_only_llm( api_intercept_module: Any,