From 436435bfc91d76bca552ebd936279e6414a2ff22 Mon Sep 17 00:00:00 2001 From: kshitijk4poor <82637225+kshitijk4poor@users.noreply.github.com> Date: Sat, 29 Aug 2026 10:40:11 +0530 Subject: [PATCH] test: pin fence/TTFP semantics for substantive-progress gating (#96667 salvage) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up for the salvaged substantive-progress fix, adapted to main's three-hook architecture: - Keep the dispatch tick and the completed-response shim tick (both deliberate on main; one-shot terminal events that cannot defeat an inactivity timeout) — update the two PR assertions accordingly. - Pin the end-to-end bug: keepalive/empty-role chunks must leave CompressionCommitFence stale, a substantive token must refresh it. - Pin the fast-lane telemetry contract (#96945/#96963): time_to_first_progress_ms records on the first frame of any kind via the split-out _notify_aux_timing_response helper. --- tests/agent/test_aux_progress_streaming.py | 60 +++++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/tests/agent/test_aux_progress_streaming.py b/tests/agent/test_aux_progress_streaming.py index 544cfe9c44..6e5e3f5524 100644 --- a/tests/agent/test_aux_progress_streaming.py +++ b/tests/agent/test_aux_progress_streaming.py @@ -143,7 +143,9 @@ class TestCreateWithProgress: assert result.choices[0].message.reasoning == "thinking..." assert result.choices[0].finish_reason == "stop" assert result.usage.total_tokens == 7 - assert ticks == [1, 1, 1] + # 1 dispatch tick (preserved for the watchdog's historical liveness + # signal — see _create_with_progress) + 1 per substantive chunk. + assert ticks == [1, 1, 1, 1] def test_completed_response_without_stream_payload_does_not_tick(self): calls = [] @@ -162,7 +164,11 @@ class TestCreateWithProgress: assert calls[0]["stream"] is True assert result is _COMPLETE - assert ticks == [] + # A completed response object carries the full summary payload, and + # the dispatch tick is the watchdog's historical liveness signal: + # both are one-shot terminal ticks, not per-frame keepalives, so + # neither can defeat an inactivity timeout. + assert ticks == [1, 1] def test_streaming_rejected_falls_back_to_plain_call(self): client = _FakeClient( @@ -423,6 +429,56 @@ class TestContentBearingProgress: assert touches == [1, 1] + def test_keepalive_chunks_do_not_reset_the_compression_fence(self): + """End-to-end bug pin (#96707): content-free frames must not refresh + CompressionCommitFence._last_progress. + + The waiter in conversation_compression charges its idle budget from + seconds_since_progress(); before the fix, every keepalive chunk fed + through _ChatStreamAccumulator ticked the fence, so a stalled + summary stream never hit the inactivity timeout.""" + fence = CompressionCommitFence() + accumulator = _ChatStreamAccumulator() + keepalive = SimpleNamespace(id=None, model=None, choices=[], usage=None) + empty_role_chunk = _chunk(content="", reasoning="") + + with aux_progress_hook(fence.touch_progress): + for _ in range(5): + accumulator.feed(keepalive) + accumulator.feed(empty_role_chunk) + # No substantive payload arrived: the fence must have stayed stale. + assert fence.seconds_since_progress() > 0.0 + + with aux_progress_hook(fence.touch_progress): + accumulator.feed(_chunk(content="token")) + assert fence.seconds_since_progress() < 0.05 + + def test_content_free_frames_still_record_ttfp_timing(self): + """The fast-lane telemetry contract (#96945/#96963) survives the + gating: time_to_first_progress_ms must record on the FIRST frame of + any kind (transport liveness), not only on the first token.""" + from agent.auxiliary_client import ( + _aux_provider_response, + _aux_timing_hook, + _notify_aux_timing_response, + ) + + timings: dict = {} + + def _timed_response() -> None: + timings.setdefault("time_to_first_progress_ms", 42) + + keepalive = SimpleNamespace(id=None, model=None, choices=[], usage=None) + accumulator = _ChatStreamAccumulator() + + with ( + _aux_timing_hook(_aux_provider_response, _timed_response), + aux_progress_hook(lambda: None), + ): + accumulator.feed(keepalive) + + assert timings["time_to_first_progress_ms"] == 42 + # --------------------------------------------------------------------------- # Ceiling arithmetic