from workers.entity_resolution import ( EntityCandidate, ResolutionDecision, rank_resolution_candidates, resolve_entity_pair, ) def organization(entity_id: str, **overrides): values = { "entity_id": entity_id, "entity_type": "organization", "name": "Example Technology AB", "source_ref": f"source:{entity_id}", "registration_country": "SE", "registration_number": None, "website": None, "city": "Stockholm", } values.update(overrides) return EntityCandidate(**values) def person(entity_id: str, **overrides): values = { "entity_id": entity_id, "entity_type": "person", "name": "Anna Andersson", "source_ref": f"source:{entity_id}", "email": None, "organization_id": None, } values.update(overrides) return EntityCandidate(**values) def test_registration_number_is_a_strong_organization_identifier(): result = resolve_entity_pair( organization("left", registration_number="556123-4567"), organization("right", registration_number="5561234567"), ) assert result.decision is ResolutionDecision.EXACT_LINK assert result.score == 1.0 assert result.requires_human_review is False def test_conflicting_registration_numbers_fail_distinct_even_when_names_match(): result = resolve_entity_pair( organization("left", registration_number="5561234567"), organization("right", registration_number="5569999999"), ) assert result.decision is ResolutionDecision.DISTINCT assert result.score == 0.0 def test_same_person_email_is_exact_link(): result = resolve_entity_pair( person("left", email="Anna@example.com"), person("right", email=" anna@EXAMPLE.com "), ) assert result.decision is ResolutionDecision.EXACT_LINK assert result.requires_human_review is False def test_fuzzy_organization_similarity_never_auto_merges(): result = resolve_entity_pair( organization("left", name="Example Technology AB", website="example.se"), organization("right", name="Example Technologies AB", website="https://www.example.se"), ) assert result.score > 0.72 assert result.decision is ResolutionDecision.REVIEW assert result.requires_human_review is True def test_different_entity_types_are_distinct(): result = resolve_entity_pair( organization("org"), person("person"), ) assert result.decision is ResolutionDecision.DISTINCT def test_candidate_ranking_prefers_exact_then_review_and_is_stable(): query = organization("query", registration_number="5561234567", website="example.se") candidates = [ organization("weak", name="Completely Different Company", registration_country="NO", city="Oslo"), organization("review", name="Example Technologies AB", website="example.se"), organization("exact", registration_number="556123-4567"), ] ranked = rank_resolution_candidates(query, candidates) assert [result.right_id for result in ranked] == ["exact", "review", "weak"] assert ranked[0].decision is ResolutionDecision.EXACT_LINK assert ranked[1].decision is ResolutionDecision.REVIEW