test: update to evolved contracts (propose-from-exemplars corpora; pronoun guard)

- propose-from-exemplars: --all now proposes 6 exemplar corpora (the ME-1..ME-5
  matcher waves added currency_amount, discrete_count_statement,
  multiplicative_aggregation). All pending. Updated the pinned set + renamed
  the test off 'three_corpora'.

- adr_0163_d2 pronoun: the design moved from hard-refusing a bare pronoun
  subject at extraction to admitting it tagged requires_pronoun_resolution=True,
  with the candidate-graph (math_candidate_graph.py:704/723) refusing to commit
  unless it resolves. Verified end-to-end: 'He has 5 apples. How many...' still
  returns answer=None. Pin the defensive flag (its absence re-opens the ADR-0174
  wrong=0 hazard) instead of the obsolete None return.
This commit is contained in:
Shay 2026-06-03 02:02:58 -07:00
parent 6ea52f8af0
commit 1fe57643e1
2 changed files with 20 additions and 3 deletions

View file

@ -140,8 +140,18 @@ class TestExtractionRefusal:
def test_missing_counted_noun_refused(self) -> None:
assert _try_extract("Sam has 5.") is None
def test_pronoun_subject_refused(self) -> None:
assert _try_extract("He has 5 apples.") is None
def test_pronoun_subject_flagged_for_resolution(self) -> None:
# ADR-0174: a bare pronoun subject is no longer hard-refused at
# extraction. It is admitted but tagged requires_pronoun_resolution=True;
# the candidate-graph (generate/math_candidate_graph.py) then refuses to
# commit an answer unless the pronoun resolves, so serving still refuses
# bare pronoun subjects end-to-end ("He has 5 apples. How many ..." ->
# answer=None). The defensive flag — not a None return — is the
# extraction-level contract; its absence would re-open the ADR-0174
# wrong=0 hazard, so pin it here.
result = _try_extract("He has 5 apples.")
assert result is not None
assert result["requires_pronoun_resolution"] is True
def test_lowercase_subject_refused(self) -> None:
assert _try_extract("sam has 5 apples.") is None

View file

@ -132,7 +132,7 @@ def test_cli_single_corpus_produces_pending_proposal(tmp_path: Path) -> None:
assert rec["proposal"]["source"]["kind"] == "exemplar_corpus"
def test_cli_all_flag_proposes_three_corpora(tmp_path: Path) -> None:
def test_cli_all_flag_proposes_all_exemplar_corpora(tmp_path: Path) -> None:
log_path = tmp_path / "proposals.jsonl"
code, out, _ = _invoke_cli([
"teaching", "propose-from-exemplars",
@ -143,8 +143,15 @@ def test_cli_all_flag_proposes_three_corpora(tmp_path: Path) -> None:
assert code == 0
payload = json.loads(out)
cats = {p["shape_category"] for p in payload["proposals"]}
# --all proposes one pending proposal per exemplar corpus. The set grew
# from the original three as the ME-1..ME-5 matcher waves added
# currency_amount, discrete_count_statement, and multiplicative_aggregation
# exemplar corpora. Update this set when a new exemplar corpus is added.
assert cats == {
"currency_amount",
"descriptive_setup_no_quantity",
"discrete_count_statement",
"multiplicative_aggregation",
"rate_with_currency",
"temporal_aggregation",
}