fix(plugins): clear _plugin_platform_names on force-rediscover

discover_and_load(force=True) cleared every per-plugin registry except
_plugin_platform_names, which register_platform() populates. A platform
plugin disabled between force-rediscovers left a stale name behind, so the
set diverged from the real platform_registry / _plugins state and never
shrank across repeated force passes.

Add the missing clear() and a regression test that seeds every per-plugin
registry, forces a rediscover, and asserts they all empty (so a future
registry addition can't silently leak across a force pass either).
This commit is contained in:
kshitijk4poor 2026-06-12 10:55:44 +05:30
parent 82d570165e
commit 889a13696b
2 changed files with 45 additions and 0 deletions

View file

@ -1129,6 +1129,7 @@ class PluginManager:
self._hooks.clear()
self._middleware.clear()
self._plugin_tool_names.clear()
self._plugin_platform_names.clear()
self._cli_commands.clear()
self._plugin_commands.clear()
self._plugin_skills.clear()

View file

@ -439,6 +439,50 @@ class TestPluginDiscovery:
assert "ep_plugin" in mgr._plugins
def test_force_rediscover_clears_all_plugin_registries(self, monkeypatch):
"""force=True must clear every plugin-populated registry.
Regression: ``_plugin_platform_names`` was populated by
``register_platform`` but omitted from the ``discover_and_load(force=True)``
clear block, so a platform plugin disabled between force-rediscovers
left a stale entry behind forever (the set diverged from the real
platform_registry / _plugins truth). This asserts the clear block
empties the full set of per-plugin registries so no future addition
silently leaks across a force pass either.
"""
mgr = PluginManager()
# Seed every registry that a plugin's register() can populate, then
# mark discovery done so force=True takes the clear path (we stub the
# inner sweep so the test doesn't depend on any on-disk plugins).
mgr._plugins["p"] = MagicMock()
mgr._hooks["pre_tool_call"] = [lambda **_: None]
mgr._middleware["llm_request"] = [lambda **_: None]
mgr._plugin_tool_names.add("some_tool")
mgr._plugin_platform_names.add("irc")
mgr._cli_commands["c"] = {"plugin": "p"}
mgr._plugin_commands["cmd"] = {"plugin": "p"}
mgr._plugin_skills["p:skill"] = {}
mgr._aux_tasks["task"] = {"plugin": "p"}
mgr._slack_action_handlers.append(("aid", lambda **_: None, "p"))
mgr._discovered = True
monkeypatch.setattr(PluginManager, "_discover_and_load_inner", lambda self_inner: None)
mgr.discover_and_load(force=True)
assert mgr._plugins == {}
assert mgr._hooks == {}
assert mgr._middleware == {}
assert mgr._plugin_tool_names == set()
assert mgr._plugin_platform_names == set(), (
"_plugin_platform_names was not cleared on force-rediscover"
)
assert mgr._cli_commands == {}
assert mgr._plugin_commands == {}
assert mgr._plugin_skills == {}
assert mgr._aux_tasks == {}
assert mgr._slack_action_handlers == []
# ── TestPluginLoading ──────────────────────────────────────────────────────