From 10d066ffd8fc69fc2f81cf8b74ce6bbb68efbb35 Mon Sep 17 00:00:00 2001 From: ethernet Date: Thu, 24 Sep 2026 22:50:07 -0400 Subject: [PATCH] fix(pm): keep the manifest import per plugin; pin the version in the sit-out test enabled_member_dirs imported hermes_cli.plugins_manifest before its loop, so a PM closure with no plugins selected needed the application's utils module (tests/scripts/test_source_driver.py builds exactly that tree). The requires_hermes sit-out test relied on the host's version identity. A tagless CI checkout has no parseable version, which makes the gate permissive. --- pm/workspace.py | 5 +++-- tests/pm/test_plugin_survival_contract.py | 6 +++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/pm/workspace.py b/pm/workspace.py index e79f0c62f7..18316036e1 100644 --- a/pm/workspace.py +++ b/pm/workspace.py @@ -211,12 +211,13 @@ def enabled_member_dirs(*, proposed_home=None, enabled=None, disabled=None) -> l as an older release), the loader skips that plugin anyway, and the member rejoins as soon as the verdict flips. Enabling one is still refused at admission. """ - from hermes_cli.plugins_manifest import requires_hermes_error - selected = enabled_plugin_dirs(proposed_home=proposed_home, enabled=enabled, disabled=disabled, skip_invalid_secondary=proposed_home is None) members = [] for path in selected: + # Per plugin: with none selected, PM must not import the application's manifest module. + from hermes_cli.plugins_manifest import requires_hermes_error + declaration = read_python_declaration(path) if requires_hermes_error(declaration.manifest): continue diff --git a/tests/pm/test_plugin_survival_contract.py b/tests/pm/test_plugin_survival_contract.py index 8fdc691e0f..d2683c76d8 100644 --- a/tests/pm/test_plugin_survival_contract.py +++ b/tests/pm/test_plugin_survival_contract.py @@ -426,7 +426,7 @@ def test_update_sync_survives_unreadable_secondary_profile(admission_env): @pytest.mark.skipif(not _uv_available(), reason="uv not on PATH") -def test_plugin_our_version_rejects_sits_out_without_being_disabled(admission_env): +def test_plugin_our_version_rejects_sits_out_without_being_disabled(admission_env, monkeypatch): """requires_hermes is judged against our version identity, which can lag (an untagged source checkout reads as an older release). Such a plugin sits out: config untouched, boot's currency check neither raises nor loops, and it rejoins once the verdict flips.""" @@ -434,8 +434,12 @@ def test_plugin_our_version_rejects_sits_out_without_being_disabled(admission_en from pm.install import sync_venv, venv_is_current from pm.lock import Facts + import hermes_cli.plugins_manifest as plugins_manifest + tmp_path, home = admission_env core = tmp_path / "core" + # A tagless checkout (CI's) has no parseable version, which makes requires_hermes permissive. + monkeypatch.setattr(plugins_manifest, "running_hermes_version", lambda: "1.0.0") for name in ("fits", "needs-newer"): plugin = home / "plugins" / name plugin.mkdir(parents=True)