From aa34d975a9546e8804dd9447691e4f9e48c74bcd Mon Sep 17 00:00:00 2001 From: Miguel Palhas Date: Fri, 4 Sep 2026 08:36:43 +0100 Subject: [PATCH] test(maestro): assert the agent session id survives recover() The test named for recovery only read the sidecar back; nothing covered the id reaching the recovered session, which is what a resume reads. Also narrows RESTART.md's leniency claim: the custom Deserialize lives in the client's own binary, so an older build still fails on Dormant. --- crates/maestro-daemon/tests/activity_report.rs | 18 ++++++++++++++++++ docs/RESTART.md | 9 ++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/crates/maestro-daemon/tests/activity_report.rs b/crates/maestro-daemon/tests/activity_report.rs index 0e272ab..d1af586 100644 --- a/crates/maestro-daemon/tests/activity_report.rs +++ b/crates/maestro-daemon/tests/activity_report.rs @@ -223,4 +223,22 @@ async fn a_reported_session_id_survives_recovery_from_the_sidecar() { .expect("sidecar read") .expect("sidecar present"); assert_eq!(stored.agent_session_id.as_deref(), Some("conv-abc123")); + + // The sidecar holding the id is only half the claim: a restarted daemon + // has to carry it back onto the recovered session, which is what a resume + // reads. Build a parallel manager over the same tmux server and state + // dirs and recover through it. + let revived = SessionManager::new( + Arc::new(fx._tmux.tmux.clone()), + fx.sidecar.clone(), + WorktreeManager::new(None), + fx._state_dir.path().join("fifos"), + ); + revived.recover().await.expect("recover"); + let recovered = observed(&revived, id).await; + assert_eq!( + recovered.agent_session_id.as_deref(), + Some("conv-abc123"), + "the recovered session must carry the agent session id, not just the sidecar" + ); } diff --git a/docs/RESTART.md b/docs/RESTART.md index 246bd1b..8296fd8 100644 --- a/docs/RESTART.md +++ b/docs/RESTART.md @@ -83,9 +83,12 @@ resized, and neither watcher pass touches it. It is a record of what was running, and the only thing left to do with one is dismiss it, which removes the sidecar so the next recovery does not bring it back. -`SessionStatus` is a wire type, so it deserializes leniently on both clients: -a spelling this build does not know reads as `Dead` rather than failing the -whole session. Clients render a dormant session as known-but-not-running — +`SessionStatus` is a wire type, so from this build forward it deserializes +leniently on both clients: a spelling the client does not know reads as `Dead` +rather than failing the whole session. That leniency lives in the client's own +binary, so it covers spellings added *after* this build, not this one — a CLI +or TUI still running an older build fails to parse a `Dormant` session, and +with it the whole session list, until it is upgraded. Clients render a dormant session as known-but-not-running — see `docs/SIDEBAR.md` for the card and `docs/COMMAND-BAR.md` for how it ranks. ## Timing