ece584b8f5
When a stream delivered text and then died on a context-overflow / payload-too-large error, the partial content (often tens of KB) was seeded as a length-continuation stub, growing the transcript monotonically. In a session whose transcript cannot be compressed back under budget (protect_last_n covers everything -> no_progress, or the summary would itself be larger -> would_grow), every later request is larger than the one that just failed — an unrecoverable loop where the user sees a 30+ minute fake hang and the only remedy is killing the session (#106260). classify_api_error already labels these errors context_overflow / payload_too_large (should_compress=True). _partial_stream_stub now returns an EMPTY stub marked _overflow_terminal for that class instead of seeding the recovered text, and recover_from_truncation treats the marker as terminal: the turn ends via the recovery contract with a clear message (start /new) and the transcript is not polluted with the partial. Normal partials (network stall, output-cap truncation, tool-call drops) are unchanged — only the overflow error class changes behavior. Tests: stub marker + empty content; a real streamed partial hitting a 'maximum context length' error returns the terminal stub; recover_from_ truncation ends the turn (no fragment/nudge appended) on the marker while a normal stub still runs the continuation path. 67 streaming/continuation regressions pass.