From 0972cbc2fc507618e7755fd8dd774525adcedaac Mon Sep 17 00:00:00 2001 From: Burhan Abdullah <131237388+BurhanAbdullah@users.noreply.github.com> Date: Sun, 11 Oct 2026 12:38:56 +0530 Subject: [PATCH 1/2] fix: reject boolean and non-finite solution values --- poweragentbench/benchmark_utils.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/poweragentbench/benchmark_utils.py b/poweragentbench/benchmark_utils.py index bfefe10..abc67a0 100644 --- a/poweragentbench/benchmark_utils.py +++ b/poweragentbench/benchmark_utils.py @@ -119,11 +119,15 @@ def load_solution(path: Path) -> dict[str, float]: value = item.get("value") if not isinstance(action_id, str): raise ValueError("Each action entry must include a string 'id'.") - if not isinstance(value, (int, float)): + # bool subclasses int in Python, but JSON booleans are not numeric action values. + if isinstance(value, bool) or not isinstance(value, (int, float)): raise ValueError(f"Action '{action_id}' must include a numeric 'value'.") + numeric_value = float(value) + if not math.isfinite(numeric_value): + raise ValueError(f"Action '{action_id}' must include a finite numeric 'value'.") if action_id in values: raise ValueError(f"Duplicate action '{action_id}' in solution file.") - values[action_id] = float(value) + values[action_id] = numeric_value return values @@ -144,6 +148,11 @@ def validate_action_values( for action_id, value in action_values.items(): if action_id not in actionspace["action_index"]: raise ValueError(f"Unknown action '{action_id}'.") + if isinstance(value, bool) or not isinstance(value, (int, float)): + raise ValueError(f"Action '{action_id}' must be a numeric value.") + value = float(value) + if not math.isfinite(value): + raise ValueError(f"Action '{action_id}' must be a finite numeric value.") action = actionspace["action_index"][action_id] min_value = float(action["min_value"]) max_value = float(action["max_value"]) From abeb559e4f3191ad2e5675f85d956c8aa7483549 Mon Sep 17 00:00:00 2001 From: Burhan Abdullah <131237388+BurhanAbdullah@users.noreply.github.com> Date: Sun, 11 Oct 2026 12:38:59 +0530 Subject: [PATCH 2/2] test: cover boolean and non-finite action values --- tests/test_benchmark_utils_contract.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/test_benchmark_utils_contract.py b/tests/test_benchmark_utils_contract.py index 800a418..cf351ee 100644 --- a/tests/test_benchmark_utils_contract.py +++ b/tests/test_benchmark_utils_contract.py @@ -179,3 +179,29 @@ def test_solution_loader_rejects_non_numeric_values(tmp_path: Path) -> None: with pytest.raises(ValueError, match="numeric"): load_solution(path) + + + +def test_solution_loader_rejects_boolean_values(tmp_path: Path) -> None: + path = tmp_path / "boolean_value.json" + path.write_text(json.dumps({"actions": [{"id": "tap_T1_up", "value": True}]}), encoding="utf-8") + + with pytest.raises(ValueError, match="numeric"): + load_solution(path) + + +@pytest.mark.parametrize("value", [float("nan"), float("inf"), float("-inf")]) +def test_solution_loader_rejects_non_finite_values(tmp_path: Path, value: float) -> None: + path = tmp_path / "non_finite.json" + path.write_text(json.dumps({"actions": [{"id": "tap_T1_up", "value": value}]}), encoding="utf-8") + + with pytest.raises(ValueError, match="finite"): + load_solution(path) + + +@pytest.mark.parametrize("value", [True, float("nan"), float("inf"), float("-inf")]) +def test_validate_action_values_rejects_boolean_and_non_finite_values(value: float) -> None: + actionspace = load_actionspace(LEVEL1 / "actionspace.json") + + with pytest.raises(ValueError, match="numeric|finite"): + validate_action_values({"tap_T1_up": value}, actionspace)