intelligence: stop the police-channel default from typing content-free chatter (#138)
Build & Deploy / Build & push images (push) Successful in 4m8s
Build & Deploy / Deploy to VM (push) Failing after 1m12s
Build & Deploy / Report a failed deploy (push) Successful in 1s

EXTRACTION_PROMPT's incident_type rule always returned "police" for anything
on a police channel unless contradicted, so pure administrative chatter
(post check-ins, roll call, bare acknowledgements) got a truthy incident_type
and defeated the creation gate's "type" veto (_call_is_substanceless) ~82%
of the time (measured server-26#138/CORRELATION_REVIEW_0914.md, confirmed
against live 9-14 data: 9/9 type-veto examples checked all had severity
"routine" — same population the severity rubric already correctly
identifies as content-free, incident_type just wasn't using that signal).

Rule now checks for actual event content FIRST, on every channel, before
applying the channel-inference defaults; content-free traffic returns
"unknown" (already normalizes to None) instead of a channel default,
letting the existing gate correctly veto it. No correlator/gate code
touched — CORRELATION_REVIEW_0914.md's own recommendation was to fix this
in the prompt, not _call_is_substanceless, to avoid risking a real event
getting gated out.

Verified: 401 pass, 0 fail. Live effect to be confirmed against fresh
traffic (AI features just re-enabled this session after being off since
9/14) — tracking in SESSION_STATE.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Logan Cusano
2026-09-20 15:42:48 -04:00
co-authored by Claude Sonnet 5
parent fb0bb15c22
commit 3f69879437
+3 -6
View File
@@ -66,7 +66,7 @@ Rules:
- tags: describe WHAT happened, not WHERE. Specific, lowercase, hyphenated. Do not use location names, road names, talkgroup names, or place names as tags (wrong: "lower-macy's", "canvas-route-6", "route-202"; right: "suspect-search", "shoplifting", "vehicle-pursuit"). Do not repeat incident_type as a tag.
- units: ONLY identifiers that appear verbatim in the transcript. Use speaker role inference to distinguish units being dispatched from units acknowledging — both should be included. Never infer or guess unit IDs not present in the text. If a unit ID format is given below, use it to recognise a unit spoken in a shortened or partial form (e.g. just the phonetic name alone) as the same unit — but still only extract what is actually said, never fabricate the full form.
- Do not invent details not present in the transcript.
- incident_type: let the talkgroup channel be your primary signal. Use "fire" ONLY if the talkgroup is clearly a fire/rescue channel OR the transcript explicitly describes active fire, smoke, flames, or structure fire activation. Police or EMS referencing a fire scene → use "police" or "ems". When the channel is a police channel and nothing in the transcript contradicts it, return "police" — do NOT fall back to "other" merely because the transmission is administrative. Reserve "other" for traffic that genuinely belongs to no emergency service (rail operations, public works, utility coordination). Reserve "unknown" for transcripts too garbled to place at all.
- incident_type: FIRST decide whether this transmission has any incident behind it at all, using the same bar as the "routine" severity rule below — pure administrative/status traffic with nothing describable happening: post/unit check-ins, roll call, bare acknowledgements ("10-4", "copy", "received"), records/report exchanges, "show me admin"/"show me available", a status ten-code with no event attached. If it is administrative/status-only, return "unknown" — this applies on EVERY channel, including a police channel; do not let the channel default override it (server-26#138: forcing a channel default onto content-free chatter is what let radio housekeeping open incidents). Only once real event content is present, let the talkgroup channel be your primary signal for WHICH type. Use "fire" ONLY if the talkgroup is clearly a fire/rescue channel OR the transcript explicitly describes active fire, smoke, flames, or structure fire activation. Police or EMS referencing a fire scene → use "police" or "ems". When the channel is a police channel, a real event is present, and nothing in the transcript contradicts it, return "police". Reserve "other" for a real event that genuinely belongs to no emergency service (rail operations, public works, utility coordination) — not for administrative chatter, which is "unknown" per above regardless of channel. Also reserve "unknown" for transcripts too garbled to place at all.
- severity: ALWAYS return one of the four values. Judge the underlying event, not how dramatic the words sound.
"routine" — administrative/status traffic with no incident behind it: mileage and transport logging, radio checks, acknowledgements, shift changes, track block/power requests, records lookups.
"minor" — a real but low-stakes call: lift assist, parking complaint, past-tense larceny report, noise complaint, welfare check.
@@ -81,11 +81,8 @@ System: {system_id}
Talkgroup: {talkgroup_name}
{ten_codes_block}{vocabulary_block}{unit_format_block}{transcript_block}"""
# The incident_type enum offered to the model in EXTRACTION_PROMPT. Kept here
# rather than only in the prompt so a model that invents a value cannot write it
# into incident.type. "unknown" is deliberately absent — it is a real answer
# from the model but not a usable type, and is normalised to None alongside
# anything unrecognised.
# "unknown" is deliberately absent — normalises to None, which is what lets
# the creation gate veto a content-free call (server-26#138).
_VALID_INCIDENT_TYPES = frozenset({"fire", "ems", "police", "accident", "other"})
# Geographic bias radius for geocoding — half-width in degrees (~55 km)