Make a loaded adapter row describe the adapter it actually loaded

The report row contradicted itself. The reason came from the attachment
record while path, adapter_id, base_model, origin and cartridge_id came from
whatever resolution preferred right now. Reproduced without any stubbing: a
live model holds adapter X, training writes a newer adapter Y, and the
endpoint then answers state=loaded adapter_id=adapter-Y while explaining
"attached to the live model from .../x-attached". A JSON consumer reads the
identity columns as the loaded adapter and gets the wrong one.

The same root cause had a second symptom. Attachments were keyed by kind with
last-writer-wins, so with two live runtimes one unload made the row claim
"that model is gone" while the other runtime's model was still alive holding
its adapter.

LoadRecord now carries the AdapterSource it came from, so a row built from a
record has exactly one identity, and the registry is a list of attachments
each holding its own weak reference: loaded means some live model still holds
an adapter, and when more than one does the reason names the other.

clear_loads had no production caller once unload stopped erasing the process
record, so it is gone rather than kept as a test-only entry point.

Two tests pin both symptoms, and both were mutation-checked: restoring the
identity to the resolved source fails the first, and letting
live_attachments ignore liveness fails the second and the unload test.

pytest -q: 227 passed. ruff clean. mypy cold cache on the three touched
source files: 2 errors, byte-identical to the same command on a stashed HEAD
tree, net zero. pyright: 2 errors, both the known qwen_vl_utils tuple
artifact, unchanged from HEAD.
This commit is contained in:
ZacharyZhang-NY committed 2026-10-08 00:23:45 -04:00
1 parent 2d1cfdadc7
commit 7ec25bf629
3 files changed
+110 -60

No files matched your search

+39 -2
View File
@@ -117,9 +117,9 @@ class _FakeProcessor:
@pytest.fixture(autouse=True)
def _no_stale_loads():
adapters.clear_loads()
adapters._ATTACHMENTS.clear()
yield
adapters.clear_loads()
adapters._ATTACHMENTS.clear()
def test_a_library_adapter_is_selected_for_its_kind(tmp_path: Path) -> None:
@@ -219,6 +219,43 @@ def test_unload_stops_claiming_a_model_that_is_gone(tmp_path: Path, monkeypatch)
assert "that model is gone" in row.reason, row.reason
def test_a_loaded_row_names_the_adapter_that_is_actually_attached(tmp_path: Path, monkeypatch) -> None:
settings = _settings(tmp_path)
attached = _write_adapter(settings.adapters_dir / "x", adapter_id="adapter-x")
monkeypatch.setattr(adapters, "load_into_model", lambda model, path: _FakeModel())
monkeypatch.setattr(QwenRuntime, "_load_base_model", lambda self: (_FakeModel(), object()))
runtime = QwenRuntime(settings)
runtime._load_transformers()
_write_adapter(settings.adapters_dir / "y", adapter_id="adapter-y")
row = next(item for item in adapters.plan(settings, Database(settings)).adapters if item.kind == CORE)
assert row.state == "loaded"
assert row.adapter_id == "adapter-x", f"the row promises {row.adapter_id} but {attached} is attached"
assert row.path == str(attached) and row.reason.endswith(str(attached)), row.reason
def test_one_unload_does_not_declare_another_live_model_gone(tmp_path: Path, monkeypatch) -> None:
settings = _settings(tmp_path)
_write_adapter(settings.adapters_dir / "x", adapter_id="adapter-x")
monkeypatch.setattr(adapters, "load_into_model", lambda model, path: _FakeModel())
monkeypatch.setattr(QwenRuntime, "_load_base_model", lambda self: (_FakeModel(), object()))
first = QwenRuntime(settings)
first._load_transformers()
_write_adapter(settings.adapters_dir / "y", adapter_id="adapter-y")
second = QwenRuntime(settings)
second._load_transformers()
database = Database(settings)
row = next(item for item in adapters.plan(settings, database).adapters if item.kind == CORE)
assert row.state == "loaded" and row.adapter_id == "adapter-y"
assert "another live model still holds adapter-x" in row.reason, row.reason
first.unload()
row = next(item for item in adapters.plan(settings, database).adapters if item.kind == CORE)
assert row.state == "loaded" and row.adapter_id == "adapter-y"
assert "gone" not in row.reason, row.reason
second.unload()
row = next(item for item in adapters.plan(settings, database).adapters if item.kind == CORE)
assert row.state == "available" and "that model is gone" in row.reason, row.reason
def test_a_rejected_candidate_does_not_claim_another_adapter_won(tmp_path: Path) -> None:
settings = _settings(tmp_path)
_write_adapter(settings.adapters_dir / "router", kind=TrainingAdapterKind.hme_router, base_model="Qwen/Qwen3.5-0.8B")