fix(analyze): drop transcript timestamp headings from LLM prompt

render_prompt prefixed each recording with a '## <recorded_at>' heading.
No system prompt consumes that timestamp, and the LLM occasionally echoed
it into the final document as a heading. Join recordings with the bare
'\n\n---\n\n' separator instead; chronology is carried by recording order.

Adds a regression test pinning that no RFC3339 timestamp or '##' reaches
the prompt.

closes #8
This commit is contained in:
2026-05-30 14:42:48 +02:00
parent d34b2645ee
commit 4dc15c5450
+22 -7
View File
@@ -4,6 +4,13 @@ use super::AnalysisInput;
/// JSON input. Recordings with blank text are skipped — they carry no signal
/// for the LLM and only add noise. Chronological order is taken as given;
/// callers must sort `recordings` before passing in (the handler does).
///
/// Recordings are concatenated with a `\n\n---\n\n` separator and nothing
/// else: no per-recording heading or timestamp. The `recorded_at` value is
/// deliberately omitted — no system prompt consumes it, and feeding it as a
/// Markdown heading caused the LLM to occasionally echo transcript timestamps
/// into the final document (issue #8). Chronology is carried by the order of
/// `recordings` alone.
pub fn render_prompt(input: &AnalysisInput) -> String {
let mut out = String::new();
let mut first = true;
@@ -15,9 +22,6 @@ pub fn render_prompt(input: &AnalysisInput) -> String {
out.push_str("\n\n---\n\n");
}
first = false;
out.push_str("## ");
out.push_str(&r.recorded_at);
out.push_str("\n\n");
out.push_str(r.text.trim());
}
out
@@ -48,7 +52,7 @@ mod tests {
"2026-04-15T10:32:00Z",
"Patient klagt über Knie.",
)]));
assert_eq!(out, "## 2026-04-15T10:32:00Z\n\nPatient klagt über Knie.");
assert_eq!(out, "Patient klagt über Knie.");
}
#[test]
@@ -57,9 +61,20 @@ mod tests {
("2026-04-15T10:32:00Z", "Erste Aufnahme."),
("2026-04-15T10:38:15Z", "Zweite Aufnahme."),
]));
assert!(out.contains("\n\n---\n\n"));
assert!(out.starts_with("## 2026-04-15T10:32:00Z"));
assert!(out.contains("## 2026-04-15T10:38:15Z"));
assert_eq!(out, "Erste Aufnahme.\n\n---\n\nZweite Aufnahme.");
}
/// Regression guard for issue #8: transcript timestamps must never reach
/// the LLM prompt — they leaked into the final document as headings.
#[test]
fn omits_recording_timestamps() {
let out = render_prompt(&mk(vec![
("2026-04-15T10:32:00Z", "Erste Aufnahme."),
("2026-04-15T10:38:15Z", "Zweite Aufnahme."),
]));
assert!(!out.contains("2026-04-15T10:32:00Z"));
assert!(!out.contains("2026-04-15T10:38:15Z"));
assert!(!out.contains("##"));
}
#[test]