diff --git a/chat.el b/chat.el index 6254644..a307fb1 100644 --- a/chat.el +++ b/chat.el @@ -1057,17 +1057,43 @@ fn receipt_rule() -> String { // // Instruction (receipt_rule) reduces this; only a deterministic strip PREVENTS it. Both ship, // because a guard that depends on the model choosing to obey is the class of thing round 8 exists -// to stop shipping. Truncation at the marker is safe: the receipt is always terminal, and a model -// copying the format copies the leading blank line too. +// to stop shipping. +// +// EXCISE THE RECEIPT, DO NOT TRUNCATE AT IT — bought with a measured regression, 2026-08-05. +// The first version of this function assumed the receipt is always TERMINAL and cut everything +// from the marker onward. It is not always terminal: told about the format in its system prompt, +// the model sometimes LEADS with a receipt and then writes the answer underneath. Cutting at the +// marker then deleted the entire answer, and the turn came back {"error":"no response"}. +// Measured on a two-search cited prompt: round 7 answered 4/4; that version answered 2/7. The +// A/B is the only reason this was caught — it looked like a flaky model, and it was not. +// So: remove the [[...]] span and keep BOTH sides. An unterminated marker at position 0 is left +// alone entirely, because no rule about receipts is worth erasing an answer over. fn receipt_strip(s: String) -> String { - let p2: Int = str_index_of(s, "\n\n[[RECEIPT") - if p2 >= 0 { - return str_slice(s, 0, p2) + let out: String = s + // Bounded pass rather than a conditional exit: rebinding the counter inside an if-expression + // is the block-expression shape that miscompiles integer arithmetic under this elc + // (BUG-PLAINCHAT-1). Four straight passes is cheaper than being clever, and once no marker + // remains every further pass is a no-op. + let guard: Int = 0 + while guard < 4 { + let p: Int = str_index_of(out, "[[RECEIPT") + let found: Bool = p >= 0 + let rest: String = if found { str_slice(out, p, str_len(out)) } else { "" } + let e: Int = if found { str_index_of(rest, "]]") } else { 0 - 1 } + let head: String = if found { str_slice(out, 0, p) } else { "" } + let tail: String = if e >= 0 { str_slice(rest, e + 2, str_len(rest)) } else { "" } + let out = if !found { + out + } else { + if e >= 0 { + head + tail + } else { + if p == 0 { out } else { head } + } + } + let guard = guard + 1 } - let p1: Int = str_index_of(s, "[[RECEIPT") - if p1 < 0 { return s } - if p1 == 0 { return "" } - return str_slice(s, 0, p1) + return str_trim(out) } fn tool_receipt(tools_used: String, sources: String) -> String {