from __future__ import annotations from app.fact_coverage import ( classify_fact_requirements, hard_fact_is_preserved, missing_hard_facts, missing_semantic_fact_ids, semantic_coverage_is_low, ) def _facts(description: str) -> list[dict[str, str]]: return [{"id": "entry_description", "source": "user_form", "field": "description", "text": description}] def test_fact_requirements_extract_atomic_objective_anchors() -> None: hard, coverage = classify_fact_requirements( _facts("This was an internal learning project.\nBuilt the import API with FastAPI for 300 users.") ) assert {(fact["kind"], fact["text"]) for fact in hard} == { ("quantity", "300 users"), ("named_term", "fastapi"), } assert [fact["id"] for fact in coverage] == [ "entry_description_part_1", "entry_description_part_2", ] def test_card_metadata_is_not_a_narrative_requirement() -> None: facts = _facts("Built the reporting API with Python.") facts.extend([ {"id": "entry_company", "field": "company", "text": "Example Co"}, {"id": "entry_position", "field": "position", "text": "Intern"}, ]) hard, coverage = classify_fact_requirements(facts) assert {fact["id"] for fact in coverage} == {"entry_description"} assert {fact["text"] for fact in hard} == {"python"} def test_repeated_named_terms_create_one_hard_anchor() -> None: hard, _coverage = classify_fact_requirements( _facts("Built a FastAPI service and documented the FastAPI deployment.") ) assert [(fact["kind"], fact["text"]) for fact in hard] == [("named_term", "fastapi")] def test_ordinary_uppercase_word_is_not_a_hard_anchor() -> None: hard, _coverage = classify_fact_requirements(_facts("Improved the API workflow for Client teams.")) assert hard == [] def test_quantity_requires_its_bound_object() -> None: fact = {"id": "fact_1", "text": "300 users", "kind": "quantity"} assert hard_fact_is_preserved(fact, "Supported 300 users.") assert not hard_fact_is_preserved(fact, "Processed 300 requests.") assert not hard_fact_is_preserved(fact, "Supported 200 users.") def test_literal_and_named_terms_are_checked_without_sentence_matching() -> None: ratio = {"id": "ratio", "text": "GPA: 4.3/5.0", "kind": "literal"} tool = {"id": "tool", "text": "fastapi", "kind": "named_term"} assert hard_fact_is_preserved(ratio, "GPA 4.3 / 5.0") assert not hard_fact_is_preserved(ratio, "GPA 4.0 / 5.0") assert hard_fact_is_preserved(tool, "Built the service with FastAPI.") assert not hard_fact_is_preserved(tool, "Built the service framework.") def test_responsibility_downgrade_is_a_hard_omission() -> None: fact = {"id": "responsibility", "text": "lead", "kind": "responsibility"} assert hard_fact_is_preserved(fact, "\u4e3b\u5bfc\u7528\u6237\u6743\u9650\u6a21\u5757\u5f00\u53d1") assert not hard_fact_is_preserved(fact, "\u53c2\u4e0e\u7528\u6237\u6743\u9650\u6a21\u5757\u5f00\u53d1") assert missing_hard_facts([fact], "\u53c2\u4e0e\u7528\u6237\u6743\u9650\u6a21\u5757\u5f00\u53d1") == ["lead"] def test_semantic_coverage_is_model_declared_and_thresholded() -> None: targets = [{"id": f"fact_{index}", "text": f"fact {index}"} for index in range(1, 5)] assert not semantic_coverage_is_low(targets, None) assert semantic_coverage_is_low(targets, ["fact_1", "fact_2"]) assert not semantic_coverage_is_low(targets, ["fact_1", "fact_2", "fact_3"]) assert missing_semantic_fact_ids(targets, ["fact_1", "fact_3"]) == ["fact_2", "fact_4"] def test_small_semantic_target_sets_never_trigger_repair() -> None: targets = [{"id": "fact_1", "text": "one"}, {"id": "fact_2", "text": "two"}] assert not semantic_coverage_is_low(targets, [])