[Backend] Validate highlights' speaker and timestamp against real segments #346
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Severity: MEDIUM. Found in the August 2026 session lifecycle review (#319).
The defect
extract_highlightsdoes the hard half right — every quote is validated by normalised substring match against the transcript, so a hallucinated quote is dropped rather than published. But thespeakerandtimestamp_refstored on eachSessionHighlightrow are LLM-asserted strings that are never checked (reminder_tasks.py:2252-2261).So a quote can be genuine, verbatim, and attributed to the wrong player — and these are published to players on the Quote Board, which makes a misattribution both visible and socially awkward in a way a summary error is not.
Proposed fix
Once segment rows exist, validate both fields against them: the
timestamp_refmust match a real segment, and thespeakermust be that segment's resolved owner. On mismatch, correct the speaker from the segment (the segment is authoritative) rather than dropping an otherwise good quote, and log the correction rate as a model-quality signal.Acceptance criteria
timestamp_refis validated against a real segmentspeakeris taken from the segment, not from the modelVerified against the acceptance criteria before closing. All met.
anchor_highlights(audio_service.py:2654-2731) matches each quote against the real segment list by normalised substring, then takes both the timestamp and the speaker from the matched segment, overriding whatever the model claimed (true_speaker = chosen.get("speaker"), line 2716). Corrections are counted in aHighlightAnchoringrecord (speaker_corrected/timestamp_corrected/ambiguous/dropped) and logged (reminder_tasks.py:2332-2337).All three named test cases exist explicitly:
test_a_correct_quote_is_left_alone,test_a_real_quote_credited_to_the_wrong_player_is_corrected,test_an_invented_timestamp_is_replaced_by_the_real_one(tests/test_highlight_anchoring.py:49-84), plus an ambiguous-match case and a cross-speaker stitched quote being dropped.Wired into the live pipeline at
reminder_tasks.py:2299-2331againstall_segments— the same per-track ASR output persisted asTranscriptSegmentrows a few lines above, so the anchor and the rows cannot disagree.Closing. Part of a full acceptance-criteria pass across the v4.0.0 milestone.