From 81688465a580d35d5f974f35b3a577e4ffc1eb4b Mon Sep 17 00:00:00 2001 From: Shay Date: Sat, 18 Jul 2026 21:57:36 -0700 Subject: [PATCH] =?UTF-8?q?test(reader-arc):=20Q3=20hazard-close=20?= =?UTF-8?q?=E2=80=94=20lock=20q:difference=20fail-closed=20(no=20guessed?= =?UTF-8?q?=20direction)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Discharges Josh's Q3 ruling: defer the q:difference capability, close the hazard now. _pattern_b_comparative_candidates is inert by construction (returns []), so 'how many more/fewer … than …' questions refuse end-to-end even when every statement injects cleanly. This suite LOCKS that so a future D.5 wiring cannot reopen the guessed-direction hole without positively determining the more/fewer direction. Verified inert-safe by 5 direct tests. --- .../test_adr_0250_q_difference_failclosed.py | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 tests/test_adr_0250_q_difference_failclosed.py diff --git a/tests/test_adr_0250_q_difference_failclosed.py b/tests/test_adr_0250_q_difference_failclosed.py new file mode 100644 index 00000000..86003201 --- /dev/null +++ b/tests/test_adr_0250_q_difference_failclosed.py @@ -0,0 +1,39 @@ +"""ADR-0250 increment 1 — Q3 hazard-close: q:difference is fail-closed. + +Josh's Q3 ruling deferred the q:difference *capability* (its cases strand on +multi-compound) but required the hazard be CLOSED now: the partial Pattern-B +"how many more/fewer" path must never emit a guessed-direction answer. The +direction bit ("more…than" → A−B vs "fewer…than" → B−A) is a wrong=0 driver +that must be positively determined; until it is, the question MUST refuse. + +`_pattern_b_comparative_candidates` is inert by construction (returns []), so +these questions refuse end-to-end. This suite LOCKS that so a future D.5 wiring +cannot silently reopen the hazard without the direction determination. The +critical cases are the ones where every STATEMENT injects cleanly — a guessed +answer would be most likely there, and matching gold by luck would be a +sealed-test wrong wearing a success costume. +""" +from __future__ import annotations + +import pytest + +from generate.math_candidate_graph import parse_and_solve + +# Each: statements parse cleanly; only the q:difference question is in play. +# Every one MUST refuse (answer is None) — never a signed-difference answer. +_Q_DIFFERENCE_PROBLEMS = [ + "Alice has 10 apples. Bob has 4 apples. How many more apples does Alice have than Bob?", + "Alice has 10 apples. Bob has 4 apples. How many fewer apples does Bob have than Alice?", + "Whitney bought 9 books and 7 magazines. How many more books than magazines did Whitney buy?", + "Tom made 12 cookies. Sam made 5 cookies. How many more cookies did Tom make than Sam?", + "Mary has a bag holding 20 pounds. She buys 4 pounds of beans. How many more pounds can Mary fit?", +] + + +@pytest.mark.parametrize("problem", _Q_DIFFERENCE_PROBLEMS) +def test_q_difference_refuses_no_guessed_direction(problem: str) -> None: + result = parse_and_solve(problem) + assert result.answer is None, ( + "q:difference must refuse (deferred capability, hazard closed): a " + f"guessed-direction answer {result.answer!r} is a wrong=0 hole. Problem: {problem!r}" + )