Files
DemonGatanjieuandClaude Opus 5.5 efa588bdc2 Say what Model Check can do without fingerprints, link its rules
The README now says in both languages that fingerprints come from this
plugin, what Model Check still does for a workflow without them (a file of
the same name to confirm, the workflow's own links, ComfyUI-Manager's list),
and has a button to the rules page, now also in English. The rules page
names ComfyUI's own model links. Also corrected: interface scale (not font
size), what Import keeps and replaces, the Gates list, and the one-server
note on cloud servers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 16:05:40 +08:00

10 KiB

Model Identity and Scanning

Read this document for Model Check, workflow provenance, missing-model recovery, hash caches, Civitai metadata resolution, or model scanning. The rules as a whole, in plain words (what counts as the same model, the confidence levels, foundation components, download sources), are in docs/guides/model-check-rules.md and its English copy model-check-rules.en.md; keep all three in step.

Identity boundary

Model Check recovers the same physical model referenced by provenance embedded in a workflow or image. Local renames and path differences are the problem it solves, so names cannot also be its proof.

Allowed automatic evidence is:

  1. plugin-carried cryptographic hash;
  2. exact physical byte size only as a disambiguator for that hash;
  3. the model category required by the target widget.

Without a hash, one unique in-category size match is only a candidate. Model Doctor shows it, but it cannot redirect the node until the user takes that candidate. Confirmation applies to the current node only; it does not create a persistent binding. If both hash and size are present and point to conflicting physical files (both match distinct local files), resolution reports an identity conflict and is rejected. When a requested model hash simply does not exist in any local file, it returns {"found": False} cleanly without falsely flagging a conflict.

Paths, filenames, source filenames, display/custom names, previews, workflow fingerprints, and fuzzy/visual similarity never establish identity. They may be used only after identity is established to return a local dropdown value, locate presentation media, and verify the value against ComfyUI's native choices. One exception, for ordinary models only: when the workflow carries no record at all (a workflow saved without the plugin), the single file of the same name among the widget's own choices is offered as a candidate (via: 'name'); a size-only candidate whose name also matches is shown as likely (via: 'name-size'). Both take a press on their row and never count among the files put in at once. Several files of that name leave the model ambiguous.

Foundation components—vae, vae_approx, clip, text_encoders, and clip_vision—are hash-only automatic-recovery categories. Byte size alone cannot automatically repair them, and they are never offered by name. When size provenance is available it may be shown as the same explicit manual candidate, but a supplied hash mismatch never falls back to a filename or size-only guess. This is a Model Check confidence boundary, not a scanner-support boundary. The scanner may traverse any active registered model folder and can still calculate a local hash when Civitai has no matching record. Sparse or ambiguous remote metadata is a reason to require cryptographic identity, not to exclude the category from scanning.

An existing native combo value remains loadable even if a foundation component's current local hash differs from stored provenance. Model Check shows a non-blocking identity-change warning instead of declaring the node missing or replacing it. If the value is absent, redirection requires one exact in-category hash match. Missing or ambiguous evidence remains unresolved for manual action.

Slash normalization of a value that already has an exact native-option equivalent is representation normalization, not discovery. The resolver must never append a foreign or cross-category value to widget.options.values merely to claim success.

Frontend provenance cache and injection

window.anomalous_hash_cache maps model widget values to exact SHA-256 and size records. It is fetched by the optional resolver from /anomalous/all_hashes. Relative-path and basename aliases exist only when unambiguous; if two files share an alias but differ in identity, omit that alias. Lookups prefer the full widget value before basename fallback.

After a scan writes new metadata, window.anomalous_reload_hashes() refreshes the frontend cache.

When provenance injection is enabled, the compatible active graph constructor's serialize path writes extraObj.anomalous_hashes[node_id_filename] = {hash, size} for known model widgets. The cache covers ordinary models and foundation categories. A foundation component without a recorded hash receives no size-only provenance. The same pass writes extraObj.anomalous_model_sources: links the workflow keeps win; a model present here without one gets its own information's link (the editor's first, else Civitai's), marked auto so a newer one replaces it; links for names no node holds any more are dropped. The live graph is never changed. The share-code export may leave the links out. A missing compatible graph API disables only injection and recovery integration, not the main browser.

Exact-path checks are limited to preflight confirmation that an already resolved local value exists. Backend discovery constrains candidates to the inferred category and intersects saved hash/size evidence. One unique in-category size-only match is returned as a confirmation-required candidate; it is never an automatic result. Multiple equal-sized candidates remain unresolved. A real hash/size conflict is rejected.

Metadata association

A Civitai .info record can describe multiple physical files, such as a model, text encoder, and VAE. get_metadata() selects the matching files[] entry by exact physical byte size. An unmatched entry may be used only when it is the sole hash candidate. Never take the first SHA-256 or select among entries by filename.

Metadata refresh is enrichment, not identity mutation. Offline generated metadata includes the discovered hash, but consumers still associate the record with the current physical file through the established size/name rules; array position is not identity.

Scanning

A scan (the scan page) runs outside the aiohttp event loop and identifies a model through the established fallback sequence:

  1. use existing valid file SHA-256 metadata when the scan does not request refresh;
  2. otherwise calculate the complete file SHA-256, never a ModelSpec header digest;
  3. if the remote service has no record, infer a bounded local base-model family from tensor/header fingerprints and write offline metadata.

model_identity.py owns digest validation and the anomalous_file_identity sidecar record: algorithm, file scope, digest, physical size/mtime, and computed source. ModelSpec hashes may describe tensor content and are never full-file identity (specification). Old locally inferred sidecars without this record keep their display data but need an explicit scan or successful on-demand SHA-256 check before supplying identity again. Successful on-demand verification preserves existing notes and remote metadata. Imported workflow provenance stays intact; it must match valid local file evidence.

Remote metadata requests are part of an explicit user-initiated scan. Local browsing and offline inference remain usable when the service is unavailable.

Physical rename conflicts are non-destructive. If the generated target filename already exists, hash both complete files. Deletion is allowed only when their full SHA-256 values match. Distinct files with the same generated display name are both preserved.

Resolution execution

The frontend finds unresolved workflow nodes and sends provenance hash, byte size, and inferred model category to the batch endpoint, falling back to the single-item endpoint if batching fails. Requests are grouped by the exact model category tuple so the backend scans each group once, but every result retains the same hash, size, category, conflict, and ambiguity rules.

If a size-selected candidate lacks cached hash metadata, the backend may hash it on demand. Only an exact hash match establishes identity; successful discovery may write offline metadata for later reuse.

After a hash match—or explicit confirmation of a size-only candidate—the frontend refreshes ComfyUI's native combo definitions and accepts the returned path only if it is present in the target widget's choices. Then it updates the dropdown through the node's widget hooks, which also clears ComfyUI's missing-model mark.

The check reads every drop-down naming a model file, and rgthree's Power Lora Loader's switched-on rows, which are no drop-downs (powerLoraRowBoxes in lora_nodes.js shows each as one: ComfyUI's LoRA list as its choices, a fix changing only the row's LoRA). The fingerprints a saved workflow carries (hash_resolver.js) and a picture's model search (api/image_search.py) read those rows too.

A model that is not here can also be found in ComfyUI-Manager's model list (the installed Manager's model-list.json, api/manager_catalog.py): an entry of the same file name whose SHA-256 matches the workflow's fingerprint is a certain source and is downloaded like the others; an entry of the same name with no fingerprint to check is offered as "Download by name", marked as such, for the user to decide. The page says where each link comes from.

Checking never changes the workflow (model_check.js). Every opened workflow is checked without reloading ComfyUI's model lists; when models are missing, a bar over the canvas says how many and how many hash matches can be put in. Only a press puts them in: the bar's or the doctor page's for hash matches, the page's per-row button for a size-only candidate. A scan with "fix the open workflow" on puts hash matches in when it ends.

A model that is not here can be downloaded from the page when its source names one exact file: Civitai by the workflow's hash, or a file link the workflow carries. The download is checked against the SHA-256 before it gets its name, so a wrong file never lands in a models folder; the file keeps the workflow's name, and nodes are pointed at it only when it went to another folder than the workflow says.

Provenance-rich workflows skip the redundant full filename-to-hash cache refresh. Legacy workflows without injected provenance may refresh it for compatibility. This is an I/O optimization only and does not change identity evidence.

Civitai lookup by hash may resolve a model/version page and route mature content to the configured domain. Hash-detail UI may compare and copy workflow and local hash/size values. Neither presentation feature changes recovery rules.