From cc038e63265d7c517ecf950ff54e2473ad5eb99f Mon Sep 17 00:00:00 2001 From: Logan Cusano Date: Sun, 23 Aug 2026 23:16:48 -0400 Subject: [PATCH] A unit call-sign is not a place MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "Post 1-2" reached the geocoder, resolved against its talkgroup anchor and produced a confident pin in the right town for an event with no known location — while sitting in the same incident's `units` list the whole time. A plausible wrong pin is worse than no pin: nothing downstream can tell it is wrong. Extraction returns `location` and `units` from one pass, so a string in both is a misclassification, not two facts. Drop it before the geocoder sees it. Closes server-26#52. Co-Authored-By: Claude Opus 5 --- .../app/internal/incident_correlator.py | 21 ++++++++++++ drb-c2-core/app/internal/intelligence.py | 14 +++++++- drb-c2-core/tests/test_incident_identity.py | 34 ++++++++++++++++++- 3 files changed, 67 insertions(+), 2 deletions(-) diff --git a/drb-c2-core/app/internal/incident_correlator.py b/drb-c2-core/app/internal/incident_correlator.py index 2654c1e..c8c779d 100644 --- a/drb-c2-core/app/internal/incident_correlator.py +++ b/drb-c2-core/app/internal/incident_correlator.py @@ -282,6 +282,27 @@ def clean_location(value) -> Optional[str]: return s +def location_is_unit(location, units) -> bool: + """ + True when a location label is really one of the incident's own unit + call-signs. + + Extraction returns `location` and `units` from the same pass, so a string + appearing in both is a misclassification, not two facts. "Post 1-2" reached + the geocoder that way, resolved against its talkgroup anchor, and produced a + confident pin in the right town for an event that has no known location at + all — worse than no pin, because nothing downstream can tell it is wrong. + See server-26#52. + + Public because `intelligence.py` applies it at extraction time, alongside + `clean_location`, so the string never reaches the geocoder. + """ + key = _place_key(location) + if not key: + return False + return any(key == _place_key(u) for u in (units or [])) + + def _place_key(value) -> str: """Case- and punctuation-blind key for comparing two location labels.""" return re.sub(r"[^a-z0-9]+", " ", str(value or "").lower()).strip() diff --git a/drb-c2-core/app/internal/intelligence.py b/drb-c2-core/app/internal/intelligence.py index 282c312..236dc63 100644 --- a/drb-c2-core/app/internal/intelligence.py +++ b/drb-c2-core/app/internal/intelligence.py @@ -19,7 +19,7 @@ from app.internal import area_context # Location validity is defined once, by the module that owns the incident's # location/pin invariant. incident_correlator does not import this module, so # this is not a cycle. -from app.internal.incident_correlator import clean_location +from app.internal.incident_correlator import clean_location, location_is_unit _PROMPT_TEMPLATE = """You are analyzing a P25 public safety radio recording. The audio was transcribed by Whisper through a digital radio vocoder, which introduces errors. Each numbered transmission is a separate PTT press from a different radio. @@ -252,6 +252,18 @@ async def extract_scenes( location: Optional[str] = clean_location(scene.get("location")) vehicles: list[str] = scene.get("vehicles") or [] units: list[str] = scene.get("units") or [] + # A "location" that is also one of this scene's own units is a unit + # call-sign, not a place. Both lists come from the same extraction pass, + # so the disagreement is free to detect and the string must be dropped + # before it reaches the geocoder — anchored place verification will + # otherwise resolve "Post 1-2" to a confident, plausible, wrong pin in + # the right town. See server-26#52. + if location and location_is_unit(location, units): + logger.info( + f"Intelligence: dropping location {location!r} — it is one of " + f"this scene's units, not a place" + ) + location = None cleared_units: list[str] = scene.get("cleared_units") or [] # Every call carries a severity — it is the signal the correlator uses to # decide whether a call is incident-worthy at all, so it must never be diff --git a/drb-c2-core/tests/test_incident_identity.py b/drb-c2-core/tests/test_incident_identity.py index 4213f39..38aa2fc 100644 --- a/drb-c2-core/tests/test_incident_identity.py +++ b/drb-c2-core/tests/test_incident_identity.py @@ -28,7 +28,7 @@ from unittest.mock import AsyncMock, patch from app.internal.incident_correlator import ( _build_context, _create_incident, _update_incident, - _resolve_location_pair, _verified_pin, clean_location, + _resolve_location_pair, _verified_pin, clean_location, location_is_unit, ) NOW = datetime(2026, 8, 20, 7, 25, 0, tzinfo=timezone.utc) @@ -340,3 +340,35 @@ async def test_a_legacy_incidents_title_is_not_claimed_by_the_next_call(): incident_type="police", severity="routine") assert "title" not in updates assert updates["location"] == "80 Grasslands Road" + + +# ── server-26#52: a unit call-sign must never become a map pin ──────────────── +# +# "Post 1-2" passed clean_location (it has a word in it), geocoded against the +# Ossining anchor and produced a confident pin in the right town for an event +# with no known location. It was in the same incident's `units` all along. + +@pytest.mark.parametrize("location,units", [ + ("Post 1-2", ["1-2", "Lincoln", "Post 1-2"]), # the dump's actual incident + ("post 1-2", ["Post 1-2"]), # case-blind + ("Post 1-2.", ["Post 1-2"]), # punctuation-blind + ("Engine 4", ["Engine 4", "Ladder 1"]), +]) +def test_location_matching_a_unit_is_rejected(location, units): + assert location_is_unit(location, units) is True + + +@pytest.mark.parametrize("location,units", [ + ("Water Street", ["1-2", "Post 1-2"]), # a real place, same incident + ("South High", []), # no units extracted + ("Riverdale Station", ["Lincoln"]), + ("", ["Post 1-2"]), # nothing to compare + (None, ["Post 1-2"]), +]) +def test_real_places_survive_the_unit_check(location, units): + assert location_is_unit(location, units) is False + + +def test_unit_check_does_not_match_on_substrings(): + """`1-2` is a unit; "1-2 Main Street" is an address that contains it.""" + assert location_is_unit("1-2 Main Street", ["1-2"]) is False