Files
DemonGatanjieu-Anomalous_Mo…/ARCHITECTURE.md
T

197 lines
13 KiB
Markdown

# Anomalous Model Browser Architecture
This is the short entry point for maintainers and AI agents. It describes the
system map, ownership boundaries, and rules that apply across subsystems. Read
only the linked topic document relevant to the task; do not load every document
by default.
## Reading map
Before implementation, follow [AGENTS.md](AGENTS.md), the canonical development
and maintenance rules. [GEMINI.md](GEMINI.md) is the Gemini reading entry point.
The prompt studio reads material prompt payloads through `web/modules/material_prompt_data.js`;
list summaries do not contain prompt bodies. See the Material Library contract below.
| When changing... | Read... |
| --- | --- |
| Python routes, storage, paths, metadata, covers, or scan state | [`docs/architecture/backend.md`](docs/architecture/backend.md) |
| Browser lifecycle, UI state, localization, media, or graph edits | [`docs/architecture/frontend.md`](docs/architecture/frontend.md) |
| Update-guide content/versioning or sidebar hover labels | [`docs/architecture/update-guide.md`](docs/architecture/update-guide.md) |
| Workflow Recipes, packages, galleries, Parameter Notebooks, or prompt roles | [`docs/architecture/recipes.md`](docs/architecture/recipes.md) |
| Material Library snapshots, image parameter details, or reusable node blocks | [`docs/architecture/material-library.md`](docs/architecture/material-library.md) |
| Model Doctor, provenance hashes, missing-model recovery, or deep scanning | [`docs/architecture/model-resolution.md`](docs/architecture/model-resolution.md) |
| Why a current product boundary exists | [`docs/decisions/README.md`](docs/decisions/README.md) |
| Recurring implementation mistakes and post-mortems | [`.agents/logs/ai_lessons.md`](.agents/logs/ai_lessons.md) |
`README.md` is user-facing documentation and `CHANGELOG.md` is user-facing
release history. Neither is the source of truth for internal architecture.
## System shape
Anomalous Model Browser is a UI-only ComfyUI extension. It registers no custom
nodes (`NODE_CLASS_MAPPINGS` is empty). ComfyUI loads the Vanilla JavaScript/CSS
frontend from `web/`; the Python package registers `/anomalous/` `aiohttp`
routes and performs local filesystem, metadata, recipe, and scan operations.
```text
ComfyUI frontend
web/main.js
-> web/modules/* UI, graph integration, localization
-> /anomalous/* JSON and bounded media requests
ComfyUI Python server
__init__.py
-> api/__init__.py route registration
-> api/*.py storage and domain operations
-> scraper.py explicit metadata/hash enrichment
User-owned data
ComfyUI model folders models and sidecars
user/.../anomalous_recipes workflow recipes and recipe assets
user/.../anomalous_parameters immutable parameter snapshots
user/.../anomalous_materials curated image/workflow material bundles
user/.../anomalous_notebooks prompt notes, with legacy originals preserved
```
The frontend and backend communicate through narrow JSON contracts. The
frontend must not infer filesystem authority, and the backend must not depend on
DOM or live LiteGraph state.
## Ownership map
### Backend
- `api/config.py` owns configured paths and active model-folder types.
- `api/utils.py` owns containment and filename validation helpers.
- `api/metadata.py` owns sidecar and safetensors metadata extraction.
- `api/models.py` owns model listing, media serving, and model-facing routes.
- `api/scanner.py` and `scraper.py` own scan orchestration and enrichment.
- `api/recipes.py` owns recipe validation, CRUD, history, and integrity receipts.
- `api/recipe_packages.py` owns bounded inspect-stage-commit package handling.
- `api/parameters.py` owns Parameter Notebook persistence and lookup.
- `api/notebooks.py` owns Prompt Note persistence and recoverable legacy copying.
- `api/materials.py` owns curated material persistence, private image assets,
summary search/pagination, editable names/tags, and node-type lookup.
- `model_policies.py` owns shared backend rename and protected-category policy.
- `model_identity.py` owns file SHA-256 evidence shared with the standalone scanner.
### Frontend
- `web/main.js` registers the extension and owns the shared browser instance.
- `ui_sidebar.js` creates the browser shell, navigation and settings. Its large
`createDOM` method remains a maintenance hotspot; new tool implementations
should live in their own modules rather than expanding that method.
- `ui_update_guide.js` owns the non-intrusive update guide modal (accessible via header icon).
- `sidebar_actions.js` owns the sidebar bottom action hover-reveal short labels (100ms), singleton dynamic DOM tooltip bubbles (`#anomalous-sidebar-tooltip-bubble`, 600ms), click/pointerdown instant text/tooltip suppression guards, `isBottomModalOpen` tooltip occlusion guards, and anti-flicker pointer stability.
- `tool_registry.js` centralizes metadata, SVG icons (enlarged 20px crisp vector outlines with 2px stroke, #cbd5e1 contrast), and stable IDs for the 9 catalog tools (including Prompt Notes / 提示词笔记) and 2 fixed anchors (Toolbox and Settings).
- `shortcut_layout.js` provides tool layout utilities and fallbacks. The bottom shortcut bar maintains the clean fixed 4-tool setup (`scan`, `doctor`, `assistant`, `materials`) plus two anchors (`toolbox`, `settings`) housed in prominent 36px buttons with full click/active text suppression and `.is-active` toggled styling.
- `ui_sidebar.js`'s Toolbox modal strictly filters out all tools already present on the bottom bar, presenting a sleek 216px auto-height utility catalog with compact, frameless 40px tiles, downward anchor caret pointing to the toolbox trigger button, 0.18s smooth spring pop-in animation, clean click action execution, and zero obstructive text or beta footers.
- `ui_grid.js` and model-detail modules own model presentation; `ui_gallery.js`
and `ui_gallery_detail.js` own generated-image browsing and inspection.
- `ui_recipes.js` / `ui_recipe_detail.js`, `ui_notebooks.js`, and `ui_materials.js`
own their respective workspace surfaces and persistence flows. `ui_notebooks.js`
owns structured Prompt Notes (提示词笔记), integrated as a standard tool in the Toolbox
with defensive workspace return state restoration, and redesigned with companion models
(Base architecture, Main checkpoint, and LoRA stack) prominently positioned at the top of the editor,
followed by the core prompt composer and material library archiving, guarded by Temporal Dead Zone (TDZ)
safe summary initialization and responsive empty-state fallback rendering. `ui_recipe_detail.js`
owns the Workflow Recipe detail workspace, including Overview prompt showcase (with `entry.text` fallback),
the responsive Parameter Presets workspace (featuring default-expanded raw node parameter inspection,
a `clamp(230px, 24vw, 290px)` sidebar with guarded card actions, uncluttered console action bars with deferred status feedback,
`minmax(130px, 1fr)` Bento Grid with universal click-to-copy, LoRA cards with flexbox truncation guards,
and sticky editor headers), as well as Versions timeline and Recipe Gallery.
- `ui_prompt_composer.js` owns the standalone Prompt Studio drawer. Its child
views are `ui_prompt_source_deck.js`, `ui_prompt_workbench.js`, and
`ui_prompt_inspector.js`. Assembly plan data, track-vs-role separation, and
cross-role tail smart-sorting are owned by `prompt_composition.js` and `prompt_studio_data.js`.
`ui_prompt_source_deck.js` owns the card preview popover with narrow bridging corridors,
differentiated hide timers, and fast dismissal when hovering or clicking library blank space.
- `ui_prompt_translator.js` owns the standalone translator. Both translator and
studio use `ui_lifecycle.js` for global listeners, request cancellation and
resize cleanup. Translation requests go through `translation_service.js`.
- `ui_dom.js` provides small DOM/JSON helpers; `material_inspector.js` owns
material-specific metadata and parameter rendering.
- `ui_doctor.js`, `model_picker.js`, `node_material_actions.js`, and
`graph_splice.js` own diagnostics and explicit graph changes.
- `ui_model_sources.js` owns the Model Source Hub (模型来源统一中控中心), providing dual-scope
(Workflow and Library) source inspection, external platform jumping, canvas `Note` node generation,
and `workflow.extra.anomalous_model_sources` metadata synchronization.
- `locales.js` is the shared runtime string catalog. Existing inline bilingual
UI strings remain migration debt; new strings belong in the catalog.
- `styles.css` owns presentation and theme overrides. Color values, dimensions
and visual design descriptions are not duplicated as architectural contracts.
## Cross-system invariants
These rules are intentionally summarized here and specified in the linked topic
documents.
1. **Identity is provenance, not naming.** Model Doctor may use a cryptographic
hash, exact byte size under the allowed category policy, and target category.
Paths, filenames, display names, previews, and fuzzy similarity are never
identity evidence.
2. **Filesystem input is untrusted.** Backend request paths must pass the shared
containment and filename helpers. Checking only for `..` is insufficient on
Windows and in the presence of alternate separators, UNC paths, or symlinks.
3. **User files are changed transactionally and conservatively.** Recipe writes,
imports, graph mutations, and sidecar operations validate before mutation and
either complete coherently or restore the prior state.
4. **The event loop stays responsive.** Recursive walks, hashing, metadata
parsing, and other potentially large disk operations run off the aiohttp
event loop. UI rendering and media loading are bounded and cancellable.
5. **Host state is preserved.** Browser panels are mutually exclusive,
Workspace/model-detail transitions are recoverable, and graph edits use
ComfyUI's change/callback contracts.
6. **Runtime strings are localized safely.** User-visible copy comes from
`locales.js`; dynamic values stay outside dictionaries and enter the DOM as
text. Only allowlisted rich content goes through `safe_dom.js`.
7. **Optional integrations fail locally.** Missing graph APIs, metadata, network
availability, or an optional resolver may disable that capability but must
not make the main extension disappear.
8. **Presentation data is not authority.** Covers, thumbnails, summaries,
cached names, and workflow fingerprints never replace the authoritative
serialized workflow or model provenance record.
## Data and compatibility boundaries
- Runtime settings and newly saved API keys live in `api/config.json`.
`scraper.py` may read the legacy root `config.json` only as a compatibility
fallback. API keys are not stored in browser `localStorage`.
- Recipes, Parameter Notebooks, and Material Library records/assets are user data outside the extension directory.
They are never bundled with or silently migrated into the plugin source.
- The extension may integrate with Civitai and optional translation services
only through explicit product behavior. External content and dependencies keep
their own terms.
- Project code and documentation use the MIT license. `TRADEMARKS.md` separately
defines the project-name and official-branding boundary.
- Internal property names and established routes may remain stable when a
user-facing surface is renamed. Do not churn compatibility contracts merely
to match presentation wording.
## Change and snapshot protocol
Every product-code change should end as one coherent local Git snapshot:
1. Run checks proportional to the changed behavior.
2. Update architecture documentation **only** when the change modifies a module
owner, data flow, public/internal interface contract, persistence format,
security boundary, or critical invariant.
3. When architecture changes, update the narrowest relevant topic document.
Update this entry point only if the system map, cross-system invariants, or
reading map changed.
4. Do not add an architecture entry merely to say that existing boundaries were
unchanged. Ordinary fixes belong in code, tests, Git history, and—when useful
to users—`CHANGELOG.md`.
5. Record a durable lesson in `.agents/logs/ai_lessons.md` only for a recurring
trap or a critical failure mode, not as a turn-by-turn work log.
6. Create a local commit after verification. Keep unrelated work out of the
snapshot and do not push without explicit user authorization.
7. Leave a clean worktree, or identify every intentional uncommitted file in the
handoff.
Decision records explain enduring choices; they are not a chronological diary.
Git history is the authoritative record of implementation changes. Planning-only
documents must be clearly labeled as proposals and must not describe unshipped
behavior as current architecture.