From cd6c0889285bafe292a5b3b73026bb49e5418142 Mon Sep 17 00:00:00 2001 From: aniruddhaadak80 Date: Mon, 24 Aug 2026 00:58:25 +0530 Subject: [PATCH] test(compression): align no-op strike tests with structural backoff (#93022) Two suites still encoded the pre-#93093 contract that the three structural no-op branches (insufficient_messages, no_compressible_window, empty_post_handoff_window) increment _ineffective_compression_count: - tests/agent/test_compaction_anti_thrash.py:: TestMinimumMessagesBranch::test_too_few_messages_records_an_ineffective_pass - tests/run_agent/test_infinite_compaction_loop.py:: TestCompressNoOpRegistersIneffective::{test_no_op_increments_counter, test_two_no_ops_block_should_compress} Structural no-ops are transcript-shape facts, not evidence of an incompressible floor, so they now arm _structural_no_op_backoff_until and leave the strike counter untouched. Update the tests to pin the new contract (count unchanged, backoff armed via time.monotonic(), should_compress blocked while it holds) and rename accordingly. The outcome contract of test_two_no_ops_block_should_compress is preserved: repeated no-ops still block further automatic compression. --- tests/agent/test_compaction_anti_thrash.py | 20 +++++++++---- .../test_infinite_compaction_loop.py | 30 ++++++++++++------- 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/tests/agent/test_compaction_anti_thrash.py b/tests/agent/test_compaction_anti_thrash.py index 457f28a5c3..cce7f0bd83 100644 --- a/tests/agent/test_compaction_anti_thrash.py +++ b/tests/agent/test_compaction_anti_thrash.py @@ -30,6 +30,8 @@ Two subtleties this pins: and disables compaction on a healthy session. ``test_no_false_positive_under_tokenizer_skew``. """ +import time + import pytest from agent.context_compressor import ContextCompressor @@ -188,11 +190,13 @@ class TestFutilityGuard: class TestMinimumMessagesBranch: - def test_too_few_messages_records_an_ineffective_pass(self): - """Returning the transcript unchanged must move the anti-thrash state. + def test_too_few_messages_defers_via_structural_backoff(self): + """A structurally impossible compaction must not strike the breaker. - Otherwise should_compress() keeps saying True about a transcript that can - never shrink, and every turn re-enters a no-op compaction. + #93022 — too-few-messages is a transcript-shape fact, not evidence + of an incompressible floor: striking it punished unrelated later + failures. Instead the branch arms the structural no-op backoff so + retries are deferred without burning anti-thrash strikes. """ cc = _compressor(threshold_tokens=1) msgs = _messages(3, size=10) @@ -202,7 +206,13 @@ class TestMinimumMessagesBranch: assert len(out) == len(msgs), "nothing should have been compressed" assert cc._last_compression_made_progress is False - assert cc._ineffective_compression_count == before + 1 + assert cc._ineffective_compression_count == before, ( + "structural no-op must leave the strike counter untouched" + ) + assert cc._structural_no_op_backoff_until > time.monotonic(), ( + "structural no-op must arm the retry backoff" + ) + assert cc._compression_block_reason().startswith("structural_backoff") class TestRejectedCompactionStrike: diff --git a/tests/run_agent/test_infinite_compaction_loop.py b/tests/run_agent/test_infinite_compaction_loop.py index a7cfe798bf..79c6b734be 100644 --- a/tests/run_agent/test_infinite_compaction_loop.py +++ b/tests/run_agent/test_infinite_compaction_loop.py @@ -10,8 +10,9 @@ compressor to fire on every subsequent turn with no progress. The fix adds two safeguards: 1. _find_tail_cut_by_tokens: when the whole transcript fits in soft_ceiling, re-walk with the raw (non-inflated) budget to find a meaningful cut. -2. compress(): when compress_start >= compress_end, record the no-op as - an ineffective compression so should_compress() anti-thrashing fires. +2. compress(): when compress_start >= compress_end, defer retries via the + structural no-op backoff (#93022) so should_compress() anti-thrashing + fires without burning anti-thrash strikes on transcript-shape facts. """ from unittest.mock import patch, MagicMock @@ -56,15 +57,16 @@ def _build_session(n_turns: int, words_per_turn: int = 20) -> list: # --------------------------------------------------------------------------- class TestCompressNoOpRegistersIneffective: - """When compress_start >= compress_end, the fix records this as - an ineffective compression so the anti-thrashing guard fires. + """When compress_start >= compress_end, the fix defers further attempts + via the structural no-op backoff (#93022) so the anti-thrashing guard + fires. We trigger this path by having _find_tail_cut_by_tokens return head_end (which makes compress_end = head_end + 1, same as compress_start after alignment).""" - def test_no_op_increments_counter(self): - """compress_start >= compress_end -> _ineffective_compression_count += 1""" + def test_no_op_arms_structural_backoff(self): + """compress_start >= compress_end -> backoff armed, strikes untouched.""" comp = _make_compressor( summary_target_ratio=0.45, config_context_length=96000, @@ -80,8 +82,14 @@ class TestCompressNoOpRegistersIneffective: result = comp.compress(messages, current_tokens=73_000) - assert comp._ineffective_compression_count >= 1, ( - f"Expected ineffective_compression_count >= 1, got {comp._ineffective_compression_count}" + assert len(result) == len(messages), ( + "no-op compression must return the transcript unchanged" + ) + assert comp._ineffective_compression_count == 0, ( + "a structural impossibility is not an ineffective strike (#93022)" + ) + assert comp._structural_no_op_backoff_until > time.monotonic(), ( + "structural no-op must arm the retry backoff" ) @@ -98,9 +106,11 @@ class TestCompressNoOpRegistersIneffective: comp.compress(messages, current_tokens=73_000) comp.compress(messages, current_tokens=73_000) - assert comp._ineffective_compression_count >= 2 + assert comp._ineffective_compression_count == 0, ( + "structural no-ops defer via backoff instead of striking (#93022)" + ) assert not comp.should_compress(73_000), ( - "should_compress should return False after 2+ ineffective compressions" + "should_compress should return False while the structural backoff holds" )