correlator: drop the dispatch/tactical name-guess from the escape hatch (#115) #133

Merged
logan merged 1 commits from fix/115-drop-dispatch-tactical-split into main 2026-09-13 14:07:36 -04:00
Owner

Owner correction (2026-09-13, direct scanning experience): the "dispatch vs tactical" split I added in #126's escape hatch was a bad premise. _is_dispatch_channel is a string match on the talkgroup's configured name (dispatch/disp/patched/primary), not a detector of real channel behavior. A channel literally named "tac"/"tactical" only carries materially different traffic during a real incident, and that's rare — the overwhelming majority of traffic on any monitored channel, including high-risk stops and pursuits, stays on the main channel regardless of what it's named. A busy single-channel department not literally named "dispatch" would silently get the more permissive 15-minute window under the old logic and could reproduce #115's original bug (the gate never firing on the channel it targets).

Checked against all 3 correlation dumps before making this change: in the currently-monitored system, the low-named channels (Muni, RFK Bridge Patrols, NYSP Troop NYC) do happen to have low call counts too — so the old split wasn't obviously broken for this exact deployment — but that's the name coincidentally tracking volume here, not the classifier detecting anything. Any new single-channel department added without "dispatch" in its name would have been silently mis-bucketed.

Fix: _recent_incident_on_same_talkgroup always uses tg_dispatch_thin_idle_minutes (5 min), full stop. Removed the _is_dispatch_channel branch and its import. Tests updated: the old "tactical channel escapes into the 15-min window" test now asserts the opposite (gates identically to a dispatch-named channel at the same age).

Not touched, flagged for its own review: incident_correlator.py's own fast/thin path uses the same _is_dispatch_channel dichotomy for actual link-decision purposes (which candidate incidents are eligible, not just this gate's escape hatch) — same bad premise, bigger blast radius since it changes what gets linked, not just what gets gated. Filing separately rather than changing correlation decisions under a fix scoped to #115's gate.

Sandboxed pytest: 380 → 380 (no net test count change — one test rewritten in place, not added/removed).

🤖 Generated with Claude Code

Owner correction (2026-09-13, direct scanning experience): the "dispatch vs tactical" split I added in #126's escape hatch was a bad premise. `_is_dispatch_channel` is a string match on the talkgroup's *configured name* (`dispatch`/`disp`/`patched`/`primary`), not a detector of real channel behavior. A channel literally named "tac"/"tactical" only carries materially different traffic during a real incident, and that's rare — the overwhelming majority of traffic on any monitored channel, including high-risk stops and pursuits, stays on the main channel regardless of what it's named. A busy single-channel department not literally named "dispatch" would silently get the more permissive 15-minute window under the old logic and could reproduce #115's original bug (the gate never firing on the channel it targets). Checked against all 3 correlation dumps before making this change: in the currently-monitored system, the low-named channels (Muni, RFK Bridge Patrols, NYSP Troop NYC) do happen to have low call counts too — so the old split wasn't obviously broken *for this exact deployment* — but that's the name coincidentally tracking volume here, not the classifier detecting anything. Any new single-channel department added without "dispatch" in its name would have been silently mis-bucketed. Fix: `_recent_incident_on_same_talkgroup` always uses `tg_dispatch_thin_idle_minutes` (5 min), full stop. Removed the `_is_dispatch_channel` branch and its import. Tests updated: the old "tactical channel escapes into the 15-min window" test now asserts the opposite (gates identically to a dispatch-named channel at the same age). **Not touched, flagged for its own review:** `incident_correlator.py`'s own fast/thin path uses the same `_is_dispatch_channel` dichotomy for actual link-decision purposes (which candidate incidents are eligible, not just this gate's escape hatch) — same bad premise, bigger blast radius since it changes what gets linked, not just what gets gated. Filing separately rather than changing correlation decisions under a fix scoped to #115's gate. Sandboxed pytest: 380 → 380 (no net test count change — one test rewritten in place, not added/removed). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
logan added 1 commit 2026-09-13 14:07:28 -04:00
Owner correction from direct scanning experience: a talkgroup named tac/tactical only sees materially different traffic during a real incident, and that's rare -- the bulk of traffic on any monitored channel, including high-risk stops and pursuits, runs on the main channel regardless of what it's named. _is_dispatch_channel's string match on the talkgroup name is a naming-convention guess, not a detector of actual channel behavior; trusting it here meant a busy single-channel department not literally named 'dispatch' would silently get the more permissive 15-minute window and could reproduce #115's original bug (the gate never firing on the channels it targets).

Always use tg_dispatch_thin_idle_minutes (5 min) in the escape hatch, regardless of talkgroup name. Does NOT touch incident_correlator.py's own fast/thin idle-window selection, which uses the same dichotomy for a different, decision-changing purpose -- bigger blast radius, left for its own review.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01Tbknwttzou4s46PAykmtix
logan merged commit 4df801c5e0 into main 2026-09-13 14:07:36 -04:00
logan deleted branch fix/115-drop-dispatch-tactical-split 2026-09-13 14:07:37 -04:00
Sign in to join this conversation.