correlator: address #102 review — 0-based segment labels, never-empty slice

drb-correlation-review on the prior commit flagged two ways the per-scene
transcript could silently fall back to the whole-call text:

1. _build_transcript_block numbered transmissions "1." while the prompt says
   "0-based indices" — a model echoing the labels it saw returned 1-based
   indices, shifting every scene's slice by one. Labels are now "0." to match
   the documented contract (also fixes the same latent skew in
   _build_scene_embed_text / #80).
2. An empty join (bad / out-of-range / non-int indices) hit
   `transcript or call_doc.get(...)` in _build_context and fell back to the
   whole-call transcript — re-opening the leak exactly when indices are wrong.
   The slice now falls back to this call's own whole transcript *before*
   _build_context sees it, so it is never "". Non-int and negative indices
   are rejected rather than raising.

Slice logic extracted to `_scene_transcript_text` with a dedicated test file
(4 cases: subset, corrected-wins, no-indices fallback, bad-indices fallback).
Call-doc fallback kept (sweep / no-scene path) per the review. Also restored
the `-> ` spacing lost in the prior commit's kwarg edit.

Full c2-core suite green: 300 passed (sandboxed venv). Still DO NOT MERGE
until the measurement window closes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Logan Cusano
2026-09-07 00:12:56 -04:00
co-authored by Claude Sonnet 5
parent ef1e3d7f9d
commit 7189ba03e4
3 changed files with 84 additions and 15 deletions
+42 -13
View File
@@ -337,18 +337,9 @@ async def extract_scenes(
)
embedding = await asyncio.to_thread(_sync_embed, scene_text)
# This scene's own words, unprefixed — corrected text if we have it,
# else the raw segments this scene owns, else (single-scene) the whole
# transcript. The correlator's LLM tier reads this per scene instead of
# the call doc's whole-call transcript (server-26#102).
if transcript_corrected:
scene_transcript = transcript_corrected
elif segments and segment_indices:
scene_transcript = " ".join(
segments[i]["text"] for i in segment_indices if i < len(segments)
)
else:
scene_transcript = transcript
scene_transcript = _scene_transcript_text(
transcript, segments, segment_indices, transcript_corrected
)
processed.append({
"tags": tags,
@@ -585,11 +576,49 @@ def _municipality_from_tg(tg_name: Optional[str]) -> Optional[str]:
def _build_transcript_block(transcript: str, segments: Optional[list[dict]]) -> str:
"""Format transcript as numbered transmissions if segments are available."""
if segments and len(segments) > 1:
lines = [f"{i+1}. [{s['start']}s] {s['text']}" for i, s in enumerate(segments)]
# 0-based labels, matching the prompt's "0-based indices into the
# numbered transmissions" — the model echoes these back as
# `segment_indices`, which _build_scene_embed_text and the per-scene
# `transcript` (server-26#102) then slice with directly.
lines = [f"{i}. [{s['start']}s] {s['text']}" for i, s in enumerate(segments)]
return f"Transmissions ({len(segments)}):\n" + "\n".join(lines)
return f"Transcript:\n{transcript}"
def _scene_transcript_text(
transcript: str,
segments: Optional[list[dict]],
segment_indices: Optional[list[int]],
transcript_corrected: Optional[str],
) -> str:
"""
This scene's own words, unprefixed — the segments it owns, joined.
server-26#102: the correlator's LLM tier reads this per scene instead of
the call doc's whole-call transcript, so on a multi-scene call scene N is
no longer judged against scenes 1..N-1's text.
Never returns "". Anything that would leave the slice empty — no
`segment_indices` (a single-segment call is never numbered by
`_build_transcript_block`), or indices that are out of range / not ints —
falls back to the whole-call transcript, which for a single-scene call is
the same text and for a mis-sliced multi-scene call is at least this
call's own words. `_sync_extract`'s prompt documents 0-based indices and
`_build_transcript_block` numbers to match, so no base normalisation here.
"""
if transcript_corrected:
return transcript_corrected
if segments and segment_indices:
joined = " ".join(
segments[i]["text"]
for i in segment_indices
if isinstance(i, int) and 0 <= i < len(segments)
)
if joined:
return joined
return transcript
def _build_scene_embed_text(
transcript: str,
segments: Optional[list[dict]],