events: LiveEvent::Note becomes struct variant so serde can actually serialize it

This commit is contained in:
müde 2026-05-17 13:14:09 +02:00
parent aa24080f7b
commit b60774a66c
5 changed files with 46 additions and 29 deletions

View file

@ -105,7 +105,16 @@ pub enum LiveEvent {
/// Free-form note from the harness (e.g. "claude exited 0",
/// "stream-json parse error: ..."). Useful when stream-json itself
/// fails so the UI doesn't just go silent.
Note(String),
///
/// Must be a struct variant (not `Note(String)`): internally-tagged
/// enums can't flatten a tag onto a primitive newtype, and serde
/// fails serialization at runtime — silently, because the SSE
/// handler's `filter_map(... .ok()? ...)` swallows the error. From
/// 2025-08 through 2026-05 every `Note` emission was a no-op + the
/// sqlite history persisted them as the literal string `"null"`.
/// The web UI's `note` renderer already reads `ev.text`, so the
/// wire shape matches without a JS change.
Note { text: String },
/// Turn finished. `ok=false` means claude exited non-zero or the
/// harness hit a transport error.
TurnEnd { ok: bool, note: Option<String> },
@ -138,7 +147,7 @@ impl EventStore {
let kind = match event {
LiveEvent::TurnStart { .. } => "turn_start",
LiveEvent::Stream(_) => "stream",
LiveEvent::Note(_) => "note",
LiveEvent::Note { .. } => "note",
LiveEvent::TurnEnd { .. } => "turn_end",
};
let payload = serde_json::to_string(event).unwrap_or_else(|_| "null".into());