refactor: fail-loud unit grading and stricter orphan pair drop
Address review: replace bare KeyError with a contextual ValueError invariant check in _grade_unit (fail-loud, no catch/skip/fallback); tighten _drop_orphan_pairs to require exactly one original + one mirror with no extra illegal-role records (total==2); clarify InferenceResult docstring to unit-grained semantics. Add tests for missing-prediction descriptive error and extra-illegal-role pair drop.
This commit is contained in:
@@ -238,6 +238,45 @@ class TestUnitLevelAggregation:
|
||||
assert result.correct == 1
|
||||
assert any("orphan" in msg for msg in captured), "孤儿 pair 未告警(静默)"
|
||||
|
||||
def test_pair_with_extra_illegal_role_dropped(self) -> None:
|
||||
"""pair_id 下混入额外非法 role 记录(total>2)→ 整对剔除、不计入 total。"""
|
||||
questions = [
|
||||
_make_question("s1", answer="B"),
|
||||
_make_question("po", answer="B", pair_id="p", question_role="pair_original"),
|
||||
_make_question("pm", answer="A", pair_id="p", question_role="pair_mirror"),
|
||||
# 共享 pair_id 的额外非法记录(重复 original 角色)
|
||||
_make_question("px", answer="C", pair_id="p", question_role="pair_original"),
|
||||
]
|
||||
records = [
|
||||
_make_record("s1", prediction="B", answer="B"),
|
||||
_make_record("po", prediction="B", answer="B"),
|
||||
_make_record("pm", prediction="A", answer="A"),
|
||||
_make_record("px", prediction="C", answer="C"),
|
||||
]
|
||||
captured: list[str] = []
|
||||
sink_id = logger.add(captured.append, level="WARNING", format="{message}")
|
||||
try:
|
||||
result = _aggregate_results(records, questions, "run-illegal-role")
|
||||
finally:
|
||||
logger.remove(sink_id)
|
||||
|
||||
assert result.total == 1 # 仅 single 存活,非法配对整对剔除
|
||||
assert result.correct == 1
|
||||
assert any("total=3" in msg for msg in captured), "非法配对未告警(静默)"
|
||||
|
||||
def test_unit_missing_prediction_raises_descriptive_error(self) -> None:
|
||||
"""unit 缺 prediction → 描述性 ValueError(fail-loud,非静默、非裸 KeyError)。
|
||||
|
||||
故意破坏聚合不变量(questions 含 s2 但 records 无 s2),验证带上下文报错。
|
||||
"""
|
||||
questions = [
|
||||
_make_question("s1", answer="B"),
|
||||
_make_question("s2", answer="A"),
|
||||
]
|
||||
records = [_make_record("s1", prediction="B", answer="B")] # 缺 s2 的 record
|
||||
with pytest.raises(ValueError, match=r"缺 prediction.*聚合不变量被破坏"):
|
||||
_aggregate_results(records, questions, "run-broken-invariant")
|
||||
|
||||
def test_empty_records_returns_zero(self) -> None:
|
||||
"""空 records/questions → 零值结果。"""
|
||||
result = _aggregate_results([], [], "run-empty")
|
||||
|
||||
Reference in New Issue
Block a user