diff --git a/drb-c2-core/app/routers/upload.py b/drb-c2-core/app/routers/upload.py index 34f468c..7188881 100644 --- a/drb-c2-core/app/routers/upload.py +++ b/drb-c2-core/app/routers/upload.py @@ -141,6 +141,14 @@ def _call_is_substanceless(ctx: dict) -> bool: """ from app.internal import incident_correlator + # The incident-creation gate skips the has_event_substance check entirely + # when a type resolved (incident_correlator._run_decision ~:1397), so a + # typed call — fire/medical/etc. — opens an incident on substance we do not + # re-check here. reassignment=True is dispatch pulling a unit onto a NEW + # job (units are blanked at :296 for exactly that reason): the strongest + # new-incident signal in the pipeline. Either one means "keep the tiebreak". + if ctx.get("incident_type") or ctx.get("reassignment"): + return False if (ctx.get("call_severity") or "routine") in ("moderate", "major"): return False if incident_correlator.has_event_substance(ctx): diff --git a/drb-c2-core/tests/test_consensus_gate.py b/drb-c2-core/tests/test_consensus_gate.py index 36b6bb6..d3483a5 100644 --- a/drb-c2-core/tests/test_consensus_gate.py +++ b/drb-c2-core/tests/test_consensus_gate.py @@ -133,6 +133,25 @@ async def test_call_with_vehicles_is_not_gated(): m_tiebreak.assert_called_once() +async def test_call_with_resolved_incident_type_is_not_gated(): + # The creation gate skips has_event_substance when a type resolved, so a + # typed call (fire/medical/…) opens an incident on substance the gate does + # not re-check — it must keep the tiebreak, not be dropped. + m_apply, m_tiebreak = await _run_consensus( + _preview("new", {}, ctx={"incident_type": "fire"}), _llm("orphan"), + ) + m_tiebreak.assert_called_once() + + +async def test_reassignment_call_is_not_gated(): + # reassignment=True is dispatch pulling a unit onto a NEW job (units are + # blanked for exactly that reason) — the strongest new-incident signal. + m_apply, m_tiebreak = await _run_consensus( + _preview("new", {}, ctx={"reassignment": True}), _llm("orphan"), + ) + m_tiebreak.assert_called_once() + + async def test_recent_incident_on_same_talkgroup_is_not_gated(): ctx = { "system_id": "sys-1",