correlator: LLM tier reads the scene's transcript, not the whole call (server-26#102)
The last leg of the #80/#95 scene-context leak. llm_correlator._call_block read call_doc's whole-call transcript for every scene, so on a multi-scene call every scene's cheap-tier and tiebreaker decision was made against text that also contained the other scenes. - intelligence.py: each processed[] scene now carries its own "transcript" — transcript_corrected, else this scene's segments joined, else (single scene) the whole transcript. - _build_context / preview_correlation / correlate_call: take a `transcript` param; _build_context resolves ctx["scene_transcript"] from it, falling back to the call doc (sweep, single-scene, tests) — the fallback is kept here, unlike embedding/severity, because a scene always has real text. - upload.py: both scene loops pass scene["transcript"]. - llm_correlator._call_block: reads ctx["scene_transcript"] (call-doc fallback retained for test-built ctx). - recorrelation_sweep: passes the call doc's text explicitly. - +1 regression test. Full c2-core suite green (296 passed, sandboxed venv). NOT for merge until the running correlation measurement window closes and its dump is analysed — deploying a correlator change mid-window would mix old and new behaviour in the sample. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
b430cf32f2
commit
ef1e3d7f9d
@@ -304,6 +304,39 @@ async def test_a_scene_is_judged_on_its_own_embedding_and_severity():
|
||||
assert ctx["call_severity"] == "major"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_the_llm_tier_reads_the_scene_transcript_not_the_whole_call():
|
||||
"""
|
||||
server-26#102. intelligence.py writes only the primary scene's corrected
|
||||
text to calls/{id}. _call_block (the LLM correlation prompt) must reason
|
||||
over the SCENE being correlated, not a whole-call transcript that also
|
||||
contains the other scenes. _build_context threads the scene's text in;
|
||||
with no scene text it falls back to the call doc (sweep / single-scene).
|
||||
"""
|
||||
with patch("app.internal.incident_correlator.fstore") as mock_fstore:
|
||||
mock_fstore.doc_get = AsyncMock(return_value={
|
||||
"transcript": "scene one about a fire. scene two about a traffic stop.",
|
||||
})
|
||||
mock_fstore.collection_list = AsyncMock(return_value=[])
|
||||
scene = await _build_context(
|
||||
call_id="call-1", units=None, vehicles=None, cleared_units=None,
|
||||
location_coords=None, reference_time=NOW,
|
||||
system_id="sys-1", talkgroup_id=383, talkgroup_name=DISPATCH_TG,
|
||||
tags=[], incident_type="police", location=None,
|
||||
reassignment=False, create_if_new=True,
|
||||
transcript="scene two about a traffic stop.",
|
||||
)
|
||||
fallback = await _build_context(
|
||||
call_id="call-1", units=None, vehicles=None, cleared_units=None,
|
||||
location_coords=None, reference_time=NOW,
|
||||
system_id="sys-1", talkgroup_id=383, talkgroup_name=DISPATCH_TG,
|
||||
tags=[], incident_type="police", location=None,
|
||||
reassignment=False, create_if_new=True,
|
||||
)
|
||||
assert scene["scene_transcript"] == "scene two about a traffic stop."
|
||||
assert fallback["scene_transcript"] == "scene one about a fire. scene two about a traffic stop."
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_a_bare_number_never_becomes_an_incident_location_or_title():
|
||||
inc = await _create(tags=["flames"], location="49", coords=None,
|
||||
|
||||
Reference in New Issue
Block a user