"""Evidence review must stay usable on a regional run. evidence_geojson emitted one feature per false positive, one per false negative and *two* per match, with no limit. A regional QA run of 40k detections against 45k reference footprints produced well over a hundred thousand features in a single response, plus one warning string per unresolvable identifier. The endpoint the whole review workflow depends on therefore stopped working exactly where review matters most. The budget goes to what a reviewer must act on — misses and false positives — before confirmations, and the response says what it left out. """ from __future__ import annotations from app.services.quality_evidence_service import QualityEvidenceService def _features(role: str, count: int) -> list[dict]: return [{"properties": {"evidence_role": role}, "id": f"{role}-{index}"} for index in range(count)] def test_missing_identifiers_collapse_into_one_statement() -> None: warnings = QualityEvidenceService.summarize_missing( candidate_ids=["a", "b", "c"], reference_ids=["r1"], ) assert len(warnings) == 1 assert "3" in warnings[0] assert "1" in warnings[0] def test_nothing_missing_produces_no_warning() -> None: assert QualityEvidenceService.summarize_missing(candidate_ids=[], reference_ids=[]) == [] def test_the_plan_is_capped_before_any_geometry_is_fetched() -> None: """Resolving 130k geometries to draw 5k of them is work for nothing.""" findings = { "match_evidence": [{"candidate_feature_id": f"c{i}", "reference_feature_id": f"r{i}"} for i in range(100)], "false_positive_evidence": [{"candidate_feature_id": f"fp{i}"} for i in range(10)], "false_negative_evidence": [{"reference_feature_id": f"fn{i}"} for i in range(10)], } plan = QualityEvidenceService.plan_evidence(findings, limit=8) assert plan.truncated is True assert len(plan.items) == 8 # Both error classes are represented; confirmations do not get a share # while errors are still waiting. assert {item.role for item in plan.items} == {"false_negative", "false_positive"} # Only the identifiers that will actually be drawn need resolving. assert len(plan.candidate_ids) + len(plan.reference_ids) == 8 assert plan.candidate_ids <= {f"fp{i}" for i in range(10)} assert plan.reference_ids <= {f"fn{i}" for i in range(10)} def test_a_rare_error_class_is_never_crowded_out() -> None: """50.000 misses must not hide the three false positives.""" findings = { "false_negative_evidence": [{"reference_feature_id": f"fn{i}"} for i in range(5_000)], "false_positive_evidence": [{"candidate_feature_id": f"fp{i}"} for i in range(3)], } plan = QualityEvidenceService.plan_evidence(findings, limit=100) roles = [item.role for item in plan.items] assert roles.count("false_positive") >= 1 assert roles.count("false_negative") >= 90 assert len(plan.items) == 100 def test_the_plan_reports_the_complete_population_not_the_capped_one() -> None: findings = { "match_evidence": [{"candidate_feature_id": f"c{i}", "reference_feature_id": f"r{i}"} for i in range(100)], "false_negative_evidence": [{"reference_feature_id": "fn"}], } plan = QualityEvidenceService.plan_evidence(findings, limit=2) assert plan.total_feature_count == 201 assert plan.role_counts == {"match_candidate": 100, "match_reference": 100, "false_negative": 1} def test_an_uncapped_plan_keeps_everything() -> None: findings = {"false_negative_evidence": [{"reference_feature_id": f"fn{i}"} for i in range(30)]} plan = QualityEvidenceService.plan_evidence(findings, limit=0) assert plan.truncated is False assert len(plan.items) == 30 assert plan.reference_ids == {f"fn{i}" for i in range(30)} def test_evidence_without_identifiers_is_skipped_not_planned() -> None: findings = { "false_positive_evidence": [{"candidate_feature_id": None}, {"candidate_feature_id": "fp"}], "false_negative_evidence": [{}], } plan = QualityEvidenceService.plan_evidence(findings, limit=0) assert [item.role for item in plan.items] == ["false_positive"] assert plan.candidate_ids == {"fp"} def test_a_planned_match_keeps_its_candidate_and_reference_together() -> None: """Half a match is not reviewable evidence.""" findings = { "match_evidence": [ {"candidate_feature_id": "c1", "reference_feature_id": "r1"}, {"candidate_feature_id": "c2", "reference_feature_id": "r2"}, ] } plan = QualityEvidenceService.plan_evidence(findings, limit=3) assert plan.truncated is True # An odd budget drops the second pair rather than showing one side of it. assert len(plan.items) == 1 assert plan.candidate_ids == {"c1"} assert plan.reference_ids == {"r1"}