From 5ba7b26a954f30b060338bbe5ca51ce0b221265a Mon Sep 17 00:00:00 2001 From: JasonBuildAI Date: Sat, 10 Oct 2026 12:51:01 +0800 Subject: [PATCH] test(collaboration): qualify the Windows peer read lane in CI #5511 reported a Windows-only crash in the peer inbox read path: the input readiness probe used os.O_NONBLOCK, which does not exist on Windows. #5456 and 05e596dd8 landed the guarded flag form plus three Win32-marked regressions (long private store paths, binary CRLF/Ctrl-Z digests, long workspace inputs behind a junction), but the windows-powershell job lists explicit pytest files and omits tests/test_peer_collaboration.py, while the ubuntu shards skip those rows by marker. The rows have executed on no runner since they landed. Run exactly those three rows in the Windows job so the platform hazards they pin are exercised on the platform they exist for. The same report described a receipt written before the read completed. That ordering was real: 025be07e3 later committed inbox reads after response validation instead of before it, and nothing has held the result since. Pin it: a readiness probe that raises leaves `reads/` untouched, and the next completed read records it. Verified on native Windows: the three rows pass, and the new receipt test fails when record_read is moved ahead of readiness. Signed-off-by: JasonBuildAI --- .github/workflows/python-tests.yml | 7 +++++++ tests/test_peer_collaboration.py | 31 ++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml index a4c4f703ba..e3951701b1 100644 --- a/.github/workflows/python-tests.yml +++ b/.github/workflows/python-tests.yml @@ -700,6 +700,13 @@ jobs: - name: Check Windows collaboration lock sidecars run: python -m pytest -q --basetemp .t tests/test_collaboration_sidecar_scan.py + - name: Qualify native Windows peer reads and long-path inputs + run: >- + python -m pytest -q + tests/test_peer_collaboration.py::test_peer_exchange_survives_long_private_store_paths + tests/test_peer_collaboration.py::test_peer_binary_artifact_preserves_crlf_and_ctrl_z_digest + tests/test_peer_collaboration.py::test_peer_read_qualifies_long_workspace_input + - name: Validate local-state routing and interruption recovery on Windows run: >- python -m pytest -q diff --git a/tests/test_peer_collaboration.py b/tests/test_peer_collaboration.py index 7166276b45..8f2e1dff76 100644 --- a/tests/test_peer_collaboration.py +++ b/tests/test_peer_collaboration.py @@ -778,6 +778,37 @@ def test_peer_update_rejects_another_results_read_and_consumption_receipts(scena consumed.write_bytes((folder / "conclusion.consumed.json").read_bytes()) with pytest.raises(ValueError, match="receipt scope"): returns(root, "delivery", "builder") + + +def test_a_failed_input_readiness_leaves_no_read_receipt(scenario, monkeypatch): + """A read that did not complete is not a delivered read. + + #5511 reported that the Windows readiness crash left the request already + looking read in `reads/`. That ordering was real: 025be07e3 later committed + inbox reads after response validation instead of before it, and nothing has + held the new ordering since. A receipt is evidence of a completed read only, + so a raising readiness probe must leave `reads/` untouched and the next + completed read must record it. + """ + + from loopx.control_plane.collaboration import peers + from loopx.control_plane.collaboration.inbox import _root + + root, registry, _, _, _, _, request_id = scenario + receipt = _root(root) / "reads" / f"{request_id}.json" + + def _fail_readiness(*args, **kwargs): + raise AttributeError("module 'os' has no attribute 'O_NONBLOCK'") + + monkeypatch.setattr(peers, "_input_readiness_for_goal", _fail_readiness) + with pytest.raises(AttributeError, match="O_NONBLOCK"): + peers.read_inbox(root, registry, "delivery", "builder") + assert not receipt.exists() + + monkeypatch.undo() + assert peers.read_inbox(root, registry, "delivery", "builder")["items"] + assert receipt.is_file() + @pytest.mark.skipif(sys.platform != "win32", reason="Win32 extended path regression") def test_peer_exchange_survives_long_private_store_paths(scenario): root, registry, brief, *_ = scenario