[PR #197] [MERGED] Fix node discovery and doc matching in scan_missing_nodes #195

Closed
opened 2026-10-26 22:10:33 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/Comfy-Org/embedded-docs/pull/197
Author: @comfyui-wiki
Created: 10/22/2026
Status: ✅ Merged
Merged: 10/23/2026
Merged by: @comfyui-wiki

Base: main ← Head: fix/node-scanner-discovery


📝 Commits (4)

  • 022d424 Fix node discovery and doc matching in scan_missing_nodes
  • 2b6a58e Tighten discovery: registration membership, schema precedence, base resolution
  • 8b33976 Read schemas by registered node id in generate_docs
  • 3fc70a0 Keep reverted and non-backend pages out of the stale list

📊 Changes

5 files changed (+888 additions, -215 deletions)

View changed files

📝 docs-generation/README.md (+1 -1)
➕ docs-generation/config/non_backend_nodes.json (+34 -0)
📝 docs-generation/scripts/generate_docs.py (+104 -3)
📝 docs-generation/scripts/scan_missing_nodes.py (+636 -211)
➕ docs-generation/tests/test_generate_docs_schema.py (+113 -0)

📄 Description

Problem

scan_missing_nodes.py found nodes only through a literal node_id="X" regex plus classes exposing INPUT_TYPES. Everything else was invisible, the same loose regex also matched old_node_id=, and a class being defined was treated as being registered, so nodes that are commented out of the registry were reported as missing docs.

Measured against main on the same tree (ComfyUI 80c8e77d4), main's scanner reports 43 missing / 96 unclassified extra folders, and it is wrong in both directions:

  • Invisible nodes (14): node_id=cls.NODE_ID (Flux2Pro/Max, FluxKontextPro/Max), schema factories with the id as the first positional argument (_cloud_schema("ComfyCloudMiniMax…"), 4 nodes), old-style NodeId = "X" attributes (CombineHooks2/4/8, ConditioningSetDefaultCombine, PairConditioningSetDefaultCombine), and mapping aliases ("ModelMergeSD2": ModelMergeSD1 — the value→key reverse lookup only returned the first key).
  • Phantom nodes (3): ConditioningAverage (trailing space), SDV_img2vid_Conditioning, T2IAdapterLoader — all three only exist as old_node_id=.
  • Not nodes at all (12): test/disabled classes whose registration is commented out (ComboOptionTestNode, DCTestNode, InvertBooleanNode, Autogrow*TestNode, ComfySoftSwitchNode, ConvertStringToComboNode, MultiGPU_Options, RecraftStyleV3VectorIllustrationNode, …) plus ComfyCloudMiniMaxH3ReferenceToVideoNode, which is commented out in get_node_list with “Disabled until the server-side issue is fixed”.
  • False “missing” (35 of the 43): the docs folder was compared as an exact string, so docs/ClipLoader/ does not satisfy CLIPLoader, docs/VaeDecode/ does not satisfy VAEDecode, and so on for every acronym-named node.
  • Unexplained extra folders (96): one flat list mixing duplicates, renames, frontend-only pages, test-node pages and nodes removed upstream.

Fix

Discovery mirrors nodes.py:init_extra_nodes: a module is either V1 (NODE_CLASS_MAPPINGS keys are the node types, including loop-built maps and aliases) or V3 (comfy_entrypoint + get_node_list, where the node type is schema.node_id, spelled node_id="X", node_id=cls.NODE_ID, schema.node_id = "X" after super().define_schema(), a schema-factory positional argument, or a NodeId class attribute). Registration membership is mandatory — a class that is not returned by get_node_list / node_list is not a node, however complete its schema looks. Base classes resolve only by plain name inside the module, so comfy.samplers.CFGGuider never resolves to a same-named local class.

io.NodeReplace is read into a rename registry and used for classification, not discovery. Doc folders match on a normalized key (case/underscore/space-insensitive; ids that collide on that key only accept an exact match) and every leftover folder is classified:

reason meaning
duplicate same node already documented under its canonical folder
renamed node exists under another id, canonical folder missing
non_backend frontend virtual node / intentional page, listed in config/non_backend_nodes.json
retired no node and no rename (removed, renamed without NodeReplace, or never registered)

Result on the same tree

main's scanner this PR
nodes found 1008 999 (1008 − 23 wrong + 14 previously invisible)
missing docs 43 19 (5 Veed + 14 registration styles that were invisible)
spelling-only mismatches counted as missing 35, matched, reported separately
extra doc folders 96, unclassified 81, all classified: 58 retired, 7 duplicate, 10 renamed, 6 non-backend
nodes with change detection 74 79

Verification

  • COMFYUI_PATH=… python3 scripts/scan_missing_nodes.py on origin/main → exit 0, numbers above; the same tree with main's script gives the “before” column.
  • Lenient matching A/B: a scratch docs tree holding only ClipLoader/, VAEDecode/, SvdImg2vidConditioning/, CLIPLoader/, VAEEncode/ reports 2 spelling mismatches and 0 extras; main reports both nodes as missing.
  • Registration gate spot-check: comfy_extras/nodes_logic.py lists 5 registered classes vs 14 defined (DCTestNode, InvertBooleanNode, … commented out); nodes_recraft.py 19 of 22 (RecraftStyleV3VectorIllustrationNode never returned); nodes_comfy_cloud.py excludes the disabled reference-to-video node.
  • Downstream: prepare_ai_input.py node CombineHooks2, … node ComfyCloudMiniMaxH3TextToVideoNode, … node Flux2MaxImageNode all succeed — they only needed class_name from the report, which discovery now fills in.
  • docs-generation/tests/*: all pass (test_translation_fixes.py has one pre-existing fa-heading failure, unrelated), including six new regression tests for schema resolution.
  • Generator: all 19 missing nodes extract with inputs (0 before), 60/60 sampled documented nodes unchanged.

Review

An independent review (Codex CLI, on this branch) flagged: unconditional explicit-id registration, module-qualified base resolution, class attributes outranking the returned schema, additive schema candidates, and loop membership not being resolved. All are fixed in the second commit; the count differences it reported were a stale local checkout on my side, corrected here against origin/main. Its remaining item — generate_docs.py only reading literal node_id="X" — is fixed in the third commit: the extractor resolves the owning class through the scanner's AST helpers, keeps the literal fast path first, and 19 of 19 currently missing nodes now extract with inputs (was 0), with the sampled 60 documented nodes unchanged.

Out of scope (follow-ups)

  • The 58 retired and 7 duplicate folders are only reported — deleting/renaming them changes live docs URLs, so it needs its own PR.
  • Separate bug found while measuring: 35 doc folders on main are title-cased (ClipLoader/, VaeDecode/, UnetLoader/, …) instead of matching the node id, which is exactly the “docs exist but the scanner says missing” pattern. Whoever generates the folders should take the node id verbatim; this PR only makes it visible.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/Comfy-Org/embedded-docs/pull/197 **Author:** [@comfyui-wiki](https://github.com/comfyui-wiki) **Created:** 10/22/2026 **Status:** ✅ Merged **Merged:** 10/23/2026 **Merged by:** [@comfyui-wiki](https://github.com/comfyui-wiki) **Base:** `main` ← **Head:** `fix/node-scanner-discovery` --- ### 📝 Commits (4) - [`022d424`](https://github.com/Comfy-Org/embedded-docs/commit/022d4243035fa0449be59cb0e82fe4ac90a8d1f2) Fix node discovery and doc matching in scan_missing_nodes - [`2b6a58e`](https://github.com/Comfy-Org/embedded-docs/commit/2b6a58ecd5e24af7d9c50441faf7386c702c56f5) Tighten discovery: registration membership, schema precedence, base resolution - [`8b33976`](https://github.com/Comfy-Org/embedded-docs/commit/8b33976b79d5e3d40c787f44b21f187eb5b6a9c5) Read schemas by registered node id in generate_docs - [`3fc70a0`](https://github.com/Comfy-Org/embedded-docs/commit/3fc70a0b4f15f9270a4d4d6e32d85559e8a8cb74) Keep reverted and non-backend pages out of the stale list ### 📊 Changes **5 files changed** (+888 additions, -215 deletions) <details> <summary>View changed files</summary> 📝 `docs-generation/README.md` (+1 -1) ➕ `docs-generation/config/non_backend_nodes.json` (+34 -0) 📝 `docs-generation/scripts/generate_docs.py` (+104 -3) 📝 `docs-generation/scripts/scan_missing_nodes.py` (+636 -211) ➕ `docs-generation/tests/test_generate_docs_schema.py` (+113 -0) </details> ### 📄 Description ## Problem `scan_missing_nodes.py` found nodes only through a literal `node_id="X"` regex plus classes exposing `INPUT_TYPES`. Everything else was invisible, the same loose regex also matched `old_node_id=`, and a class being *defined* was treated as being *registered*, so nodes that are commented out of the registry were reported as missing docs. Measured against `main` on the same tree (ComfyUI `80c8e77d4`), `main`'s scanner reports **43 missing / 96 unclassified extra folders**, and it is wrong in both directions: - **Invisible nodes (14):** `node_id=cls.NODE_ID` (`Flux2Pro/Max`, `FluxKontextPro/Max`), schema factories with the id as the first positional argument (`_cloud_schema("ComfyCloudMiniMax…")`, 4 nodes), old-style `NodeId = "X"` attributes (`CombineHooks2/4/8`, `ConditioningSetDefaultCombine`, `PairConditioningSetDefaultCombine`), and mapping aliases (`"ModelMergeSD2": ModelMergeSD1` — the value→key reverse lookup only returned the first key). - **Phantom nodes (3):** `ConditioningAverage ` (trailing space), `SDV_img2vid_Conditioning`, `T2IAdapterLoader` — all three only exist as `old_node_id=`. - **Not nodes at all (12):** test/disabled classes whose registration is commented out (`ComboOptionTestNode`, `DCTestNode`, `InvertBooleanNode`, `Autogrow*TestNode`, `ComfySoftSwitchNode`, `ConvertStringToComboNode`, `MultiGPU_Options`, `RecraftStyleV3VectorIllustrationNode`, …) plus `ComfyCloudMiniMaxH3ReferenceToVideoNode`, which is commented out in `get_node_list` with “Disabled until the server-side issue is fixed”. - **False “missing” (35 of the 43):** the docs folder was compared as an exact string, so `docs/ClipLoader/` does not satisfy `CLIPLoader`, `docs/VaeDecode/` does not satisfy `VAEDecode`, and so on for every acronym-named node. - **Unexplained extra folders (96):** one flat list mixing duplicates, renames, frontend-only pages, test-node pages and nodes removed upstream. ## Fix Discovery mirrors `nodes.py:init_extra_nodes`: a module is either V1 (`NODE_CLASS_MAPPINGS` keys are the node types, including loop-built maps and aliases) or V3 (`comfy_entrypoint` + `get_node_list`, where the node type is `schema.node_id`, spelled `node_id="X"`, `node_id=cls.NODE_ID`, `schema.node_id = "X"` after `super().define_schema()`, a schema-factory positional argument, or a `NodeId` class attribute). **Registration membership is mandatory** — a class that is not returned by `get_node_list` / `node_list` is not a node, however complete its schema looks. Base classes resolve only by plain name inside the module, so `comfy.samplers.CFGGuider` never resolves to a same-named local class. `io.NodeReplace` is read into a rename registry and used for classification, not discovery. Doc folders match on a normalized key (case/underscore/space-insensitive; ids that collide on that key only accept an exact match) and every leftover folder is classified: | reason | meaning | |---|---| | `duplicate` | same node already documented under its canonical folder | | `renamed` | node exists under another id, canonical folder missing | | `non_backend` | frontend virtual node / intentional page, listed in `config/non_backend_nodes.json` | | `retired` | no node and no rename (removed, renamed without `NodeReplace`, or never registered) | ## Result on the same tree | | `main`'s scanner | this PR | |---|---|---| | nodes found | 1008 | 999 (1008 − 23 wrong + 14 previously invisible) | | missing docs | 43 | **19** (5 Veed + 14 registration styles that were invisible) | | spelling-only mismatches | counted as missing | **35**, matched, reported separately | | extra doc folders | 96, unclassified | **81**, all classified: 58 retired, 7 duplicate, 10 renamed, 6 non-backend | | nodes with change detection | 74 | 79 | ## Verification - `COMFYUI_PATH=… python3 scripts/scan_missing_nodes.py` on `origin/main` → exit 0, numbers above; the same tree with `main`'s script gives the “before” column. - Lenient matching A/B: a scratch docs tree holding only `ClipLoader/`, `VAEDecode/`, `SvdImg2vidConditioning/`, `CLIPLoader/`, `VAEEncode/` reports 2 spelling mismatches and 0 extras; `main` reports both nodes as missing. - Registration gate spot-check: `comfy_extras/nodes_logic.py` lists 5 registered classes vs 14 defined (`DCTestNode`, `InvertBooleanNode`, … commented out); `nodes_recraft.py` 19 of 22 (`RecraftStyleV3VectorIllustrationNode` never returned); `nodes_comfy_cloud.py` excludes the disabled reference-to-video node. - Downstream: `prepare_ai_input.py node CombineHooks2`, `… node ComfyCloudMiniMaxH3TextToVideoNode`, `… node Flux2MaxImageNode` all succeed — they only needed `class_name` from the report, which discovery now fills in. - `docs-generation/tests/*`: all pass (`test_translation_fixes.py` has one pre-existing fa-heading failure, unrelated), including six new regression tests for schema resolution. - Generator: all 19 missing nodes extract with inputs (0 before), 60/60 sampled documented nodes unchanged. ## Review An independent review (Codex CLI, on this branch) flagged: unconditional explicit-id registration, module-qualified base resolution, class attributes outranking the returned schema, additive schema candidates, and loop membership not being resolved. All are fixed in the second commit; the count differences it reported were a stale local checkout on my side, corrected here against `origin/main`. Its remaining item — `generate_docs.py` only reading literal `node_id="X"` — is fixed in the third commit: the extractor resolves the owning class through the scanner's AST helpers, keeps the literal fast path first, and **19 of 19** currently missing nodes now extract with inputs (was 0), with the sampled 60 documented nodes unchanged. ## Out of scope (follow-ups) - The 58 `retired` and 7 `duplicate` folders are only *reported* — deleting/renaming them changes live docs URLs, so it needs its own PR. - **Separate bug found while measuring:** 35 doc folders on `main` are title-cased (`ClipLoader/`, `VaeDecode/`, `UnetLoader/`, …) instead of matching the node id, which is exactly the “docs exist but the scanner says missing” pattern. Whoever generates the folders should take the node id verbatim; this PR only makes it visible. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-26 22:10:33 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Comfy-Org/embedded-docs#195
No description provided.