From a3a26b8fc5888f2d1c89f2dad482dc7ca57b3a29 Mon Sep 17 00:00:00 2001 From: Shay Date: Sun, 7 Jun 2026 07:49:10 -0700 Subject: [PATCH] test(constraint): pin the three Pack-C review hazards as regression tests Per review: (H1) exactly-two-category binding already has its meaningful-fail twin; (H2) a weighted total whose unit does not match the coefficient unit refuses missing_weighted_total (never a cross-unit sum); (H3) answer-choice ties EXACTLY or refuses no_matching_option (never nearest). All three were already handled by construction; these pin them so they stay handled. --- tests/test_answer_choices.py | 7 +++++++ tests/test_constraint_reader.py | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/tests/test_answer_choices.py b/tests/test_answer_choices.py index 2be8c4ae..f974e6c4 100644 --- a/tests/test_answer_choices.py +++ b/tests/test_answer_choices.py @@ -68,6 +68,13 @@ def test_no_matching_option_refuses() -> None: assert isinstance(out, Refusal) and out.reason == "no_matching_option" +def test_exact_match_only_never_nearest() -> None: + # Hazard: a proven value with no exact option REFUSES — it never snaps to the nearest + # (10 or 12). Exact-or-refuse is the wrong=0 boundary for answer-choice tie-in. + out = verify_answer_choice(11, {"A": 10, "B": 12, "C": 13, "D": 14}, "B") + assert isinstance(out, Refusal) and out.reason == "no_matching_option" + + def test_ambiguous_duplicate_options_refuse() -> None: out = verify_answer_choice(4, {"A": 4, "B": 4}, None) assert isinstance(out, Refusal) and out.reason == "ambiguous_options" diff --git a/tests/test_constraint_reader.py b/tests/test_constraint_reader.py index 63b009e8..64fb8c05 100644 --- a/tests/test_constraint_reader.py +++ b/tests/test_constraint_reader.py @@ -76,6 +76,17 @@ def test_coefficient_unit_mismatch_refuses() -> None: assert isinstance(out, Refusal) and out.reason == "coefficient_unit_mismatch" +def test_weighted_total_in_wrong_unit_refuses() -> None: + # Hazard: the weighted total's unit must match the coefficient unit. Coefficients are in + # students; a total in DOLLARS matches no coefficient unit, so the weighted equation is + # never assembled -> missing_weighted_total. The reader never sums across units. + out = read_constraint_problem( + "A school rents 6 buses. Each large bus holds 50 students and each small bus holds " + "30 students. The buses cost 260 dollars in total. How many large buses are there?" + ) + assert isinstance(out, Refusal) and out.reason == "missing_weighted_total" + + def test_off_category_query_refuses() -> None: out = read_constraint_problem( "A school rents 6 buses for a trip. Each large bus holds 50 students and each small bus "