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:
Logan Cusano
2026-09-07 00:06:37 -04:00
co-authored by Claude Sonnet 5
parent b430cf32f2
commit ef1e3d7f9d
6 changed files with 75 additions and 7 deletions
+4 -1
View File
@@ -116,6 +116,7 @@ async def _correlate_with_consensus(
reassignment: bool = False,
embedding: Optional[list] = None,
severity: Optional[str] = None,
transcript: Optional[str] = None,
) -> Optional[str]:
"""
Consensus correlator: runs the rules engine and the cheap LLM in sequence.
@@ -133,7 +134,7 @@ async def _correlate_with_consensus(
tags=tags, incident_type=incident_type, location=location,
location_coords=location_coords, units=units, vehicles=vehicles,
cleared_units=cleared_units, reassignment=reassignment,
embedding=embedding, severity=severity,
embedding=embedding, severity=severity, transcript=transcript,
)
ctx = preview["ctx"]
rules_decision = preview["decision"]
@@ -226,6 +227,7 @@ async def _run_extraction_pipeline(
reassignment=is_reassignment,
embedding=scene.get("embedding"),
severity=scene.get("severity"),
transcript=scene.get("transcript"),
)
if incident_id and incident_id not in incident_ids:
incident_ids.append(incident_id)
@@ -343,6 +345,7 @@ async def _run_intelligence_pipeline(
reassignment=is_reassignment,
embedding=scene.get("embedding"),
severity=scene.get("severity"),
transcript=scene.get("transcript"),
)
if incident_id and incident_id not in incident_ids:
incident_ids.append(incident_id)