From f689c916bfe0dcba6bb57de0674ea0aa5802c045 Mon Sep 17 00:00:00 2001 From: Miguel Palhas Date: Mon, 24 Aug 2026 22:50:02 +0100 Subject: [PATCH] fix(maestro): poll awaiting-input until leaderless state holds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pipeline leader exits as soon as both stages are forked, which can beat the surviving stage opening the tty and parking on read — the one- shot assertion then ran against a group with no parked member yet. Poll for the answer, accepting it only while the foreground group is still leaderless so a shell that regained the tty cannot satisfy it. Fixes #113 --- crates/maestro-daemon/tests/activity.rs | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/crates/maestro-daemon/tests/activity.rs b/crates/maestro-daemon/tests/activity.rs index d7fe201..a3b6348 100644 --- a/crates/maestro-daemon/tests/activity.rs +++ b/crates/maestro-daemon/tests/activity.rs @@ -189,8 +189,23 @@ fn a_foreground_pipeline_whose_leader_exited_is_still_awaiting_input() { "never observed a foreground group whose leader had exited" ); - assert!( - awaiting_input(pane.pane_pid, &pane.tty, &ProcGroups::snapshot()), - "a surviving pipeline member still holds the tty" - ); + // The leader can be gone while the surviving stage is still setting up: + // `true` exits as soon as both stages are forked, before the reader has + // opened the tty and parked. Poll for the answer, but only accept it + // while the state this test exists for still holds — otherwise a shell + // that regained the terminal would satisfy it vacuously. + let deadline = std::time::Instant::now() + Duration::from_secs(5); + let mut holds = false; + while std::time::Instant::now() < deadline { + let groups = ProcGroups::snapshot(); + let still_leaderless = pgrp_and_tpgid(pane.pane_pid).is_some_and(|(pgrp, tpgid)| { + tpgid > 0 && tpgid != pgrp && pgrp_and_tpgid(tpgid).is_none() + }); + if still_leaderless && awaiting_input(pane.pane_pid, &pane.tty, &groups) { + holds = true; + break; + } + std::thread::sleep(Duration::from_millis(20)); + } + assert!(holds, "a surviving pipeline member still holds the tty"); }