Files
Azornes-Comfyui-Model-Resolver/docs/architecture.md
T

169 lines
7.1 KiB
Markdown

# Backend architecture
Model Resolver keeps the ComfyUI entry point small and separates HTTP wiring from
the feature logic that powers each route.
## Runtime flow
1. `__init__.py` exposes the ComfyUI compatibility exports and initializes the
extension.
2. `core/extension.py` owns runtime state such as progress trackers and starts
route registration.
3. `core/routes/registry.py` loads the available integrations and builds a
`RouteContext` with explicit dependencies.
4. Modules in `core/routes/` adapt HTTP requests and responses to service calls.
5. Services in `core/services/` contain feature behavior and receive their
dependencies through `RouteContext`.
Route registration imports the concrete route modules directly. The actual
handlers live in focused route adapters and services; no compatibility grouping
layer is kept for this application-only package.
## Workflow analysis package
Workflow inspection is grouped under `core/workflow/` and is deliberately kept
separate from HTTP routes and workflow mutation:
- `widgets.py` contains static node-type and widget-position knowledge.
- `dynamic_widgets.py` discovers runtime widget metadata from ComfyUI nodes.
- `references.py` extracts model references and resolves local paths.
- `subgraphs.py` handles subgraph indexes and promoted inputs.
- `analysis.py` traverses workflows and aggregates missing-model results.
- `inventory.py` builds the cached inventory used by repeated analyses.
The dependency direction is layered: widget definitions are the base, dynamic
widget discovery builds on them, references consume both, subgraph handling
consumes references and widget definitions, analysis composes references and
subgraphs, and inventory consumes analysis. The package does not depend on
route adapters or services. `core/workflow_updater.py` remains a separate
writer used after resolution; it is not part of read-only workflow analysis.
When adding workflow behavior, place it in the narrowest component that owns
the responsibility and add a focused test in `tests/test_workflow_components.py`
or `tests/test_workflow_analyzer.py`. Keep imports within the documented layer
direction; `tests/test_workflow_boundaries.py` enforces this contract.
## Search provider availability
Search responses distinguish an unavailable provider from a successful search
with no matching model. Provider-specific failures are exposed in
`source_status` while the older `source_errors` field remains available for
diagnostics and compatibility:
```json
{
"source_errors": {
"civarchive": "CivArchive search failed: HTTP 522"
},
"source_status": {
"civarchive": {
"state": "unavailable",
"code": "provider_unavailable",
"retryable": true,
"http_status": 522,
"message": "CivArchive may be overloaded or temporarily unavailable. Please try again."
}
}
}
```
The frontend uses `source_status` for user-facing labels and notifications:
- `state: unavailable` means the provider or its network path is temporarily
unavailable; it is not a confirmed no-match result.
- `state: rate_limited` means the provider asked the client to slow down.
- `state: not_found` means the provider did not expose a matching page.
- `state: error` represents a non-retryable provider rejection or another
provider-specific failure.
When `retryable` is true, the source status row shows a retry action. A retry
repeats only that provider with a forced refresh and does not rerun the other
search sources. Automatic retry is intentionally not performed, so a slow or
overloaded provider cannot delay every search attempt.
The backend log uses structured fields such as `code`, `http_status`,
`retryable`, and `error_type`; user-facing messages should come from the safe
`message` field rather than the raw exception text.
## Frontend architecture
The frontend keeps ComfyUI-specific integration at the extension boundary in
`web/model_resolver.js` and composes the dialog behavior in
`web/resolver/resolver_dialog.js`. The dialog is assembled from focused method
groups:
1. `web/resolver/shell/` owns lifecycle, workflow identity, and tab state.
2. `web/resolver/search/` owns source selection, search state, aliases, and hash
matching.
3. `web/resolver/views/` owns view-specific state such as missing models and
model information.
4. `web/resolver/downloads/` owns queue storage and download progress policy.
5. `web/resolver/utils/` owns shared API, keybinding, and browser helpers.
Pure policies and state transitions are exported as small ES modules so they
can be tested without booting ComfyUI. The extension entry point and the dialog
composition are covered separately as integration contracts.
## Adding a route
When adding a feature, keep the request parsing, status codes, and JSON response
in a route adapter. Put reusable behavior in a service and add its dependency to
`RouteContext` explicitly. Use `json_api_endpoint` for the common error boundary,
and preserve deliberate `aiohttp.web.HTTPException` statuses when returning
client errors.
Add a focused route/service test before changing behavior. For changes that touch
route registration or shared backend code, run the complete Python suite as well.
## Local verification
For frontend changes, run these commands from the project directory:
```powershell
npm test
npm run test:coverage
npm run lint
```
`test:coverage` uses Node's built-in test coverage reporter and prints the
current statement, branch, and function coverage. It is an inspection report,
not a hard threshold, because runtime-only ComfyUI adapters cannot be fully
exercised outside the host application.
## Pull request checks
The repository workflow lives in `.github/workflows/ci.yml`. It runs the
frontend and backend checks for pull requests whose source repository is
outside this repository, which keeps automated validation focused on external
contributions. It does not run for direct pushes to `main`; local changes by
the maintainer should use the verification commands above before committing.
The workflow uses the tracked `package-lock.json` with `npm ci`, has read-only
repository permissions, and does not require secrets. Its two jobs run:
1. `npm test` and `npm run lint` for the frontend.
2. The Python suite with branch coverage for `core.workflow`, Ruff, and
`compileall` for the backend.
The backend job requires at least 75% coverage for `core.workflow` and uploads
the XML report as the `workflow-coverage` artifact. The threshold is scoped to
the refactored workflow package while the remaining legacy backends are being
covered incrementally.
The workflow uses `pull_request`, not `pull_request_target`, so code from an
external fork is tested with the restricted pull-request token context.
Run these commands with the same Python interpreter used by ComfyUI:
```powershell
python -m pytest
python -m ruff check __init__.py core
python -m compileall -q __init__.py core
python -m coverage run -m pytest
python -m coverage report -m
```
The development tools are declared in the `dev` optional dependency group in
`pyproject.toml`. Coverage configuration is kept there as well, with branch
coverage enabled and `core/` as the measured source.