Let C2 name a talkgroup it already knows
84 of the 100 incidents in the 2026-08-23 dump were titled "Ems — TGID 9048"
or "Other — TGID 9600" -- the fallback, not a description. The title is the
incident's name everywhere it appears: list rows, map pins, Discord alerts.
_create_incident builds it from a content tag and a talkgroup label, and the
label was collapsing to "TGID {id}" because talkgroup_name arrived as None.
It is a plain form field on /upload, forwarded untouched into correlation, and
the node only sends it when OP25 had the name in its loaded tags file -- which
is exactly the case C2 can cover from its own systems collection, where all 125
talkgroup definitions live.
The lookup already existed, on the other path: mqtt_handler resolved it from
the system config on call_start. So the call document held the right name while
the pipeline that titles the incident ignored it. That asymmetry is the bug.
internal/talkgroups.py is now the one implementation -- caller's hint, then the
call document, then the system config -- and both paths use it.
_run_intelligence_pipeline resolves once at the funnel /upload and
/calls/{id}/reprocess share, so the dispatch-channel test, scene extraction and
the title all see a real name. When the call document was the thing missing it,
the resolved name is written back, so the archive and the orphan panel stop
showing a bare TGID too.
Also gives fast/thin a corr_fit_signal. It is 63% of all links and was the only
path writing none, so corr_fit_signal was absent on 295 of 309 calls and the
admin debug view's distribution panel read empty -- looking broken when it was
faithfully reporting that the dominant path records nothing. It now says
thin_recency, which is what actually decided it.
Closes server-26#34. Refs server-26#35 -- the tier's 3.5% invocation rate is a
cost/benefit question, not a bug, and stays open.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
a278e2215a
commit
039a06dc72
@@ -244,9 +244,27 @@ async def _run_intelligence_pipeline(
|
||||
3. Correlate each scene with existing incidents (or create new ones)
|
||||
4. Check alert rules and dispatch notifications
|
||||
"""
|
||||
from app.internal import transcription, intelligence, incident_correlator, alerter
|
||||
from app.internal import transcription, intelligence, incident_correlator, alerter, talkgroups
|
||||
from app.internal.feature_flags import get_flags
|
||||
|
||||
# The node only sends talkgroup_name when OP25 had it in the loaded tags
|
||||
# file, so it arrives empty for exactly the talkgroups C2 can name from the
|
||||
# system config. Resolve it once, here, at the single funnel both /upload
|
||||
# and /calls/{id}/reprocess pass through — everything downstream (the
|
||||
# dispatch-channel test, scene extraction, and the incident title) then
|
||||
# gets a real name instead of "TGID 9048". server-26#34.
|
||||
_call_doc = await fstore.doc_get("calls", call_id)
|
||||
talkgroup_name = await talkgroups.resolve(
|
||||
system_id, talkgroup_id, hint=talkgroup_name, call_doc=_call_doc,
|
||||
)
|
||||
# Backfill the call document too, so the archive and the orphan panel stop
|
||||
# showing a bare TGID for a channel we can now name.
|
||||
if talkgroup_name and _call_doc is not None and not _call_doc.get("talkgroup_name"):
|
||||
try:
|
||||
await fstore.doc_set("calls", call_id, {"talkgroup_name": talkgroup_name})
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not backfill talkgroup_name on call {call_id}: {e}")
|
||||
|
||||
flags = await get_flags()
|
||||
|
||||
# Resolve per-system overrides: system flag=False beats global flag=True,
|
||||
|
||||
Reference in New Issue
Block a user