Skip to content

refactor(model-manager): apply model record changes in the model manager service - #9941

Open
joshistoast wants to merge 4 commits into
mainfrom
refactor/model-record-change
Open

joshistoast wants to merge 4 commits into
mainfrom
refactor/model-record-change

Conversation

@joshistoast

@joshistoast joshistoast commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Editing a model record has to bracket the write so that loads which overlap it are rechecked. It also has to compare the old and new records, and drop cached instances under the model load lock when the change affects loading.

The load service owned that fence, but the model manager router carried out the steps itself. Its comparison also omitted models_path. So rewriting a model's path between its models-relative and absolute forms evicted the cached model and rejected in-flight loads, while the load service treated it as no change.

Commits:

  1. Fix (router comparison): the router compares paths the way the load fence does.
  2. Refactor (move into services):
    • The load service applies a record change as one operation (apply_record_change): the edit bracket, the store write, one comparison, and the drop from each distinct cache under the load lock.
    • The model manager service owns update_model_record and reidentify_model, including the fields kept on re-identification.
    • The router keeps the per-key claims and maps errors to HTTP.
    • One distinct_caches rule replaces the per-call-site handling of device-aliased caches.
  3. Fix (store key guard): the record store refuses an update whose key differs from the record's. A service caller can no longer write a record that reports a key nothing can look it up by. The router's 422 for this case is unchanged.

QA Instructions

  • uv run --no-sync pytest tests/app/routers/test_model_manager.py tests/app/services/model_manager tests/app/services/model_load tests/app/services/model_records tests/app/services/image_index passes.

  • Full suite (-n 4): 14980 passed. The failures were the 112 model-identification and model-path tests, which need git-lfs fixtures that were not installed on the test machine, and fail the same way on main.

  • New: tests/app/services/model_manager/test_model_record_changes.py uses a real SQLite store, two real ModelCaches and real identification of small synthetic files, and covers:

    • eviction per field;
    • the same file written as an absolute path;
    • store rejection;
    • re-identification keeping user settings.

    Threaded fence tests drive the real apply_record_change with a load queued on the lock, including a write that commits and then raises.

  • Mutation checks: each of these makes at least one test fail:

    • writing outside the bracket;
    • dropping after it;
    • no bracket;
    • clearing the recheck flag on a failed write;
    • dropping only one alias or one key;
    • comparing without models_path;
    • releasing the key claim before the write.
  • The OpenAPI schema generated from this branch is identical to the committed openapi.json.

Review

Resolved:

  • The new interface had no test that the write and the cache drop happen inside the edit bracket. Without one, a regression could again build and cache a model from a superseded record.
  • A leftover public bracket method allowed writes that skipped the drop.
  • The key-immutability rule was enforced only in the router.

No remaining material findings. The router's per-key claims staying in the router is deliberate; moving them is a separate change.

Compatibility / Rollout

  • HTTP routes, status codes, details and the OpenAPI schema are unchanged.
  • ModelLoadServiceBase.record_edit is removed from the base interface. No caller remains.
  • ModelRecordServiceSQL.update_model now raises ValueError when given a different key. No in-repo caller does this.

Checklist

  • The PR has a short but descriptive title, suitable for a changelog
  • Meaningful regression coverage added / updated where needed; obsolete tests/code removed
  • Persisted-state and API changes include required migrations / compatibility validation
  • Relevant performance/efficiency opportunities considered; material claims have evidence
  • Material review findings resolved and relevant checks rerun
  • Documentation added / updated (if applicable)
  • Updated What's New copy (if doing a release after this PR)

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

…pdating records

Rewriting a model's path between its models-relative and absolute forms no longer evicts the cached model or rejects in-flight loads.
…ger service

The load service applies a record change as one operation: the edit bracket, the store write, one comparison and the cache drop under the load lock.
The model manager owns update and re-identification; the router only claims the key and maps errors to HTTP.
The record store rejects an update whose key differs from the record's, so service callers cannot write a record that reports a key nothing can look it up by.
@github-actions github-actions Bot added api python PRs that change python files services PRs that change app services python-tests PRs that change python tests docs PRs that change docs labels Oct 19, 2026
@JPPhoto
JPPhoto self-requested a review October 19, 2026 10:44

@JPPhoto JPPhoto left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pre-existing issues that you can fix:

  • invokeai/app/services/model_load/model_load_default.py:221-225: If a write commits then raises, cache eviction is skipped; later loads can reuse the old model. The base router had the same behavior, and the new test covers only a cold load. Suggested issue: test this failure with a warm cache and evict if the stored record changed.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api docs PRs that change docs python PRs that change python files python-tests PRs that change python tests services PRs that change app services

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants