"""Phase W — the geometric field reader on forward-substitutable relations. Proves the field reads problem TEXT into an exact integer answer via conformal translators + projective read-back, and REFUSES (never guesses) outside its sealed metric grammar. wrong==0 is structural: every commit is an exact-integer read-back. """ from __future__ import annotations from evals.numeric_harness import assert_eval_close from generate.relational_field_reader import READER_LINEAGE, read_relational # --- commits: the field reads correctly ------------------------------------ def test_fact_then_more_than(): r = read_relational( "Tom has 3 marbles. Jane has 5 more marbles than Tom. " "How many marbles does Jane have?" ) assert not r.refused assert_eval_close(r.answer, 8) assert r.answer_unit == "marbles" assert r.reader_lineage == READER_LINEAGE def test_fewer_than(): r = read_relational( "Anna has 20 apples. Ben has 7 fewer apples than Anna. " "How many apples does Ben have?" ) assert not r.refused assert_eval_close(r.answer, 13) def test_chained_forward_substitution(): r = read_relational( "Tom has 4 coins. Jane has 6 more coins than Tom. " "Sara has 10 more coins than Jane. How many coins does Sara have?" ) assert not r.refused assert_eval_close(r.answer, 20) # 4 -> 10 -> 20 def test_part_whole_sum_query(): r = read_relational( "Tom has 3 marbles. Jane has 5 more marbles than Tom. " "How many marbles do Tom and Jane have?" ) assert not r.refused assert_eval_close(r.answer, 11) # 3 + 8 def test_large_value_within_ceiling_is_exact(): # x=12345 already collapses f32 (the n_o weight loses the ±1 past ~4096); # f64 + translator stays exact here. r = read_relational( "Tom has 12345 dollars. Jane has 5000 more dollars than Tom. " "How many dollars does Jane have?" ) assert not r.refused assert_eval_close(r.answer, 17345) def test_never_commits_a_drifted_answer(): """wrong==0 guard: at a scale where the translator sandwich loses f64 integer exactness, the field REFUSES (precision_drift) rather than commit a wrong int.""" r = read_relational( "Tom has 123456 dollars. Jane has 654321 more dollars than Tom. " "How many dollars does Jane have?" ) # Either it commits the EXACT answer, or it refuses — never a wrong integer. if r.refused: assert r.refusal_reason == "precision_drift" else: assert_eval_close(r.answer, 777777) # --- refusals: the field declines outside its sealed grammar ---------------- def test_refuses_multiplicative(): r = read_relational( "Tom has 3 marbles. Jane has twice as many marbles as Tom. " "How many marbles does Jane have?" ) assert r.refused assert r.refusal_reason == "fenced_multiplicative" def test_refuses_times_cue(): r = read_relational( "Tom has 3 marbles. Jane has 4 times as many marbles as Tom. " "How many marbles does Jane have?" ) assert r.refused assert r.refusal_reason == "fenced_multiplicative" def test_refuses_over_ceiling(): r = read_relational( "Tom has 9000000 marbles. How many marbles does Tom have?" ) assert r.refused assert r.refusal_reason == "over_ceiling" def test_refuses_forward_reference(): r = read_relational( "Jane has 5 more marbles than Tom. Tom has 3 marbles. " "How many marbles does Jane have?" ) assert r.refused assert r.refusal_reason == "non_forward_substitutable" def test_refuses_no_question(): r = read_relational("Tom has 3 marbles. Jane has 5 more marbles than Tom.") assert r.refused assert r.refusal_reason == "no_query" def test_refuses_negative_quantity(): r = read_relational( "Tom has 3 marbles. Jane has 5 fewer marbles than Tom. " "How many marbles does Jane have?" ) assert r.refused assert r.refusal_reason == "negative_quantity" def test_refuses_empty(): assert read_relational("").refused assert read_relational(" ").refusal_reason == "empty_input"