diff --git a/tests/gateway/test_goal_continuation_drain.py b/tests/gateway/test_goal_continuation_drain.py index 58c111dde6467..662f541fc6266 100644 --- a/tests/gateway/test_goal_continuation_drain.py +++ b/tests/gateway/test_goal_continuation_drain.py @@ -120,7 +120,10 @@ async def test_fifo_enqueued_continuation_is_drained_without_new_user_message(): await adapter._process_message_background(event, key) # The in-band drain hands off to a fresh task (#17758); let it run. for _ in range(40): - if len(handled) >= 2: + # Wait for the SENDS, not just the handler calls: the delivery + # ledger hops to worker threads around each send, so the handler + # can return while reply-2's send is still in flight. + if len(adapter.sent) >= 2: break await asyncio.sleep(0.05) diff --git a/tests/gateway/test_session_split_brain_11016.py b/tests/gateway/test_session_split_brain_11016.py index 5a5439f4bd585..b6a850244edbb 100644 --- a/tests/gateway/test_session_split_brain_11016.py +++ b/tests/gateway/test_session_split_brain_11016.py @@ -198,9 +198,13 @@ class TestStaleSessionLockSelfHeal: # An ordinary message should heal the stale lock, then fall through # to normal dispatch. User gets a reply instead of a busy ack. await adapter.handle_message(_make_event("hello")) - # Drain any spawned background tasks. - for _ in range(5): - await asyncio.sleep(0) + # Drain any spawned background tasks. Real sleeps, not bare yields: + # the delivery ledger hops to worker threads around the send, so a + # zero-delay yield loop can finish before the reply lands. + for _ in range(40): + if any("handled:text" in r for r in adapter.sent_responses): + break + await asyncio.sleep(0.05) assert any("handled:text" in r for r in adapter.sent_responses), ( "stale lock trapped a normal message — split-brain not healed"