From 0862b47f76de5ca5c099120e1bdc26b30a6578d7 Mon Sep 17 00:00:00 2001 From: iris <2+iris@noreply.localhost> Date: Sun, 6 Sep 2026 22:43:01 -0400 Subject: [PATCH] Record the loose end the taskNote outage exposed, and the last of its checks A session whose transcript will not parse is skipped with only a log line, so from the phone it is indistinguishable from an idle unresponsive one. That is why the outage needed a report from Bryan rather than showing itself. The cause is fixed; the class is not, and it is the "design the unknown state first" rule rather than a bug in one code path. Also rustfmt on the parse path, which the fix landed unformatted. Co-Authored-By: Claude Opus 5 --- TODO.md | 18 ++++++++++++++++++ server/src/session/transcript.rs | 5 ++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/TODO.md b/TODO.md index 1f9dcde..41d0504 100644 --- a/TODO.md +++ b/TODO.md @@ -33,3 +33,21 @@ one in place when it turns out to need a decision. that would work today, for Claude sessions, and it is the option that was not chosen. + +## A session the server could not load + +- [ ] **A session whose transcript will not parse is skipped with nothing but a + log line, and from the phone it looks exactly like an idle unresponsive + one.** `SessionManager::new` catches a failing `launch` and logs + "couldn't relaunch session ", so the session has no pump and no + driver: no status, no history, nothing sendable. That is what the + `taskNote` incident (fd71d87) looked like from Bryan's phone, and why it + needed a report from him rather than being visible in the app. + `Event::Unreadable` removes the cause that time, but not the class — an + unreadable `process.json`, a provider edited away and an unreachable host + all reach the same place. + This is the "design the unknown state first" rule: a session the server + could not load is not a session with nothing to say, and only the phone + can show the difference. It needs a status the wire can carry for it — + the failure with its reason, reported on the session itself — rather than + the reader having to tell it apart from silence. diff --git a/server/src/session/transcript.rs b/server/src/session/transcript.rs index 02d357d..1357ef1 100644 --- a/server/src/session/transcript.rs +++ b/server/src/session/transcript.rs @@ -353,9 +353,8 @@ impl<'a> Indexed<'a> { #[serde(rename = "type")] kind: Option, } - let place: JustPlace = serde_json::from_str(line).with_context(|| { - format!("bad transcript line in {}", self.path.display()) - })?; + let place: JustPlace = serde_json::from_str(line) + .with_context(|| format!("bad transcript line in {}", self.path.display()))?; // Debug rather than a warning: a transcript written against a // newer build has one of these per line it wrote, and the row // on the phone is where this is actually reported.