mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-07-03 13:48:49 +00:00
## Summary Redesign missing-model detection for ADR 0009 promoted subgraph widgets so candidates are created from the widget value the user can actually edit, while still using the concrete interior widget as the schema/options source. ## Why This PR Exists This PR comes from the follow-up missing-model detection work for the ADR 0009 / 1.46 subgraph widget changes introduced by [#12197](https://github.com/Comfy-Org/ComfyUI_frontend/pull/12197). [#12197](https://github.com/Comfy-Org/ComfyUI_frontend/pull/12197) intentionally changed promoted subgraph widgets to be represented through subgraph input links. After that change, the promoted widget on the host `SubgraphNode` is the editable value owner, and linked interior widgets are no longer guaranteed to mirror that value. The old missing-model contract still treated the concrete interior node widget as the effective source of truth in subgraph cases: - recursive scans entered the subgraph and scanned the interior widget value; - candidates were keyed by the interior node/widget identity; - the parent subgraph host mostly received propagated highlight/navigation behavior; - subgraph container widgets were not treated as first-class candidate sources. That contract breaks after ADR 0009. A user can resolve a missing model by changing the promoted host widget to an installed model, while the linked interior widget can still hold the old stale value. If detection keeps scanning the linked interior value, entering the subgraph or reloading the workflow can re-create a false missing-model error that no longer corresponds to the value the user can edit. ADR 0009 also means the same subgraph definition can be reused by multiple `SubgraphNode` hosts. Once missing-model detection moves from the interior definition widget to the promoted host widget, the selected value is no longer a property of the shared definition alone. It is a property of a specific host instance. That makes the old interior-node identity insufficient for mode changes, removal handling, and re-scan behavior: a single interior leaf definition can be reachable through multiple host execution paths, and only the affected host path should add, remove, or restore a candidate. This PR also builds on [#12990](https://github.com/Comfy-Org/ComfyUI_frontend/pull/12990), which narrowed workflow-level `models[]` and embedded model data to metadata enrichment only. Together, the intended boundary is: - live widgets create missing-model candidates; - workflow/root-level `models[]` and node metadata only enrich candidates that already came from a live widget; - promoted widget values are read from the editable host widget, not inferred from stale interior `widgets_values`. ## Changes - **What**: - Introduces promoted-widget scan targets that split: - host promoted widget value and candidate identity; - concrete leaf widget/node definition data. - Scans the outermost unlinked promoted widget on a `SubgraphNode` host as the selected value owner. - Skips linked interior widgets as candidate sources, preventing stale linked widget values from producing duplicate or false missing-model candidates. - Resolves the concrete leaf widget for combo options, asset-widget support, node type, directory lookup, and embedded metadata enrichment. - Keys promoted missing-model candidates by the host execution id and host promoted widget name. - Adds `sourceExecutionId` to promoted candidates so liveness still follows the concrete source execution path, including nested inactive subgraph containers. - Uses source-scope activity for pipeline filtering and async verification, while keeping highlight/store/clearing identity host-keyed. - Removes host-keyed promoted candidates when their source execution scope is removed or bypassed. - Re-scans ancestor subgraph hosts when an interior source path is un-bypassed, so host-keyed promoted errors can reappear correctly. - Handles shared subgraph definitions by deriving promoted source paths from the concrete host instance path, rather than treating the shared definition node id as globally unique. - Shares promoted source resolution between Vue node processing and the right-side panel to avoid drift. - Aligns missing-model clearing across Vue node widgets, legacy canvas widgets, and right-side panel Parameters/Nodes section widgets. - Adds unit coverage for scan identity, source-scope liveness, dynamic mode changes, source-scope removal, shared-definition host isolation, and right-side panel clearing. - Adds nested promoted-widget E2E coverage for OSS and Cloud flows across Vue, Parameters tab, and legacy widget surfaces. - **Breaking**: None expected. - **Dependencies**: None. ## New Detection Contract A missing-model candidate is created from an unlinked final editable value owner. That value owner can be: - a normal node model widget; or - the outermost promoted model widget displayed on a `SubgraphNode` host. For promoted widgets: - the host promoted widget supplies the selected value; - the host execution id and host widget name are the candidate identity; - the concrete leaf widget supplies definition data such as combo options and asset-browser support; - the concrete source execution path is retained as `sourceExecutionId` for liveness only; - linked interior widgets are skipped as candidate sources because their values are not authoritative when driven by a promoted input. For a nested chain: `Outer promoted widget A -> inner promoted widget B -> concrete widget C` only `A` creates the candidate. `B` and `C` are linked along the promoted-input path and are skipped as selected-value sources, while `C` still provides the concrete widget definition used to evaluate `A`. ## Shared Definition And Source-Scope Liveness ADR 0009 promoted widgets make subgraphs behave more like reusable definitions with host-owned inputs. Two host `SubgraphNode`s can point at the same interior subgraph definition while carrying different promoted widget values. In that shape, the missing-model candidate must be keyed to the editable host surface, but the activity check cannot use the host id alone. For example, if two outer hosts share the same nested subgraph definition, one host can select a valid model while the other still selects a missing model. The result should be one missing-model reference, not a single definition-level error and not two errors after one host is fixed. Likewise, bypassing or un-bypassing an interior nested container should affect only the host execution paths that actually pass through that container. This PR therefore separates two concepts: - **candidate identity**: host execution id + host promoted widget name, used for storage, highlight, navigation, and clearing; - **candidate liveness**: concrete source execution path, used for scan-time activity checks, pipeline filtering, async verification, source-scope removal, and re-exposure after mode changes. That separation is the reason this PR updates more than the scan itself. Moving the detection target to the subgraph host also requires the mode-change and removal paths to understand that a host-keyed candidate can be invalidated by a descendant source path, and can need to be restored by re-scanning an ancestor host when an interior source path becomes active again. ## Review Focus Please review the identity split carefully: - candidate/store/highlight/clearing identity should remain host-keyed for promoted widgets; - liveness should use `sourceExecutionId` when present, falling back to `nodeId` for normal candidates; - scan-time activity checks should account for the source node itself and all ancestor subgraph containers; - source-scope removal should remove host-keyed candidates whose concrete source path was removed or bypassed; - un-bypassing an interior source path should re-scan affected ancestor subgraph hosts so host-keyed candidates can reappear; - shared subgraph definitions should not merge errors across different host instances; - linked interior widgets should not produce their own missing-model candidates; - asset-browser eligibility should be resolved from the concrete leaf node type and widget name, not the synthetic subgraph host type; - right-side panel edits should clear host missing-model errors and source validation errors consistently. The E2E matrix intentionally keeps nested promoted workflows only. Nested promoted widgets cover the same editable host path as single promoted widgets while also exercising the `A -> B -> C` chain that can break source-scope liveness and re-scan behavior. The nested fixture also includes multiple host instances that share the same subgraph definition, so it verifies that fixing one host does not accidentally clear or suppress another host's missing-model candidate. Direct/single promoted behavior is still covered at the unit level. ## Non-Goals - This PR does not reintroduce workflow-level `models[]` candidate creation. - This PR does not infer selected model values from `widgets_values`. - This PR does not synchronize linked interior widget values back from promoted host widgets. - This PR does not redesign missing-media scanning; missing media still skips subgraph containers and remains keyed by concrete interior paths. The shared async post-verification active-scope filter is intentionally stricter, so a pending missing-media candidate is no longer surfaced if its own node is bypassed or removed while verification is in flight. ## Validation - `pnpm exec vitest run src/components/rightSidePanel/parameters/SectionWidgets.test.ts src/platform/missingModel/missingModelScan.test.ts src/composables/graph/useErrorClearingHooks.test.ts src/platform/missingModel/missingModelPipeline.test.ts src/platform/missingModel/missingModelStore.test.ts src/utils/graphTraversalUtil.test.ts src/composables/graph/useGraphNodeManager.test.ts src/renderer/extensions/vueNodes/composables/useProcessedWidgets.test.ts --reporter=dot` - 8 files passed, 294 tests passed. - `pnpm exec vitest run src/platform/missingModel/missingModelScan.test.ts src/core/graph/subgraph/resolveConcretePromotedWidget.test.ts src/components/rightSidePanel/parameters/SectionWidgets.test.ts` - 3 files passed, 71 tests passed. - `pnpm typecheck` - `pnpm typecheck:browser` - `pnpm format:check` - targeted ESLint for changed production/unit/E2E files - `git diff --check` - `pnpm build` - `pnpm build:cloud` - OSS affected E2E on the 8188 build: - `PLAYWRIGHT_LOCAL=1 PLAYWRIGHT_TEST_URL=http://localhost:8188 pnpm exec playwright test browser_tests/tests/propertiesPanel/errorsTabModeAware.spec.ts --project=chromium --grep "Changing an OSS .*promoted|Refreshing a resolved promoted|Reloading a resolved nested"` - 5 passed. - Cloud affected E2E on the 8188 cloud build: - `PLAYWRIGHT_LOCAL=1 PLAYWRIGHT_TEST_URL=http://localhost:8188 pnpm exec playwright test browser_tests/tests/propertiesPanel/errorsTabCloudMissingModels.spec.ts --project=cloud --grep "Changing a Cloud .*promoted"` - 2 passed; the Cloud legacy promoted asset-modal case still fails until [#13075](https://github.com/Comfy-Org/ComfyUI_frontend/pull/13075) is merged. - Full OSS `errorsTabModeAware.spec.ts` on the 8188 build: - 23 passed; 3 existing paste/clipboard cases failed before the promoted subgraph section with node count remaining at 1 after `clipboard.paste()`. - Commit hooks ran `oxfmt`, `oxlint`, `eslint`, `pnpm typecheck`, and browser typecheck where applicable. - Pre-push hook ran `pnpm knip --cache`. ## Screenshots Before https://github.com/user-attachments/assets/6380c1da-1d92-4b70-888e-3ade572c4b5b After https://github.com/user-attachments/assets/4cfc24d6-3dc3-4e36-9b31-72fea6b3d9d5