diff --git a/investigator-runtime/src/detectives/poirot.ts b/investigator-runtime/src/detectives/poirot.ts index 39edef1..36c53fc 100644 --- a/investigator-runtime/src/detectives/poirot.ts +++ b/investigator-runtime/src/detectives/poirot.ts @@ -244,6 +244,23 @@ export async function runPoirot(task: PoirotTask): Promise< return { skipped: true, reason: "incomplete_bilingual_analysis" }; } + // Soft-truncate before sending to the writer: the prompt asks ≤ 280 chars + // per language but the model occasionally goes slightly over (304 chars + // observed live with j-edgar-hoover PT-BR). Truncate at sentence boundary + // when possible, else at the cap. + const trimTo = (s: string, max: number): string => { + if (s.length <= max) return s; + const cut = s.slice(0, max); + const lastPeriod = Math.max(cut.lastIndexOf(". "), cut.lastIndexOf("; ")); + return (lastPeriod > max * 0.6 ? cut.slice(0, lastPeriod + 1) : cut).trim(); + }; + args.verdict = trimTo(args.verdict, 280); + args.verdict_pt_br = trimTo(args.verdict_pt_br, 280); + args.access_to_event = trimTo(args.access_to_event, 800); + args.access_to_event_pt_br = trimTo(args.access_to_event_pt_br, 800); + args.bias_notes = trimTo(args.bias_notes, 800); + args.bias_notes_pt_br = trimTo(args.bias_notes_pt_br, 800); + // Pass the shortlist's most-represented doc_id as a fallback for chunk_id // resolution in case the model emits a bare "c0042" without doc_id. const docCount = new Map();