From fc9feb4d0870d004c0745c369016e32420e21d5a Mon Sep 17 00:00:00 2001 From: mosaic-coder Date: Sat, 25 Jul 2026 17:13:31 -0500 Subject: [PATCH] fix(lease-broker): recovery_runtime_unittest wait_ready() connect-probe (co-equal CI flake, cherry-pick #898) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit wait_ready() polled socket_path.exists() to decide the daemon was ready, but exists() only proves the path was bind()'d — not that the daemon has called listen() yet. Under CI load the gap between bind() and listen() widens enough that the first client connect() can land in the window and get ECONNREFUSED, flaking the suite. PR #898 fixed the identical TOCTOU race in recovery_b1_adversarial_unittest.py by replacing the existence check with a real socket.connect()-and-close probe (contextmanager, per-probe settimeout, retrying ConnectionRefusedError/FileNotFoundError). This applies the same proven form here, adapted to this file's own wait_ready: its existing 5.0s deadline, its daemon-exited-early check, and its exact "daemon did not create private broker socket" TimeoutError message are all preserved byte-for-byte. Zero assertion changes, zero daemon/source changes, zero gate-timeout relaxation. Only wait_ready() in this file was touched; recovery_b1 and the p5/p6 probes are untouched (separate trailing PR). Closes #899 --- .../mosaic/src/lease-broker/recovery_runtime_unittest.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/mosaic/src/lease-broker/recovery_runtime_unittest.py b/packages/mosaic/src/lease-broker/recovery_runtime_unittest.py index 1b6d2b6d..cba46257 100644 --- a/packages/mosaic/src/lease-broker/recovery_runtime_unittest.py +++ b/packages/mosaic/src/lease-broker/recovery_runtime_unittest.py @@ -62,8 +62,13 @@ def request(socket_path: Path, value: dict[str, object]) -> dict[str, object]: def wait_ready(process: subprocess.Popen[str], socket_path: Path) -> None: deadline = time.monotonic() + 5.0 while time.monotonic() < deadline: - if socket_path.exists(): + try: + with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as probe: + probe.settimeout(0.25) + probe.connect(str(socket_path)) return + except (ConnectionRefusedError, FileNotFoundError): + pass if process.poll() is not None: output = process.stdout.read() if process.stdout is not None else "" raise RuntimeError(f"daemon exited before READY: {output}")