From 2f8a39463d2f8981218c0a686a18b0a8d424697b Mon Sep 17 00:00:00 2001 From: Levi Neuwirth Date: Thu, 30 Jul 2026 18:50:18 -0400 Subject: [PATCH] test(process): give the in-drain pin a fixture that can actually fail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Found by bite-testing, not by review. With the in-drain seam reverted, the pin still passed both content assertions and failed only the consumed-plan check — meaning "LATE-MARKER is absent" was holding for a reason unrelated to the probe. `poll_one` sends SIGTERM to the whole group on leader exit, so the untrapped descendant died before its 0.5s sleep finished. The late marker never arrived on *either* path, which makes the absence assertion vacuous: it would have stayed green with the collapse fixed. The descendant now installs `trap '' TERM` behind `survivor_script`'s readiness gate, so it survives the group TERM and writes its marker at 0.5s — well inside the 2s drain timeout the real path would run to. Re-bitten: the reverted seam now fails on the LATE-MARKER assertion itself. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Lv428Fth9LRtffwJSsqH7T --- src/process.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/process.rs b/src/process.rs index 78d2e4b..219cce9 100644 --- a/src/process.rs +++ b/src/process.rs @@ -4799,8 +4799,24 @@ mod tests { // The descendant keeps fd1, so the readers stay open after the // leader exits. EARLY is written before the leader exits, so it // is in the pipe before the drain begins. + // + // **`trap '' TERM` is load-bearing, and its absence made the + // first draft of this pin vacuous.** `poll_one` TERMs the whole + // group on leader exit, so an untrapped descendant dies before + // its 0.5s sleep ends — the late marker then never arrives on + // *either* path, and "LATE-MARKER is absent" holds for a reason + // that has nothing to do with the probe. The bite caught it: + // with the seam reverted the pin still passed both content + // assertions and failed only the consumed-plan check. + // + // The readiness gate is `survivor_script`'s, for its reason: a + // slow scheduler can otherwise deliver the group TERM before + // the subshell's `trap` runs. + let ready = dir.path().join("ready"); let script = format!( - "echo EARLY; ( sleep 0.5; echo LATE-MARKER; sleep 5 ) & echo $! > {pid}", + "echo EARLY; ( trap '' TERM; : > {ready}; sleep 0.5; echo LATE-MARKER; sleep 5 ) & \ + echo $! > {pid}; while [ ! -e {ready} ]; do sleep 0.01; done", + ready = ready.display(), pid = pidfile.display(), ); sup.plan_in_drain_probe_failure(nix::errno::Errno::EPERM);