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
mainfrom
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
mainfrom
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).

@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

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 16 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 69f7c702-45a8-459b-9217-d9c0aa517dff

📥 Commits

Reviewing files that changed from the base of the PR and between 707963d and 4295f0c.

📒 Files selected for processing (2)
  • comfy_cli/cql/engine.py
  • tests/comfy_cli/cql/test_engine.py
✨ 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
mattmillerai added a commit that referenced this pull request Jul 18, 2026
…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:

Base automatically changed from matt/be-3357-validate-required-inputs to main July 22, 2026 18:46
mattmillerai and others added 2 commits July 22, 2026 11:48
…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.
…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>
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.

2 participants