From e3d5ce01f8aee6f59ba5b8f9a0f5fa7631f1a14a Mon Sep 17 00:00:00 2001 From: t Date: Tue, 13 Oct 2026 08:22:40 -0700 Subject: [PATCH] test(adapters): hold the sse-drop-once turn until the reconnect (#894) The V2 SSE-reconnect end-to-end test failed on every Windows main run since the OpenCode V2 merge (assert 1 >= 2 streams). A gap now probes over HTTP every tick, and the fake finished the turn ~0.15 s after the prompt, so on a runner whose reconnect is slower than a probe tick the probe completed the session before the second stream opened. The fake's sse-drop-once scenario now ends the turn only once the reconnect is up, and the test slows the reconnect to 0.5 s so Linux exercises the losing timing too. Ablation: drop the fake's wait -> assert 1 >= 2. --- CHANGELOG.md | 3 +++ tests/test_opencode_http.py | 20 +++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4025140c..a0499a29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,6 +57,9 @@ breaking changes may land in a minor release. ### Fixed +- Fix the OpenCode V2 SSE-reconnect end-to-end test failing on slow runners (Windows): the + gap's HTTP probe completed the session before the reader reconnected. The fake now + holds the turn busy until the reconnect is up. - Resolve a codex session's rollout by session id when the hook's transcript path is missing or unreadable, so its usage is captured and the token budget guard arms (#775). diff --git a/tests/test_opencode_http.py b/tests/test_opencode_http.py index 3b0152d1..6f743ede 100644 --- a/tests/test_opencode_http.py +++ b/tests/test_opencode_http.py @@ -100,7 +100,9 @@ # html-health the health route answers 200 text/html (the web-UI # shell a server of another major serves for its routes) # sse-drop-once completed, but the FIRST event stream closes right after -# server.connected — the turn end arrives on the reconnect +# server.connected, and the turn ends only once the reconnect +# is up (until then an HTTP probe reads busy) — the turn end +# arrives on the reconnect however slowly the client reconnects # provider-outage (V2) the turn never finishes: the provider is down, so the # stream carries `session.retry.scheduled` frames (the shape # captured live from 2.0.27 on a closed port) and nothing else @@ -286,6 +288,13 @@ def run_turn(): # let the 204 flush before any scripted death tears the connection down time.sleep(0.15) push_turn_start() + if SCENARIO == "sse-drop-once": + deadline = time.time() + 10 # a reader that never reconnects fails the test + while time.time() < deadline: + with LOCK: + if STATE["streams"] >= 2: + break + time.sleep(0.02) if SCENARIO in ("completed", "sse-drop-once"): write_result(); write_spec(); finish_turn(); push_idle() elif SCENARIO == "nudge-then-complete": @@ -4466,10 +4475,15 @@ def test_v2_sse_reconnect(tmp_path): def test_v2_e2e_sse_reconnect_delivers_the_turn_end(tmp_path, v2_fake): """End to end: the first event stream breaks right after connecting; the - turn end queued meanwhile arrives on the reconnect and completes the - session.""" + turn end arrives on the reconnect and completes the session. + + The reconnect is slowed past the gap's per-tick probe cadence, the timing a + slow runner hits anyway: the fake holds the turn busy until the reconnect, + so the probe cannot complete the session over HTTP first. + Ablation: drop the fake's wait for the second stream -> one stream.""" launcher, rec = v2_fake adapter = make_adapter(tmp_path, binary=str(launcher)) + adapter.reconnect_sleep_s = 0.5 result = adapter.run(make_spec(tmp_path, rec, "sse-drop-once"))