Skip to content

feat(nodes): live-refresh annotation data from comfy-complete; fix templates fetch envelope - #474

Merged
skishore23 merged 12 commits into
mainfrom
fix/live-refresh-data-sources
Aug 4, 2026
Merged

feat(nodes): live-refresh annotation data from comfy-complete; fix templates fetch envelope#474
skishore23 merged 12 commits into
mainfrom
fix/live-refresh-data-sources

Conversation

@skishore23

@skishore23 skishore23 commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

Makes the node-annotation data (supported_nodes.yaml, cloud_disable_config.yaml) refresh itself from the public Comfy-Org/comfy-complete repo instead of being frozen until a pip install -U, and repurposes the no-op comfy nodes refresh into the command that forces it. Drops the dead no_gpu_nodes.json dataset, and fixes two templates fetch envelope bugs.

This branch has been rebuilt on current main. Main moved 126 commits since it forked and landed several of the same fixes — better. See "What main already fixed" below for what was dropped rather than merged.

Changes

Node annotations — live refresh with a hard offline/latency contract

New cql/annotations_source.py resolves the annotation pair: TTL-fresh cache → live fetch → stale cache → bundled snapshot. Three properties it guarantees, each one a review finding:

  • Nothing unvalidated reaches the cache. Both files are parsed and shape-checked before they're written. Previously a 200 with an HTML body (captive portal, rate-limit page) was cached and stamped fresh; since engine.parse_supported_nodes degrades to "no annotations" rather than raising, that silently blanked every node's labels for the full 7-day TTL, and the bundled fallback never got a chance. Cache reads are re-validated too, so an entry written by an older build can't do the same thing.
  • The pair is atomic. cloud_disabled is computed by matching labels from one file against disable rules in the other, so a fresh file paired with a stale one mis-classifies nodes. Both are fetched, validated and committed together or not at all.
  • The hot path is bounded and never surprises an offline user. The two files fetch concurrently on daemon threads behind one wall-clock deadline — a socket timeout doesn't bound a hung DNS resolver, and a ThreadPoolExecutor's atexit join would outlive the deadline we just enforced. A failure is negative-cached for an hour, so a persistently offline machine pays the deadline once, not once per comfy nodes invocation.

comfy nodes ls --input <dump> now makes no network calls: Graph.load passes allow_network=False down to the annotation lookup on that path. The caller handed us a local file precisely so nothing goes over the wire.

Bodies read through http.read_capped with an 8 MiB cap, via the http(s)-only plain_urlopen. COMFY_CLI_NO_REMOTE_REFRESH is normalized case-insensitively (so =FALSE means what it says) and named in comfy nodes refresh --help.

A cache-write failure is now reported as cache_error alongside source: "remote" rather than misfiled as a fetch failure — "downloaded fine, couldn't save it" calls for different action than "couldn't download it".

nodes refresh --where stays accepted

--where steers nothing here — the annotation files are routing-independent — but the CLI's own cql_no_graph hint and two shipped SKILL.md files told people to type it. Rejecting it would turn "you followed the hint" into No such option (exit 2) right when someone is already stuck. It's accepted, ignored, and hidden from --help.

All three references are corrected in the same change. As @bigcat88 noted, nodes refresh only touches annotations — object_info is fetched live and was never cached, so it was never the fix for cql_no_graph. They now point at the real remedy (check comfy cloud whoami / network, or start a local server).

templates fetch envelope fixes

  • node_count counts nodes. len(wf) counted the frontend wrapper keys ({id, revision, nodes, links, …}), so every UI-format template read ~10 regardless of size. api_seedance2_0_r2v reported 10 for a 3-node workflow; it now reports 3.
  • --out "" no longer swallows the workflow. The write branch tested if out: while the envelope ride-along tested out is None, so an empty --out wrote no file and omitted the workflow — in JSON mode the fetched workflow was lost entirely. An empty --out is normalized to "no file requested" up front so both guards agree.
  • The full workflow rides along in data.workflow when no file was written, since emit() owns stdout in JSON mode. Declared in schemas/templates.json.

Dead data removal

no_gpu_nodes.json and the needs_gpu field / parse_no_gpu_nodes / the annotate + load params it fed. Upstream is gone and the bundled file is permanently {"no_gpu_nodes": []}, so needs_gpu was a constant true. It appears in no published schema and no skill doc.

What main already fixed (dropped from this branch)

  • cql/gallery.py and its tests. feat(templates): add 24h TTL with stale-cache fallback to gallery cache (BE-3393) #559 (BE-3393) and fix(http): bound three unbounded HTTP body reads behind a shared read cap #654 gave command/templates.py a 24h TTL, stale-cache fallback with a warning, parse-before-cache, atomic + best-effort cache writes, clock-skew handling, and a bounded read — a superset of the extracted engine here, with more test coverage. Kept main's.
  • generate refresh 404 handling. @bigcat88 was right that the spec lives at /openapi; main already fetches it with an /openapi.yml fallback for older deployments.
  • The templates ls --query removal. Main turned it into a cql_query_invalid envelope pointing at the flag filters. Deleting the flag would regress that to No such option (exit 2), which is the same breaking-change trap as --where. The flag and its error code stay; only the help text advertising a grammar we never had is gone (now hidden).
  • The cql.data package-data glob. Narrowing it to *.yaml would have dropped default_text2img.json — added to that package after this branch forked — out of the wheel and broken comfy run's default workflow. Reverted.

Tests

tests/comfy_cli/cql/test_annotations_source.py (45 tests): env-flag truthiness, validator shape checks, resolution order, poisoned-cache rejection, half-present cache, atomic pair, negative caching and its expiry, bounded deadline, actual concurrency, cache-error vs fetch-error separation.

Plus: an engine test asserting --input resolves annotations with allow_network=False; templates fetch node-count tests for both serializations; ride-along present/absent and the --out "" case; a nodes refresh --where cloud regression guard.

Full suite green (the 29 failures on this branch are the same 29 present on origin/maintest_logs, jobs, onboarding, spend_gate, restore_snapshot_fast_deps — none touched here). ruff check and ruff format clean.

Verified live end-to-end: comfy nodes refresh fetches and caches both files from comfy-complete, and templates fetch api_seedance2_0_r2v reports the true node count.

Replace hand-maintained / stale bundled data with live-refresh from the
public Comfy repos, and fix the architecture around CQL + templates.

Data freshness (live fetch + TTL cache + offline fallback):
- Node annotations (supported_nodes.yaml, cloud_disable_config.yaml) now
  resolve via new cql/annotations_source.py: 7-day TTL cache -> live fetch
  from Comfy-Org/comfy-complete -> bundled snapshot fallback. Repurpose the
  no-op `comfy nodes refresh` to force a re-fetch. COMFY_CLI_NO_REMOTE_REFRESH
  disables network for airgapped/CI.
- Gallery (templates/index.json) brought to parity: 7-day TTL auto-refresh
  and graceful fall back to stale cache when offline (previously cached
  forever and errored offline).

Remove dead data / code:
- Delete no_gpu_nodes.json (upstream source gone, file always empty) and the
  needs_gpu field / parse_no_gpu_nodes / annotate+load params it fed.
- Remove the templates `--query` CQL stub (the grammar was never ported; it
  only ever returned an error) plus the now-orphaned cql_query_invalid error
  code and its stale skill-doc section.
- Remove fictional `comfy query` references (help_json examples + run_cli demo
  step that invoked a non-existent command); the run_cli step now demos the
  real flag-based `comfy nodes` commands.
- Tighten cql.data package-data glob to *.yaml.

Architecture:
- Extract the gallery-search engine (port of gallery_search.go predicates)
  out of command/templates.py into cql/gallery.py, so it sits beside the
  node-graph engine (cql/engine.py) and command/templates.py is a thin shell
  -- mirroring how command/nodes.py wraps cql.engine.Graph.

generate refresh:
- Fail gracefully on the now-404 api.comfy.org/openapi.yml: explain the
  partner catalog ships bundled and updates via `pip install -U` instead of
  dumping a raw HTTP error.

Tests: add cql/test_annotations_source.py and cql/test_gallery.py; cover
nodes refresh and templates --query removal. All suites pass, ruff clean.
@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. enhancement New feature or request labels Jun 25, 2026
@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown

✅ All contributors have signed the CLA. Thank you! This PR is ready to be merged.
Posted by the CLA Assistant Lite bot.

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Changes

The PR adds paired remote and bundled annotation resolution with validation, caching, atomic writes, offline handling, and refresh reporting. It removes GPU annotation tracking from the CQL engine. CLI updates refresh annotations and improve template workflow counts and JSON output.

Annotations and CLI workflow updates

Layer / File(s) Summary
Annotation source resolution
comfy_cli/cql/annotations_source.py, tests/comfy_cli/cql/test_annotations_source.py
The new module fetches, validates, caches, and reports annotation pairs. Tests cover fallback, concurrency, atomicity, backoff, and failures.
Graph annotation loading
comfy_cli/cql/engine.py, tests/comfy_cli/cql/test_engine.py
The engine removes GPU metadata and loads default annotations through the new source module. Local file loads disable network access.
Node annotation refresh
comfy_cli/command/nodes.py, comfy_cli/command/run/__init__.py, comfy_cli/skills/comfy-debug/SKILL.md, comfy_cli/skills/comfy/SKILL.md, tests/comfy_cli/command/test_nodes_cli.py
comfy nodes refresh refreshes annotation files, reports their sources, and preserves the deprecated --where option. Guidance and tests reflect the new behavior.
Template fetch output
comfy_cli/command/templates.py, comfy_cli/schemas/templates.json, tests/comfy_cli/command/test_templates.py
Template fetch counts nodes by workflow format, treats empty --out as stdout, and includes the workflow in stdout JSON output. Query filtering is hidden and marked unavailable.

Suggested reviewers: luke-mino-altherr, mattmillerai

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/live-refresh-data-sources
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch fix/live-refresh-data-sources

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

@coderabbitai
coderabbitai Bot requested a review from luke-mino-altherr June 25, 2026 05:12

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
comfy_cli/command/templates.py (1)

219-232: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

refresh_cmd caches fetch_gallery() bytes without validating JSON.

Same family as the gallery.load_gallery concern: Line 228 writes the fetched bytes to the cache before any parse, so a non-JSON 200 response would persist a broken index that later templates ls reads as fresh. A quick json.loads(data) guard before write_bytes keeps the cache honest — no junk in the trunk.

🛡️ Proposed guard
     cache = gallery.cache_path()
+    try:
+        json.loads(data)  # don't cache a non-JSON body
+    except json.JSONDecodeError as e:
+        renderer.error(code="gallery_fetch_failed", message=f"remote returned non-JSON: {e}")
+        raise typer.Exit(code=1) from e
     cache.parent.mkdir(parents=True, exist_ok=True)
     cache.write_bytes(data)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@comfy_cli/command/templates.py` around lines 219 - 232, `refresh_cmd` writes
the result of `gallery.fetch_gallery()` directly to the cache without verifying
it is valid JSON, so a successful but non-JSON response can poison the cached
gallery. Add a JSON validation step in `refresh_cmd` (using the fetched bytes
before `cache.write_bytes`) and fail with the existing error handling path if
parsing fails, so only valid gallery data is persisted; use the
`gallery.fetch_gallery`, `cache.write_bytes`, and `renderer.error` flow to
locate the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@comfy_cli/cql/annotations_source.py`:
- Around line 82-93: The synchronous _fetch path in _resolve_one is blocking
comfy nodes on the default annotations load, so change the fallback behavior to
avoid waiting on network I/O in the hot path. Update _try_default_annotations
and/or _resolve_one so stale or bundled data is returned immediately, then
refresh the cache in the background, or fetch the two entries from _FILES
concurrently to reduce total latency. Keep the existing stale-cache and bundled
fallback logic intact and preserve the current cache write behavior in
annotations_source.py.

In `@comfy_cli/cql/gallery.py`:
- Around line 87-97: The gallery cache path in fetch_gallery() is writing raw
fetch_gallery() bytes to disk before validating them, which can poison the cache
with non-JSON payloads. Update the fetch-and-cache flow in gallery.py so the
data is parsed with json.loads(data) first, and only after that succeeds should
cache.write_bytes(data) run. Keep the existing fallback behavior for
cache.is_file() and the GalleryError path, but ensure only valid JSON ever
reaches the cache.

In `@tests/comfy_cli/cql/test_gallery.py`:
- Around line 98-152: Add a regression test in the gallery load suite for the
poisoned-cache path: when `gallery.load_gallery` calls `fetch_gallery` and
receives non-JSON bytes, it should fail before persisting anything. Reuse the
existing `test_load_gallery_fetches_and_caches` style with `monkeypatch` on
`gallery.cache_path` and `gallery.fetch_gallery`, then assert the cache file
does not exist or remains unwritten after the bad payload. This should
specifically cover the parse-before-write behavior in `load_gallery` so a
malformed upstream response cannot populate the cache.

---

Outside diff comments:
In `@comfy_cli/command/templates.py`:
- Around line 219-232: `refresh_cmd` writes the result of
`gallery.fetch_gallery()` directly to the cache without verifying it is valid
JSON, so a successful but non-JSON response can poison the cached gallery. Add a
JSON validation step in `refresh_cmd` (using the fetched bytes before
`cache.write_bytes`) and fail with the existing error handling path if parsing
fails, so only valid gallery data is persisted; use the `gallery.fetch_gallery`,
`cache.write_bytes`, and `renderer.error` flow to locate the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1735287c-0352-49ac-a93f-7f89c8791e9b

📥 Commits

Reviewing files that changed from the base of the PR and between 7e87c77 and 51d131b.

📒 Files selected for processing (16)
  • comfy_cli/command/generate/app.py
  • comfy_cli/command/nodes.py
  • comfy_cli/command/run_cli.py
  • comfy_cli/command/templates.py
  • comfy_cli/cql/annotations_source.py
  • comfy_cli/cql/data/no_gpu_nodes.json
  • comfy_cli/cql/engine.py
  • comfy_cli/cql/gallery.py
  • comfy_cli/error_codes.py
  • comfy_cli/help_json.py
  • comfy_cli/skills/comfy-debug/SKILL.md
  • pyproject.toml
  • tests/comfy_cli/command/test_nodes_cli.py
  • tests/comfy_cli/command/test_templates.py
  • tests/comfy_cli/cql/test_annotations_source.py
  • tests/comfy_cli/cql/test_gallery.py
💤 Files with no reviewable changes (4)
  • comfy_cli/skills/comfy-debug/SKILL.md
  • comfy_cli/help_json.py
  • comfy_cli/cql/data/no_gpu_nodes.json
  • comfy_cli/error_codes.py

Comment thread comfy_cli/cql/annotations_source.py Outdated
Comment thread comfy_cli/cql/gallery.py Outdated
Comment thread tests/comfy_cli/cql/test_gallery.py Outdated
…-out

`comfy --json templates fetch <name>` (no --out) previously returned only
metadata — the documented `data.workflow` field was never populated, so a JSON
consumer had no way to retrieve the fetched workflow. Include the parsed
workflow under `data.workflow` when there's no file destination (pretty mode
already streams it to stdout); omit it with --out since it's on disk. Document
the field in schemas/templates.json and add tests for both paths.

Found via subagent CLI testing of the CQL command surface.
…-robust

- Apply `ruff format` to nodes.py + test_nodes_cli.py (CI runs
  `ruff format --diff`, which I'd missed locally).
- test_ls_query_option_removed asserted on Rich-rendered error text that wraps
  by terminal width; assert only on Click's exit code 2 (usage error), the
  stable cross-environment signal.

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@comfy_cli/command/nodes.py`:
- Around line 889-891: The bundled-fallback message in refresh_annotations
output is too failure-like for the intentional COMFY_CLI_NO_REMOTE_REFRESH path.
Update the rprint wording in nodes.py so the refresh flow uses neutral “bundled”
fallback language instead of “remote fetch failed,” and let the existing
error/reason field from refresh_annotations convey why the bundled snapshot was
used.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 00173e53-033c-4108-bc84-dd1a5a80f4b4

📥 Commits

Reviewing files that changed from the base of the PR and between 4720d3f and b43914c.

📒 Files selected for processing (3)
  • comfy_cli/command/nodes.py
  • tests/comfy_cli/command/test_nodes_cli.py
  • tests/comfy_cli/command/test_templates.py

Comment thread comfy_cli/command/nodes.py Outdated
@skishore23

Copy link
Copy Markdown
Contributor Author

I have read and agree to the Contributor License Agreement

comfy-legal added a commit to Comfy-Org/comfy-cla that referenced this pull request Jun 25, 2026
Comment thread comfy_cli/command/generate/app.py Outdated
bigcat88

This comment was marked as duplicate.

Comment thread comfy_cli/command/nodes.py Outdated
Comment thread comfy_cli/cql/engine.py Outdated
Comment thread comfy_cli/command/templates.py Outdated
Comment thread comfy_cli/cql/annotations_source.py Outdated
@skishore23 skishore23 added the cursor-review Request Cursor bot review label Jul 2, 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 @skishore23.

Found 9 finding(s).

Severity Count
🟠 High 1
🟡 Medium 3
🟢 Low 4
⚪ Nit 1

Panel: 8/8 reviewers contributed findings.

Comment thread comfy_cli/cql/engine.py Outdated
Comment thread comfy_cli/cql/gallery.py Outdated
Comment thread comfy_cli/cql/annotations_source.py Outdated
Comment thread comfy_cli/cql/annotations_source.py Outdated
Comment thread comfy_cli/cql/gallery.py Outdated
Comment thread comfy_cli/cql/annotations_source.py Outdated
Comment thread comfy_cli/command/templates.py Outdated
Comment thread comfy_cli/cql/annotations_source.py
Comment thread comfy_cli/cql/annotations_source.py Outdated
@skishore23
skishore23 requested a review from bigcat88 July 3, 2026 04:59

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

The direction here is right and the earlier review round agreed on the fixes — but the fix commits referenced in the review threads (a224a9c, 4b3b3ed) were never pushed: they don't exist in this repo (GitHub returns 422 for both SHAs), and the branch's three commits end at b43914c. Every defect acknowledged as 'fixed' in the threads is still live on the branch. Verified empirically on the current head merged with main (full unit suite passes — 2508 — so the base is sound; these are the outstanding items):

  1. comfy nodes refresh --where cloud — the hint comfy-cli itself prints in command/run/__init__.py:534 (and two SKILL.md references) — now errors No such option: --where (reproduced locally). This is the breaking change flagged in the earlier thread.
  2. comfy generate refresh still fetches /openapi.yml (command/generate/app.py:505) — the /openapi fix described in the thread was never pushed. Note mattmillerai has open PRs #517/#560 for exactly this; consider dropping that part here and coordinating.
  3. Cache poisoning (inline) — annotations and gallery both cache unvalidated bytes for 7 days.
  4. node_count (inline) — still counts top-level UI-format keys.
  5. The hot-path/offline concern on engine._try_default_annotations (network fetch on stale cache even for explicit --input dumps) is likewise unaddressed.

Also: the branch now conflicts with main in error_codes.py (main added description_ignored next to the cql_query_invalid block this PR deletes — resolution is trivial: keep main's new code, drop cql_query_invalid, which is unused once your templates.py changes land). And the gallery-TTL portion now overlaps open #559/#566 — worth coordinating so the same cache logic doesn't land twice.

Comment thread comfy_cli/cql/annotations_source.py Outdated
Comment thread comfy_cli/command/nodes.py Outdated
Comment thread comfy_cli/command/templates.py Outdated
Main moved 126 commits since this branch forked, and several of them landed
the same ground this PR was covering — better. The merge keeps main's version
wherever that's true and keeps this branch's only where it still adds something:

Dropped in favour of main:
* `cql/gallery.py` + its tests. `ef7e21b` (BE-3393) and `1d8c35b` gave
  `command/templates.py` a 24h TTL, stale-cache fallback with a warning,
  parse-before-cache, atomic + best-effort cache writes, clock-skew handling
  and a bounded read. That is a superset of what this branch's extracted
  engine did, with far more test coverage.
* The `generate refresh` 404 handling. Main already fetches `/openapi` with an
  `/openapi.yml` fallback — bigcat88's point, fixed upstream.
* The `templates ls --query` removal. Main turned it into a `cql_query_invalid`
  envelope with a pointer at the flag filters; deleting the flag would regress
  that to `No such option` (exit 2). The flag and its error code stay; only the
  help text that advertised a grammar we never had is gone (now hidden).
* The `cql.data` package-data glob. Narrowing it to `*.yaml` would have dropped
  `default_text2img.json` — added to that package after this branch forked —
  out of the wheel and broken `comfy run`'s default workflow.

Review findings, all previously claimed as fixed in 4b3b3ed/a224a9c but never
pushed (bigcat88, 2026-07-22):

* `annotations_source` no longer caches unvalidated bodies. Both files are
  parsed and shape-checked before they reach disk, so an HTML captive-portal
  200 falls through to the bundled snapshot instead of silently blanking every
  node's annotations for a 7-day TTL. Cache reads are re-validated too, so an
  entry written by an older build can't do the same.
* The pair is fetched, validated and committed atomically. A fresh
  `supported_nodes.yaml` paired with a stale `cloud_disable_config.yaml`
  mis-computes `cloud_disabled`.
* `comfy nodes ls --input <dump>` makes no network calls at all. `Graph.load`
  now passes `allow_network=False` down to the annotation lookup on that path.
* The hot path is bounded: both files fetch concurrently on daemon threads
  behind one wall-clock deadline (a socket timeout doesn't bound a hung DNS
  resolver, and a ThreadPoolExecutor's atexit join would outlive the deadline),
  and a failure is negative-cached for an hour so an offline machine pays once,
  not once per command.
* Bodies read through `http.read_capped` with an 8 MiB cap, via the http(s)-only
  `plain_urlopen`.
* A cache-write failure is reported as `cache_error` with `source: "remote"`,
  not misfiled as a fetch failure — the data was downloaded fine.
* `COMFY_CLI_NO_REMOTE_REFRESH` is normalized case-insensitively, so `=FALSE`
  no longer means the opposite of what it says, and it's named in `--help`.
* `nodes refresh` still accepts `--where`. It steers nothing, but the CLI's own
  `cql_no_graph` hint and two shipped SKILL.md files told people to type it;
  rejecting it turns "you followed the hint" into exit 2. Hidden from `--help`,
  and all three references now point at the real remedy — `object_info` is
  fetched live, so `nodes refresh` was never the fix for that error anyway.
* `templates fetch` reports the real node count. `len(wf)` counted the frontend
  wrapper keys, so every UI-format template read ~10 (`api_seedance2_0_r2v`: 10
  for a 3-node workflow).
* `templates fetch --out ""` no longer loses the workflow. `if out:` and
  `out is None` disagreed, so an empty `--out` wrote no file *and* omitted the
  envelope ride-along.
* Neutral wording on the bundled-snapshot line: `COMFY_CLI_NO_REMOTE_REFRESH`
  reaches it by design, not by failure.

`needs_gpu` / `no_gpu_nodes.json` removal stands: upstream is gone, the bundled
file is permanently empty, so the field was a constant `true` — and it appears
in no published schema or skill doc.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai
coderabbitai Bot requested a review from mattmillerai August 4, 2026 19:46
@skishore23 skishore23 changed the title feat: live-refresh public data sources; make gallery a CQL engine feat(nodes): live-refresh annotation data from comfy-complete; fix templates fetch envelope Aug 4, 2026

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
comfy_cli/command/templates.py (2)

102-114: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Honor COMFY_CLI_NO_REMOTE_REFRESH before fetching the gallery.

When the cache is absent or stale, _load_gallery calls _fetch_gallery() without checking the remote-refresh opt-out. This creates an outbound GitHub request in airgapped and CI environments. Check the setting before Line 114. If a cache exists, use it regardless of age. If no cache exists, return a controlled local error.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@comfy_cli/command/templates.py` around lines 102 - 114, Update _load_gallery
to honor COMFY_CLI_NO_REMOTE_REFRESH before invoking _fetch_gallery when the
cache is absent or stale. If a cache exists, return its contents regardless of
age; if no cache exists, return the established controlled local error instead
of making a remote request, while preserving explicit refresh behavior when
remote access is allowed.

40-45: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use the required seven-day gallery TTL.

Line 45 refreshes the gallery cache after 24 hours. The stated cache contract requires seven days. This causes unnecessary daily network fetches.

Proposed fix
-GALLERY_TTL_SECONDS = 24 * 60 * 60
+GALLERY_TTL_SECONDS = 7 * 24 * 60 * 60
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@comfy_cli/command/templates.py` around lines 40 - 45, Update the
GALLERY_TTL_SECONDS constant to use the required seven-day cache duration
instead of 24 hours, preserving the existing _load_gallery refresh and
stale-cache fallback behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@comfy_cli/cql/annotations_source.py`:
- Around line 248-263: Update _persist_pair to stage both fetched files in
temporary files before renaming either destination, then commit both staged
files only after all staging succeeds, preserving the existing error return
behavior and cleanup requirements. Keep _write_atomic as the staging primitive
so existing tests that monkeypatch it continue to simulate write failures, or
update those patch targets consistently; ensure failed staging cannot leave a
partially committed pair.

In `@comfy_cli/skills/comfy-debug/SKILL.md`:
- Line 50: Remove the obsolete cql_query_invalid error path and --query option
from the relevant CLI handling and documentation, including the error
registration/emission in comfy_cli/command/templates.py and its mention in the
comfy-debug skill. Preserve the remaining conversion_error and cql_no_graph
guidance unchanged.

In `@tests/comfy_cli/command/test_nodes_cli.py`:
- Around line 214-241: Extend TestNodesRefresh with two cases that exercise the
pretty-rendering refresh path instead of the JSON-only path used by _run: one
fake result containing source "unavailable", and another containing a remote
entry with path None and cache_error. Invoke the refresh command through the
existing CLI setup, capture output with capsys, and assert each case exposes the
expected unavailable and cache-error messaging from refresh_cmd.

In `@tests/comfy_cli/cql/test_annotations_source.py`:
- Around line 294-306: Adjust test_fetch_pair_runs_concurrently by increasing
the mocked slow fetch delay and raising the elapsed-time assertion bound
together, preserving enough separation that concurrent execution passes with
scheduling overhead while sequential execution remains distinguishable.

---

Outside diff comments:
In `@comfy_cli/command/templates.py`:
- Around line 102-114: Update _load_gallery to honor COMFY_CLI_NO_REMOTE_REFRESH
before invoking _fetch_gallery when the cache is absent or stale. If a cache
exists, return its contents regardless of age; if no cache exists, return the
established controlled local error instead of making a remote request, while
preserving explicit refresh behavior when remote access is allowed.
- Around line 40-45: Update the GALLERY_TTL_SECONDS constant to use the required
seven-day cache duration instead of 24 hours, preserving the existing
_load_gallery refresh and stale-cache fallback behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ed100954-1a45-4586-9eb3-679a7e0e676b

📥 Commits

Reviewing files that changed from the base of the PR and between b43914c and 8d52dfc.

📒 Files selected for processing (11)
  • comfy_cli/command/nodes.py
  • comfy_cli/command/run/__init__.py
  • comfy_cli/command/templates.py
  • comfy_cli/cql/annotations_source.py
  • comfy_cli/cql/engine.py
  • comfy_cli/skills/comfy-debug/SKILL.md
  • comfy_cli/skills/comfy/SKILL.md
  • tests/comfy_cli/command/test_nodes_cli.py
  • tests/comfy_cli/command/test_templates.py
  • tests/comfy_cli/cql/test_annotations_source.py
  • tests/comfy_cli/cql/test_engine.py

Comment thread comfy_cli/cql/annotations_source.py
Comment thread comfy_cli/skills/comfy-debug/SKILL.md Outdated

### `workflow_not_api_format`
UI-format workflows are converted to API format **client-side** using object_info (no server conversion endpoint exists). If conversion fails with `conversion_error`, re-export via `File > Export (API)` in ComfyUI; if object_info can't be fetched (`cql_no_graph`), run `comfy nodes refresh --where cloud` or start a local server.
UI-format workflows are converted to API format **client-side** using object_info (no server conversion endpoint exists). If conversion fails with `conversion_error`, re-export via `File > Export (API)` in ComfyUI; if object_info can't be fetched (`cql_no_graph`), it is fetched live rather than cached — check `comfy cloud whoami` and your network, or start a local server, then retry.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check for stale references to the removed cql_query_invalid code and templates --query stub.
set -uo pipefail

echo "== cql_query_invalid references =="
rg -n --hidden -g '!.git' 'cql_query_invalid' || echo "(none)"

echo
echo "== error_codes registry entry =="
fd -i 'error_codes.py' --exec rg -n -C3 'cql_query|cql_no_graph' {} \;

echo
echo "== templates --query / query stub references =="
rg -n --hidden -g '!.git' -- '--query' || echo "(none)"

echo
echo "== shipped skill docs =="
fd -i 'SKILL.md' comfy_cli/skills --exec rg -n 'cql_query_invalid|--query|nodes refresh' {} \;

Repository: Comfy-Org/comfy-cli

Length of output: 290


🏁 Script executed:

set -u

echo "== target skill references =="
rg -n -C2 'cql_query_invalid|cql_no_graph|--query|nodes refresh' comfy_cli/skills/comfy-debug/SKILL.md || true

echo
echo "== tracked references =="
rg -n --hidden -g '!.git' -g '!*.log' 'cql_query_invalid|cql_no_graph|templates.*--query|--query' . || true

echo
echo "== error registries =="
fd -i 'error_codes.py' --exec sh -c 'echo "--- $1"; rg -n -C3 "cql_query|cql_no_graph" "$1" || true' sh {} \;

echo
echo "== relevant command definitions =="
rg -n -C3 'cql_query_invalid|cql_no_graph|templates|--query' comfy_cli/command comfy_cli/skills || true

Repository: Comfy-Org/comfy-cli

Length of output: 47040


Remove the obsolete cql_query_invalid path and --query option. The error remains registered, emitted by comfy_cli/command/templates.py, and documented in comfy_cli/skills/comfy-debug/SKILL.md.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@comfy_cli/skills/comfy-debug/SKILL.md` at line 50, Remove the obsolete
cql_query_invalid error path and --query option from the relevant CLI handling
and documentation, including the error registration/emission in
comfy_cli/command/templates.py and its mention in the comfy-debug skill.
Preserve the remaining conversion_error and cql_no_graph guidance unchanged.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@claude please resolve

Comment thread tests/comfy_cli/command/test_nodes_cli.py
Comment thread tests/comfy_cli/cql/test_annotations_source.py Outdated
CodeRabbit caught a real gap in the previous commit. `_persist_pair` called
`_write_atomic` once per file in sequence, which makes each file atomic but not
the pair: if the second write fails on a full disk, the first is already
committed while the second keeps its old bytes *and* its old mtime.
`_read_cached_pair(require_fresh=False)` then hands back a fresh
`supported_nodes.yaml` beside an older `cloud_disable_config.yaml` — the exact
generation mixing this module promises never happens, and `cloud_disabled` is
computed by cross-referencing the two.

`_write_atomic` is split into `_stage_atomic` (write the temp, return its path)
and the commit; `_persist_pair` now stages both files before renaming either,
so nothing lands until both are ready. Verified against the old code path: it
produced `NEW-sup` + `old-dis` where the new one leaves both at the old
generation, with no orphaned temp files either way.

Tests:
* `test_second_write_failing_leaves_the_old_pair_intact` pins the above.
* `test_fetch_pair_runs_concurrently` proves concurrency with a
  `threading.Barrier` instead of a stopwatch. The wall-clock version left 0.25s
  of slack for thread scheduling, which is a flake waiting for a loaded runner;
  a barrier deadlocks under a sequential implementation and has no timing
  threshold to drift.
* Pretty-path coverage for `nodes refresh`: `source: "unavailable"`, a remote
  entry carrying `cache_error`, and the two "reason field is absent" fallbacks.
  `_run` pins the JSON renderer, so none of that wording was exercised.

Not taken: CodeRabbit also asked to finish removing `cql_query_invalid` and
`templates ls --query`. Those are deliberately kept — the error code gives an
actionable envelope, whereas deleting the flag regresses it to `No such option`
(exit 2), which is the same breaking-change trap as `nodes refresh --where`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

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

♻️ Duplicate comments (1)
comfy_cli/cql/annotations_source.py (1)

277-285: ⚠️ Potential issue | 🟠 Major

Publish the annotation pair through one commit record.

Two os.replace calls do not form one transaction. If a reader runs between the replacements, two refreshes interleave, or the second replacement fails, the cache can contain files from different fetches. _read_cached_pair can then return a mismatched pair, and the engine can compute cloud_disabled from unrelated snapshots.

Write each pair under an immutable generation. Atomically replace one manifest or current-generation pointer only after both files are ready. Add regressions for a failed second os.replace and interleaved refreshes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@comfy_cli/cql/annotations_source.py` around lines 277 - 285, Update the
annotation publish flow around the staged os.replace loop to write both files
under an immutable generation, then atomically replace a single manifest or
current-generation pointer only after both files are ready. Modify
_read_cached_pair to resolve and read the pair through that committed generation
so failed second replacements and interleaved refreshes cannot produce
mismatched snapshots, and add regressions covering both scenarios.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@comfy_cli/cql/annotations_source.py`:
- Around line 277-285: Update the annotation publish flow around the staged
os.replace loop to write both files under an immutable generation, then
atomically replace a single manifest or current-generation pointer only after
both files are ready. Modify _read_cached_pair to resolve and read the pair
through that committed generation so failed second replacements and interleaved
refreshes cannot produce mismatched snapshots, and add regressions covering both
scenarios.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 61966770-552d-4b2c-8792-91a94dfb6435

📥 Commits

Reviewing files that changed from the base of the PR and between 8d52dfc and fa149bc.

📒 Files selected for processing (3)
  • comfy_cli/cql/annotations_source.py
  • tests/comfy_cli/command/test_nodes_cli.py
  • tests/comfy_cli/cql/test_annotations_source.py

CodeRabbit pushed back on the previous fix and was right. Staging both files
before renaming either shrinks the window but does not close it: two
`os.replace` calls are not one transaction. A reader can land between them, the
second can fail after the first committed, and — the case that actually bites —
two concurrent `comfy nodes` refreshes can interleave (A renames sup, B renames
both of its own, A renames dis) leaving A's labels beside B's disable rules for
a full TTL. `cloud_disabled` is computed by cross-referencing the two, so that
mix is a wrong answer, not a cosmetic one.

Measured rather than assumed: a 0.4s race with two writers and two readers
against the two-file scheme observed 1199 mixed generations out of 5245 reads
(23%). The single-file version observes zero.

Rather than the manifest / generation-directory scheme suggested, the pair now
rides in one `annotations.json` published by one `os.replace`. That makes the
whole class unrepresentable — no partial commit, no interleave, no half-present
pair — with less code than the two-file version it replaces: `_read_cached_pair`
is one read and one parse, and the "one file present, one missing" branch is
gone because there is no half.

* Cache carries a `schema` version; anything unrecognised (non-JSON, wrong
  schema, missing entry, failed validator) reads as a miss and falls through to
  bundled — never to a silently blank annotation.
* The old per-file cache is ignored by construction and swept on first write.
* `refresh_annotations` reports the shared cache path for both documents.

Tests: a real 4-thread race asserting no reader ever observes a mixed pair, a
failed-write test showing the old generation survives whole, legacy-cache
ignore + cleanup, and a parametrised sweep of malformed cache shapes. Replaces
the now-meaningless "second write fails" test — there is no second write.

Verified live: `comfy nodes refresh` fetches, validates and caches both
documents into a single 33 KB annotations.json.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Auditing the review threads against the branch turned up one finding I had
never actually closed: CodeRabbit's round-1 "outside diff range" note on
`templates.py`. I took main's file wholesale during the merge and inherited the
bug with it.

`refresh_cmd` bypassed `_persist_cache` entirely — bare `cache.write_bytes(data)`
with no validation, no OSError guard and no atomic rename. Reproduced: a 200
carrying rate-limit HTML is written verbatim, the command reports success and
exits 0, and every subsequent `templates ls` then fails `gallery_load_failed`
for the full 24h TTL. The stale-cache fallback cannot rescue it, because the
cache *is* the garbage. `_load_gallery` got all three of these right in #559;
only the standalone command was left behind.

* `refresh_cmd` validates before persisting and routes through `_persist_cache`,
  so it is atomic and cannot clobber a good index with an unusable body.
* New `_parse_gallery` shape-checks the decode: `json.loads` alone accepts
  `null`, `7` and `{"error": …}`, none of which are a gallery. Every decode
  site now uses it, so a wrong-shaped body fails as `gallery_load_failed`
  instead of surfacing later as an unrelated error or zero rows.
* `_persist_cache` returns its error instead of swallowing it. `templates ls`
  still ignores it — it already holds valid data — but `refresh`, whose entire
  job is caching, now reports `gallery_cache_write_failed` and exits 1 rather
  than claiming success. Registered in the error-code registry.
* `templates ls` self-heals: a fresh-but-unparseable cache (inherited from an
  older build that wrote before validating) is treated as a miss and re-fetched
  rather than raised on until the TTL expires.
* `refresh` reports `categories` alongside `bytes`, so success is verifiable
  rather than just asserted.

Also documents the one review finding that is accepted rather than fixed: the
annotation files come from `comfy-complete`'s mutable `main` with no pinning.
The repo publishes no tags, releases or digests, so there is nothing to pin to,
and a commit pin would defeat the live refresh. Bounded because the data is
advisory (the cloud server does its own filtering) and the bundled snapshot has
the same trust root; the shape validators are the compensating control.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label Aug 4, 2026
Main's #515 deleted `comfy nodes refresh` as dead command surface — correctly,
for the version it was looking at, which printed a sentence and exited. This
branch gives the command a real job (force-refresh the annotation cache from
comfy-complete), so the premise for removing it no longer holds. Kept.

The overlap turned out to be mostly agreement. #515 independently rewrote the
same three `comfy nodes refresh --where cloud` references bigcat88 flagged, and
reached the same conclusion: object_info is fetched live, so the remedy is to
check sign-in/connection and retry. Took main's wording verbatim in
`run/__init__.py` and `skills/comfy-debug/SKILL.md` rather than keeping a
gratuitous second phrasing of the same advice.

`skills/comfy/SKILL.md` takes main's wording plus the note that `comfy nodes
refresh` is a *different* cache (annotations, not object_info). That
clarification matters more now than when I wrote it — the command exists again
and does something unrelated to the error being described.

Restored `comfy nodes refresh` in `discovery.py`. #515 removed the entry along
with the command, and git auto-merged that deletion since only main touched the
file — leaving the command implemented but unlisted. Caught by checking rather
than by a test; the registry has no coverage tying it to the Typer app.

Full suite: 3921 passed, same 29 pre-existing failures as origin/main.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@skishore23
skishore23 requested a review from bigcat88 August 4, 2026 21:06
`comfy discover` publishes `schemas/nodes.json` as the payload contract for the
`comfy nodes` surface, and this PR added two fields to it — `refreshed` and
`files` — without describing them there. An agent reading `discover` would not
have known they exist. `schemas/templates.json` got updated for the `workflow`
ride-along; this one was missed.

Documents both, including the parts that are easy to misread: `refreshed: false`
is not necessarily an error (COMFY_CLI_NO_REMOTE_REFRESH lands there by design),
`path` is the same for both rows because the pair shares one cache file, and
`cache_error` means the fetch succeeded but the write didn't — the opposite of a
network problem.

Enforced in both directions: the schema must describe the fields, and every
`source` variant the command can emit must validate against it — including the
genuine offline path, not only fakes. Nothing previously validated any `nodes`
payload against its published schema, which is why this drifted silently.

Two corrections to the previous commit message, which was wrong on both counts:

* It said the discovery registry has no coverage tying it to the Typer app.
  It does — `test_every_emitted_command_registers_a_schema` fails when the
  `comfy nodes refresh` entry is missing (verified by removing it and watching
  the suite go red). CI would have caught that drift; my manual catch was
  redundant, not load-bearing.

* Separately, and NOT fixed here: `test_logs_payload_matches_published_schema`
  validates against `load_all_schemas()["logs"]`, the `{name, title, schema}`
  wrapper, rather than the inner `schema`. `name`/`schema` are not validation
  keywords, so that validator asserts nothing and the test passes for any
  payload. Confirmed: a payload with `refreshed: "yes"` is accepted by the
  wrapper and rejected by the inner schema. Left alone because that test is
  already failing in this environment for unrelated reasons, so the fix can't
  be verified locally — flagging rather than pushing a blind change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@skishore23

Copy link
Copy Markdown
Contributor Author

@bigcat88 — everything you raised on 2026-07-22 is on the branch now and verified; the earlier "fixed in 4b3b3ed" replies were wrong and I'm sorry for the round-trip they cost you. Details are in the three threads above.

Your CHANGES_REQUESTED is the remaining gate on this PR — would you mind taking another look when you have a moment?

Context on what changed, since it's more than a rebase: main moved 126 commits while this sat, and four parts of the original PR were dropped rather than merged, because main had already solved them better —

Verification, since the last round of claims here didn't hold up: the wheel was built and installed into a clean venv and the CLI driven end-to-end from it — packaging contents, both cache-upgrade paths, and the offline --input path with socket.connect/getaddrinfo hard-blocked process-wide (not just mocked). Full suite green apart from 29 failures that are identical on origin/main.

One review finding is accepted rather than fixed, and flagged in the module docstring: the annotation files come from comfy-complete's mutable main with no pinning. The repo publishes no tags, releases or digests, so there's nothing to pin to, and a commit pin defeats the live refresh. Bounded because the data is advisory — the cloud server does its own filtering — and the bundled snapshot has the same trust root; the shape validators are the compensating control.

@skishore23
skishore23 dismissed bigcat88’s stale review August 4, 2026 21:46

All three findings are fixed and verified on the rebuilt branch (see thread replies). This review targets b43914c, which has since been merged with 126 commits of main and substantially reworked

skishore23 and others added 3 commits August 4, 2026 14:55
Four more commits landed on main. No textual conflicts, but two are worth
naming because they touch this PR's blast radius:

* #519 (`fix(run): resolve the bundled default checkpoint at runtime`) edits
  `cql/data/default_text2img.json` and adds 143 lines to `default_workflow.py`.
  That is the file this PR's original `cql.data` package-data narrowing would
  have dropped out of the wheel — the regression is now considerably more
  expensive than when it was reverted, so the revert is re-verified below.

* #525 removes 8 dead symbols including the `oauth_cancelled` error code.
  Auto-merged cleanly against this branch's `gallery_cache_write_failed`
  addition; neither touches the other.

* #517 fetches the generate spec from `/openapi` — the same fix this branch
  dropped in favour of main's, so the two agree.

Full suite on the merged tree: 3977 passed, same 29 pre-existing failures.
ruff clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two more commits on main. Only conflict is `tests/comfy_cli/command/test_nodes_cli.py`,
where both sides appended new test classes at the same offset: this branch's
`TestNodesRefresh` / `TestNodesRefreshPublishedContract` and #667's
`TestLocalTargetResolution`. Disjoint class sets, so both are kept — a textual
conflict, not a semantic one.

#667 (`resolve validate/nodes object_info target via resolve_host_port`) touches
the same `comfy nodes` surface but a different axis — how the object_info target
is resolved, not how annotations are loaded. Auto-merged in `nodes.py` with no
overlap against the `refresh` command.

Full suite: 4044 passed, same 29 pre-existing failures. ruff clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Fourth main merge on this branch. Only conflict is
`tests/comfy_cli/command/test_templates.py`, where #557 appended 24 tests for
the new `templates check` subcommand at the same offset as this branch's 5
`fetch` tests. Disjoint names, both kept — 62 tests in the file, all passing.

`command/templates.py` and `discovery.py` auto-merged: #557 adds a new
subcommand and its registry entry, this branch changes `fetch`'s node count and
envelope plus the `refresh` cache path. No overlap.

Full suite: 4068 passed, same 29 pre-existing failures. ruff clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@skishore23
skishore23 merged commit e36fdd3 into main Aug 4, 2026
17 checks passed
@skishore23
skishore23 deleted the fix/live-refresh-data-sources branch August 4, 2026 23:07
@github-actions github-actions Bot locked and limited conversation to collaborators Aug 4, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

cursor-review Request Cursor bot review enhancement New feature or request lgtm This PR has been approved by a maintainer size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants