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).
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)
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 main2026-09-13 14:07:36 -04:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
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_channelis 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_talkgroupalways usestg_dispatch_thin_idle_minutes(5 min), full stop. Removed the_is_dispatch_channelbranch 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_channeldichotomy 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