fix(plugins): reject bool and -inf hook results in dynamic interval

get_update_interval() ran bool through float() (bool is an int subclass,
so True/False became 1.0/0.0) and only checked for +inf, not -inf. Both
cases landed on the MIN_DYNAMIC_UPDATE_INTERVAL floor by coincidence
instead of falling back to the static/manifest interval as invalid
input should.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Tst9cied2ri9bH4QRWa6H
This commit is contained in:
Claude
2026-09-11 02:18:00 +00:00
parent ee76c48765
commit ee0c017e53
2 changed files with 14 additions and 2 deletions
+7 -1
View File
@@ -8,6 +8,7 @@ API Version: 1.0.0
"""
import json
import math
import queue
import sys
import time
@@ -793,6 +794,11 @@ class PluginManager:
return None
if requested is None:
return None
if isinstance(requested, bool):
self.logger.debug(
"get_update_interval() returned a bool for %s, which is not a number",
plugin_id)
return None
try:
requested = float(requested)
except (TypeError, ValueError):
@@ -800,7 +806,7 @@ class PluginManager:
"get_update_interval() returned %r for %s, which is not a number",
requested, plugin_id)
return None
if requested != requested or requested == float('inf'): # NaN / inf
if not math.isfinite(requested): # NaN / +inf / -inf
return None
return max(requested, self.MIN_DYNAMIC_UPDATE_INTERVAL)
+7 -1
View File
@@ -98,10 +98,16 @@ class TestABrokenHookCannotStopUpdates:
def test_a_non_numeric_hook_falls_back(self, manager, junk):
assert manager._get_plugin_update_interval("sports", _Plugin(wants=junk)) == 60.0
@pytest.mark.parametrize("junk", [float("nan"), float("inf")])
@pytest.mark.parametrize("junk", [float("nan"), float("inf"), float("-inf")])
def test_nan_and_infinity_fall_back(self, manager, junk):
assert manager._get_plugin_update_interval("sports", _Plugin(wants=junk)) == 60.0
@pytest.mark.parametrize("junk", [True, False])
def test_a_bool_hook_falls_back(self, manager, junk):
"""bool is a subclass of int, so it must be rejected before float()
turns it into 0.0/1.0 and the floor silently swallows the mistake."""
assert manager._get_plugin_update_interval("sports", _Plugin(wants=junk)) == 60.0
class TestTheFloor:
"""A plugin asking for 0 would be re-entered on every tick of the render