mirror of
https://github.com/affaan-m/ECC.git
synced 2026-10-26 18:35:05 +00:00
fix: reject lossy classifier tool-call indices
RED: 6 failures proved booleans and fractional indices could invent evidence. GREEN: 49 targeted tests; full skill-comply suites pass on Windows (88 passed, 5 platform skips) and Linux (93 passed). Parser coverage 100%; exact integer floats and numeric strings remain supported. Pi/catalog checks pass.
(cherry picked from commit 6dde588860)
This commit is contained in:
1 parent
7b7ec11b2a
commit
99b6a9bb8f
2 files changed
+9
-2
No files matched your search
@@ -85,6 +85,8 @@ def _parse_classification(text: str) -> dict[str, list[int]]:
|
||||
raise ClassifierParseError(
|
||||
f"classifier returned non-list JSON value: {type(value).__name__}"
|
||||
)
|
||||
if any(isinstance(i, bool) or (isinstance(i, float) and not i.is_integer()) for i in value):
|
||||
raise ValueError("tool call indices must be whole numbers, not booleans")
|
||||
return {k: [int(i) for i in v] for k, v in parsed.items()}
|
||||
except (json.JSONDecodeError, ValueError, TypeError, OverflowError) as e:
|
||||
raise ClassifierParseError(
|
||||
|
||||
@@ -28,7 +28,12 @@ class TestParseClassification:
|
||||
_parse_classification('{"a": [0], "other": "x"}')
|
||||
|
||||
def test_existing_index_coercion_is_preserved(self) -> None:
|
||||
assert _parse_classification('{"a": [true, 2.9, "3"]}') == {"a": [1, 2, 3]}
|
||||
assert _parse_classification('{"a": [0, 2.0, "3"]}') == {"a": [0, 2, 3]}
|
||||
|
||||
@pytest.mark.parametrize("index", [True, False, 2.9, -0.1])
|
||||
def test_boolean_and_fractional_indices_raise(self, index: object) -> None:
|
||||
with pytest.raises(classifier.ClassifierParseError, match="failed to parse"):
|
||||
_parse_classification(json.dumps({"a": [index]}))
|
||||
|
||||
def test_empty_object_is_valid(self) -> None:
|
||||
assert _parse_classification("{}") == {}
|
||||
@@ -54,7 +59,7 @@ class TestParseClassification:
|
||||
assert issubclass(classifier.ClassifierParseError, RuntimeError)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("response", ["not JSON", "[]", '{"a": ["x"]}', '{"a": "x"}', '{"a": [0], "other": null}', '{"a": [1e309]}', '{"a": [-1e309]}'])
|
||||
@pytest.mark.parametrize("response", ["not JSON", "[]", '{"a": ["x"]}', '{"a": "x"}', '{"a": [0], "other": null}', '{"a": [1e309]}', '{"a": [-1e309]}', '{"a": [false]}', '{"a": [0.5]}'])
|
||||
def test_grader_propagates_classifier_parse_failure(response: str) -> None:
|
||||
"""An invalid successful subprocess response cannot become a zero score."""
|
||||
spec = ComplianceSpec(
|
||||
|
||||
Reference in new issue
Block a user