diff --git a/loopx/extensions/runtime.py b/loopx/extensions/runtime.py index 9c52db6413..c5b100a4d9 100644 --- a/loopx/extensions/runtime.py +++ b/loopx/extensions/runtime.py @@ -478,11 +478,10 @@ def extension_status( "enabled": bool(entry.get("enabled")), "active_revision": entry.get("active_revision"), "rollback_available": bool(entry.get("rollback_revision")), - # Readiness is the same predicate the catalog and dispatch use: - # a stale proof under an incompatible API is not "verified". - "doctor_verified": bool(entry.get("enabled")) - and _active_manifest_incompatibility(entry) is None - and _verified_entrypoint(entry) is not None, + # A proof must resolve the exact active revision before its + # compatibility is meaningful; older unrevisioned state stays + # visible but unverified. + "doctor_verified": _status_doctor_verified(entry), "revision_count": len(entry.get("revisions") or []), } for entry in visible @@ -669,6 +668,16 @@ def _active_manifest_incompatibility(entry: Mapping[str, Any]) -> str | None: ) +def _status_doctor_verified(entry: Mapping[str, Any]) -> bool: + """Require a revision-bound doctor proof before resolving compatibility.""" + + return ( + bool(entry.get("enabled")) + and _verified_entrypoint(entry) is not None + and _active_manifest_incompatibility(entry) is None + ) + + def extension_catalog_entries( extension_manifest_paths: Iterable[str | Path] = (), *, diff --git a/tests/test_local_state_migration.py b/tests/test_local_state_migration.py index fb5a7e2ce1..d098b8d0db 100644 --- a/tests/test_local_state_migration.py +++ b/tests/test_local_state_migration.py @@ -614,7 +614,12 @@ def test_extension_cli_keeps_legacy_machine_state_without_a_global_registry(tmp_ "schema_version": "loopx_extension_state_v0", "extensions": {"example": {"id": "example", "enabled": True}}, }) - assert _list_extensions(source.parents[1])[0]["id"] == "example" + listed = _list_extensions(source.parents[1])[0] + assert listed["id"] == "example" + assert listed["enabled"] is True + assert listed["active_revision"] is None + assert listed["revision_count"] == 0 + assert listed["doctor_verified"] is False assert _extension_cli(source.parents[1], "disable", "example", "--execute")["changed"] assert _read(source / "extensions" / "state.json")["extensions"]["example"]["enabled"] is False assert not target.exists()