correlator: give the LLM tier what it needs to link, stop it defaulting to "new" (server-26#115)
The 2026-09-07 measurement window (CORRELATION_REVIEW_0907.md) showed the consensus tiebreaker was the dominant over-split driver: it ran on 45% of calls and resolved link/orphan disagreements as "new" ~24/25 of the time, shattering one Mohegan Park car-alarm job into 9 incidents and opening ~7 incidents from radio checks / roll calls. Two causes, two fixes: 1. `_inc_summary` gave the model `id|type|loc|units|tags|idle` — no title, no talkgroup. It literally could not see that two "car alarms, Mohegan Park Ave/Avenue" incidents on TG 9560 were the same. Now includes the incident title (the strongest same-event signal) and talkgroup. 2. `_RULES` told the model "orphan when in doubt — conservative is always correct". For a system that over-splits, that is backwards: a wrong link is cheap, a duplicate incident is the failure. Rewritten to: prefer link for a plausible same-talkgroup continuation (low bar), reserve "new" for a genuinely different event, and explicitly "orphan" non-incidents (radio checks, roll call, 10-8/10-98, mileage logs). Plus `_extract_road_ids` now canonicalises street-type synonyms (Avenue→ave, Street→st, Road→rd, ...), so "Mohegan Park Avenue" and "Mohegan Park Ave" share a road id — that one difference was splitting the car-alarm incident. +tests/test_correlator_115.py. Full c2-core suite green (sandboxed venv). Bigger levers deferred to follow-ups: the consensus escalation itself (should a cheap-LLM "orphan" ever reach a tiebreak?), a first-class road-overlap fit signal in _call_fits_incident, geocode coverage. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
0712e7a437
commit
3a944f35c1
@@ -0,0 +1,54 @@
|
||||
"""
|
||||
server-26#115 — the tiebreaker manufactured incidents because it was blind to
|
||||
what would tell it two incidents are one.
|
||||
|
||||
Two low-risk supports for the reframed prompt:
|
||||
1. `_extract_road_ids` collapses street-type synonyms, so "Mohegan Park Ave"
|
||||
and "Mohegan Park Avenue" share a road id (they were splitting one
|
||||
car-alarm incident into two).
|
||||
2. `_inc_summary` now carries the incident title and talkgroup, the two
|
||||
signals the model needs to recognise a same-channel continuation.
|
||||
"""
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from app.internal.incident_correlator import (
|
||||
_extract_road_ids, _location_mentions_road_overlap,
|
||||
)
|
||||
from app.internal.llm_correlator import _inc_summary
|
||||
|
||||
NOW = datetime(2026, 9, 7, 8, 0, 0, tzinfo=timezone.utc)
|
||||
|
||||
|
||||
def test_avenue_and_ave_are_the_same_road_id():
|
||||
assert _extract_road_ids("Mohegan Park Avenue") == _extract_road_ids("Mohegan Park Ave")
|
||||
assert _extract_road_ids("191 Broadway Street") == _extract_road_ids("191 Broadway St")
|
||||
assert _extract_road_ids("North State Road") == _extract_road_ids("North State Rd")
|
||||
|
||||
|
||||
def test_road_overlap_matches_across_the_synonym():
|
||||
assert _location_mentions_road_overlap("multiple car alarms Mohegan Park Avenue",
|
||||
["patrol to Mohegan Park Ave"]) is True
|
||||
# still discriminates genuinely different streets
|
||||
assert _location_mentions_road_overlap("Oak Avenue", ["Elm Avenue"]) is False
|
||||
|
||||
|
||||
def test_inc_summary_carries_title_and_talkgroup():
|
||||
s = _inc_summary({
|
||||
"incident_id": "abc123",
|
||||
"type": "police",
|
||||
"talkgroup_ids": [9560],
|
||||
"title": "Nuisance Alarm at Mohegan Park Ave",
|
||||
"location": "Mohegan Park Ave",
|
||||
"units": ["Headquarters"],
|
||||
"tags": ["car-alarm"],
|
||||
"updated_at": NOW.isoformat(),
|
||||
}, NOW)
|
||||
assert "title:'Nuisance Alarm at Mohegan Park Ave'" in s
|
||||
assert "tg:[9560]" in s
|
||||
assert "id:abc123" in s
|
||||
|
||||
|
||||
def test_inc_summary_omits_missing_optional_fields():
|
||||
s = _inc_summary({"incident_id": "x", "updated_at": NOW.isoformat()}, NOW)
|
||||
assert "title:" not in s and "tg:" not in s and "loc:" not in s
|
||||
assert s.startswith("id:x")
|
||||
Reference in New Issue
Block a user