24add1db74
Compression could produce a transcript with ZERO user-role messages, which OpenAI-compatible backends (vLLM/Qwen) reject with a non-retryable `400 No user query found in messages`. This crashes `hermes kanban` workers unrecoverably: every resume replays the same poisoned history and fails on the very first request after a successful compaction. The existing #52160 guard pins the handoff summary to role="user" only when `last_head_role == "system"` — i.e. when the system prompt sits inside `messages` (the gateway `/compress` path). The main auto-compression path prepends the system prompt at request-build time, so the list handed to `compress()` starts with a user/assistant turn, `last_head_role` defaults to "user", and the summary is emitted as role="assistant". A kanban worker seeded with a single short `"work kanban task <id>"` prompt followed by nothing but assistant/tool turns therefore ends up user-less once that early turn is summarised. Generalise the guard: when no user-role message survives in the protected head or the preserved tail, force the summary to carry role="user" so the request always has at least one user turn. When a user does survive (e.g. in the tail), the guard does not fire, so alternation is preserved. Fixes #58753.