From 0448aaeac182292e4827534dcda81e716910160c Mon Sep 17 00:00:00 2001 From: Kayshen-X Date: Mon, 10 Aug 2026 08:55:16 +0800 Subject: [PATCH] test(ai): retry the stderr stress turn past a spawn ETXTBSY race Writing a stub and exec'ing it from sixteen threads at once lets one thread's still-open write fd ride another thread's fork() and hold the freshly-written stub open for write, so execve reports "Text file busy" and the turn surfaces a spawn error instead of the child's stderr. That is a parallel write-then-exec harness artifact, not the drain behaviour under test, and it flaked the stress case on the emulated aarch64 runner. turn_error now retries past the microsecond ETXTBSY window. --- .../src/chat_subprocess_exit_tests.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/crates/op-host-services/src/chat_subprocess_exit_tests.rs b/crates/op-host-services/src/chat_subprocess_exit_tests.rs index 2e961bddb..fbde282b1 100644 --- a/crates/op-host-services/src/chat_subprocess_exit_tests.rs +++ b/crates/op-host-services/src/chat_subprocess_exit_tests.rs @@ -68,7 +68,25 @@ fn stub_cli(body: &str) -> (std::path::PathBuf, std::path::PathBuf) { /// Run one generation turn against a stand-in and return the error text /// the user would see. +/// +/// Retries a spawn that races on `ETXTBSY`. Writing a stub and exec'ing +/// it from many threads at once means one thread's still-open write fd +/// can be inherited across another thread's `fork()` and briefly hold +/// the freshly-written stub open for write, so `execve` reports "Text +/// file busy". That is an artifact of the parallel write-then-exec +/// harness, not the stderr-drain behaviour under test, and the window is +/// microseconds — a retry clears it. fn turn_error(body: &str) -> String { + for _ in 0..16 { + let message = turn_error_once(body); + if !message.contains("Text file busy") && !message.contains("os error 26") { + return message; + } + } + turn_error_once(body) +} + +fn turn_error_once(body: &str) -> String { let (dir, binary) = stub_cli(body); let provider = SubprocessProvider::for_cli_generation(CliName::Antigravity) .expect("antigravity has a subprocess template")