Skip to content

fix(validate): only enforce promoted hard checks on output-reachable nodes (BE-3406)#565

Open
mattmillerai wants to merge 2 commits into
matt/be-3357-validate-required-inputsfrom
matt/be-3406-validate-output-reachable
Open

fix(validate): only enforce promoted hard checks on output-reachable nodes (BE-3406)#565
mattmillerai wants to merge 2 commits into
matt/be-3357-validate-required-inputsfrom
matt/be-3406-validate-output-reachable

Conversation

@mattmillerai

Copy link
Copy Markdown
Collaborator

ELI-5

ComfyUI's server only checks the nodes that actually feed into an output (like Save Image), plus everything upstream of them. Any node left disconnected — dangling in an exported workflow — is quietly thrown away and never checked. But PR #551 added strict "you're missing a required input" / "value out of range" rejections that fired on every recognized node, including those disconnected ones. So validate would hard-reject a workflow the server would happily run (a disconnected node especially loses its required link inputs, which the frontend only serializes when connected). This PR teaches validate to do the same pruning the server does: figure out which nodes are reachable from an output, and only apply those promoted hard checks to them.

What changed

Tests

New (in TestValidateServerParity):

  • test_disconnected_node_missing_required_is_prunedacceptance (a): disconnected node missing every required input, alongside a valid connected chain → valid: true.
  • test_reachable_node_missing_required_still_errorsacceptance (b): node on the output chain missing a required input still hard-errors.
  • test_transitive_ancestor_missing_required_still_errors — a two-hop-upstream ancestor is reachable and still validated (proves the backward walk follows edges, not just direct parents).
  • test_output_node_missing_required_still_errors — an output node itself seeds the reachable set.
  • test_disconnected_out_of_range_demoted_to_warning — out-of-range on a pruned node is a warning, not a hard error; chain stays valid.
  • test_reachable_out_of_range_still_errors — the connected node still hard-errors on out-of-range.

Updated: test_below_min_error, test_above_max_error, test_required_autogrow_with_no_slots_errors (from #551) each had a single non-output node with no output chain — the server would prune those too (they'd hit prompt_no_outputs, never range/required-checked). Wired the tested node to a SaveImage so the promotion is asserted where the server actually enforces it.

uv run --extra dev pytest tests/comfy_cli/cql/ → 152 passed. ruff check + ruff format --check clean.

Notes / judgment calls

Deferred from a review thread on #551 (BE-3406).

…nodes (BE-3406)

ComfyUI's validate_prompt only validates output nodes and their transitive
input ancestors; nodes not reachable from any output are pruned and never
validated. #551's promoted hard checks (required_input_missing,
autogrow_no_slots, below_min/above_max) ran for every recognized node,
hard-rejecting a disconnected/incomplete node the server would silently drop
(esp. a required LINK input the frontend omits when disconnected).

Compute the output-reachable node set by walking input link references backward
from every output node, and restrict the required-presence and range hard
errors to that set. Out-of-range values on pruned nodes are demoted back to
advisory warnings. Edge/shape/enum checks are unchanged (pre-existing behavior,
out of scope). Three #551 tests whose single node had no output are updated to
wire that node to a SaveImage so the promotion is asserted where the server
enforces it.
@mattmillerai mattmillerai added agent-coded PR authored by the agent-work loop cursor-review Request Cursor bot review labels Jul 18, 2026
@mattmillerai
mattmillerai marked this pull request as ready for review July 18, 2026 01:07
@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 44480436-a380-4249-bc5a-7da959f5a137

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch matt/be-3406-validate-output-reachable
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch matt/be-3406-validate-output-reachable

Comment @coderabbitai help to get the list of available commands.

@dosubot dosubot Bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Jul 18, 2026

@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.

🔍 Cursor Review — Consolidated panel

Triggered by @mattmillerai.

Found 4 finding(s).

Severity Count
🟠 High 1
🟡 Medium 1
🟢 Low 2

Panel: 6/8 reviewers contributed findings.

Reviewers that did not contribute: kimi-k2.5:adversarial (empty), kimi-k2.5:edge-case (empty)

Comment thread comfy_cli/cql/engine.py Outdated
Comment thread comfy_cli/cql/engine.py Outdated
Comment thread comfy_cli/cql/engine.py
Comment thread comfy_cli/cql/engine.py
…ify demoted range warnings (BE-3406)

Cursor-review follow-ups on PR #565:

- Guard non-dict `inputs` in both the per-input loop and the
  `_output_reachable_node_ids` walk: a truthy non-dict value slipped past
  `or {}` and crashed `.items()`/`.values()` with an unhandled traceback
  instead of returning structured errors.
- Screen unhashable class_type (list/dict) in `Graph.node()`, coerce a
  non-str class_type to "" in the main loop, and route the linked-source
  lookup through the guarded `self.node()` — a `dict.get` on an unhashable
  key raised TypeError across the reachability walk and lookup sites.
- Fully qualify the `field` of a range violation demoted to a warning on a
  pruned node (`node.class.input`), matching every other warning's schema
  that preflight renders via `w["field"]`.

Adds TestValidateMalformedInputs (non-dict inputs, unhashable class_type
must not crash) and a demoted-warning field-format assertion.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:M This PR changes 30-99 lines, ignoring generated files. labels Jul 18, 2026
@mattmillerai

Copy link
Copy Markdown
Collaborator Author

🤖 The reviews loop filed Linear follow-up ticket(s) for review thread(s) deferred as out of scope for this PR:

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

Labels

agent-coded PR authored by the agent-work loop cursor-review Request Cursor bot review size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant