Skip to content

feat: validate auto-converts UI-format workflows like comfy run (BE-3359)#553

Open
mattmillerai wants to merge 2 commits into
mainfrom
matt/be-3359-validate-ui-convert
Open

feat: validate auto-converts UI-format workflows like comfy run (BE-3359)#553
mattmillerai wants to merge 2 commits into
mainfrom
matt/be-3359-validate-ui-convert

Conversation

@mattmillerai

Copy link
Copy Markdown
Collaborator

ELI-5

If you hand comfy validate a workflow you exported from the ComfyUI canvas
(the "UI" shape with nodes/links arrays), it used to shrug and say
"✓ valid" — while actually checking nothing. Every wrapper key (nodes,
links, groups, config, …) just tripped a "this isn't a node" warning, no
real nodes were checked, and you got a cheerful but meaningless pass.

Now validate notices the UI shape and quietly converts it to the API shape
first — the exact same lowering comfy run already does — and validates the
real graph. So you get a truthful answer, and the JSON tells you it validated
the converted graph.

What changed

  • comfy_cli/cmdline.py (validate): after loading the workflow + graph and
    before graph.validate_workflow(...), detect UI format with the existing
    is_ui_workflow predicate and, when it matches, convert with
    convert_ui_to_api(...) — mirroring comfy run. On a WorkflowConversionError
    or an empty conversion, emit the structured workflow_not_api_format error
    (exit 1) naming the conversion; an unexpected converter crash maps to
    conversion_crash (like run) so the agent flow never sees a raw traceback. On
    success the converted graph is validated and the JSON envelope gains
    converted_from_ui: true + converted_node_count.
  • comfy_cli/cql/engine.py (Graph): Graph now retains the raw
    /object_info it was built from and exposes it as Graph.object_info. The
    converter reuses this — no second fetch, and offline --input still
    supplies both the graph and the converter's object_info from one file.

No engine.py validation-logic change: once conversion runs before the node
loop, the wrapper-key non_node_key noise disappears as a side effect;
non_node_key keeps its correct meaning for genuinely stray keys in API files.

Tests (tests/comfy_cli/command/test_validate_command.py, new)

All run offline via --input against the existing sd15 fixtures:

  • UI export → valid:true, converted_from_ui:true, converted_node_count:7,
    zero non_node_key warnings (the BE-3349 repro, now truthful).
  • UI export with an unknown node type → valid:false + unknown_class_type
    (real problem surfaced) with converted_from_ui:true.
  • UI export that converts to zero executable nodes → exit 1,
    workflow_not_api_format, message names the conversion.
  • API-format file → unchanged, no converted_from_ui key.
  • Empty dict / non-dict payloads → existing behavior unchanged.

Judgment calls

  • The ticket's suggested "unconvertible" test was an unknown-type node → expect
    workflow_not_api_format. Empirically that input does convert (to a node
    with that class_type), so it surfaces as valid:false/unknown_class_type
    instead — which is arguably the more useful outcome and matches the acceptance
    criterion ("valid:false on real problems in the converted graph"). I cover
    both: unknown-type → valid:false, and a genuinely empty conversion (nodes
    with no type) → workflow_not_api_format.
  • Added a defensive conversion_crash branch (not spelled out in the ticket but
    part of run's handling it says to mirror) so an unexpected converter failure
    returns a structured error rather than a traceback — the MCP pre-flight flow
    this ticket serves depends on structured output.
  • Graph.object_info is a small additive accessor (public property) — no
    existing behavior changed; it just exposes the raw dict from_object_info
    already received.

Not a capability denial

The new workflow_not_api_format/conversion_crash exits only fire when the
product's own converter (convert_ui_to_api, the same one comfy run uses)
genuinely fails on that file — verified empirically. This PR adds the
UI-validation capability that was silently absent; it does not deny one that
exists elsewhere.

Test status

New suite: 6/6 pass. Full suite: 2570 passed, 9 pre-existing failures unrelated
to this change (tomlkit multiline-comment breakage in
registry/test_config_parser.py + nodes/test_node_init.py, tracked separately
as BE-3290 — ValueError: Comment cannot contain line breaks; none touch
validate/Graph). ruff check + ruff format --check clean.

…-3359)

Detect frontend/UI-export workflows in `comfy validate` and lower them to
API format with the existing convert_ui_to_api before validating, exactly as
`comfy run` does. Previously a UI export validated vacuously (each wrapper
key emitted a non_node_key warning, zero nodes checked, verdict valid:true).

Graph now retains the raw object_info it was built from (Graph.object_info),
so the converter reuses it with no second fetch and offline --input keeps
working. The JSON envelope gains converted_from_ui + converted_node_count.
@mattmillerai mattmillerai added agent-coded PR authored by the agent-work loop cursor-review Request Cursor bot review labels Jul 17, 2026
@coderabbitai

coderabbitai Bot commented Jul 17, 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: 55 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: ccf4ed92-9654-490b-b362-40f3618cd6cf

📥 Commits

Reviewing files that changed from the base of the PR and between a732f5c and e3aed41.

📒 Files selected for processing (3)
  • comfy_cli/cmdline.py
  • comfy_cli/cql/engine.py
  • tests/comfy_cli/command/test_validate_command.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch matt/be-3359-validate-ui-convert
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch matt/be-3359-validate-ui-convert

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

@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 2 finding(s).

Severity Count
🟢 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
Comment thread comfy_cli/cmdline.py
Per Cursor review: object_info returns the graph's live internal schema
state by reference; document that callers must not mutate it (a defensive
copy of the ~11KB payload on every access is not worth the cost, and the
only consumer, convert_ui_to_api in validate, reads it).
@mattmillerai
mattmillerai marked this pull request as ready for review July 17, 2026 21:57
@dosubot dosubot Bot added size:M This PR changes 30-99 lines, ignoring generated files. enhancement New feature or request labels Jul 17, 2026
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 enhancement New feature or request size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant