From acb2954d82654f6e730497d19a5bdb0ff74e60a8 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Thu, 11 Jun 2026 12:45:45 -0700 Subject: [PATCH] fix(agent): freeze carveout-era SUMMARY_PREFIX for renormalization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The prompt consolidation above retires the carveout-era prefix. Without a frozen copy in _HISTORICAL_SUMMARY_PREFIXES, summaries persisted by pre-upgrade builds would lose detection (_is_context_summary_content) and renormalization (_strip_summary_prefix) — the exact regression class the tuple exists to prevent. Adds contract tests covering every frozen prefix. Refs #41607 #38364 #42812 --- agent/context_compressor.py | 25 ++++++++++++++ tests/agent/test_summary_prefix_semantics.py | 34 ++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/agent/context_compressor.py b/agent/context_compressor.py index c7ca134b175..9c479705f9e 100644 --- a/agent/context_compressor.py +++ b/agent/context_compressor.py @@ -80,6 +80,31 @@ LEGACY_SUMMARY_PREFIX = "[CONTEXT SUMMARY]:" # embedded in the body and keeps hijacking replies. Keep newest-first; entries # are matched literally. Add a frozen copy here whenever SUMMARY_PREFIX changes. _HISTORICAL_SUMMARY_PREFIXES = ( + # Carveout era (#41607/#38364/#42812): "consistent → use as background" + # licensed stale-task resumption on topic overlap. + "[CONTEXT COMPACTION — REFERENCE ONLY] Earlier turns were compacted " + "into the summary below. This is a handoff from a previous context " + "window — treat it as background reference, NOT as active instructions. " + "Do NOT answer questions or fulfill requests mentioned in this summary; " + "they were already addressed. " + "Respond ONLY to the latest user message that appears AFTER this " + "summary — that message is the single source of truth for what to do " + "right now. " + "If the latest user message is consistent with the '## Active Task' " + "section, you may use the summary as background. If the latest user " + "message contradicts, supersedes, changes topic from, or in any way " + "diverges from '## Active Task' / '## In Progress' / '## Pending User " + "Asks' / '## Remaining Work', the latest message WINS — discard those " + "stale items entirely and do not 'wrap up the old task first'. " + "Reverse signals in the latest message (e.g. 'stop', 'undo', 'roll " + "back', 'just verify', 'don't do that anymore', 'never mind', a new " + "topic) must immediately end any in-flight work described in the " + "summary; do not re-surface it in later turns. " + "IMPORTANT: Your persistent memory (MEMORY.md, USER.md) in the system " + "prompt is ALWAYS authoritative and active — never ignore or deprioritize " + "memory content due to this compaction note. " + "The current session state (files, config, etc.) may reflect work " + "described here — avoid repeating it:", # Pre-#35344: contained the self-contradicting "resume exactly" directive. "[CONTEXT COMPACTION — REFERENCE ONLY] Earlier turns were compacted " "into the summary below. This is a handoff from a previous context " diff --git a/tests/agent/test_summary_prefix_semantics.py b/tests/agent/test_summary_prefix_semantics.py index 42047142f08..eb8dfbee233 100644 --- a/tests/agent/test_summary_prefix_semantics.py +++ b/tests/agent/test_summary_prefix_semantics.py @@ -80,3 +80,37 @@ def test_memory_authority_preserved(): assert "MEMORY.md" in SUMMARY_PREFIX assert "USER.md" in SUMMARY_PREFIX assert "authoritative" in SUMMARY_PREFIX + + +def test_no_background_consistency_carveout(): + """The "consistent → use as background" carveout licensed stale-task + resumption on topic overlap (#41607, #38364, #42812). It must stay gone, + and the prefix must explicitly neutralize topic overlap.""" + lower = SUMMARY_PREFIX.lower() + assert "you may use the summary as background" not in lower + assert "topic overlap" in lower + + +def test_replaced_prefixes_are_frozen_for_renormalization(): + """Every retired SUMMARY_PREFIX must be frozen into + _HISTORICAL_SUMMARY_PREFIXES, otherwise summaries persisted by older + builds lose detection/renormalization after an upgrade. The carveout-era + prefix is the latest retiree.""" + from agent.context_compressor import ( + _HISTORICAL_SUMMARY_PREFIXES, + ContextCompressor, + ) + + carveout_era = [ + p for p in _HISTORICAL_SUMMARY_PREFIXES + if "you may use the summary as background" in p + ] + assert carveout_era, "carveout-era prefix missing from frozen tuple" + # The live prefix must never be one of the frozen ones. + assert SUMMARY_PREFIX not in _HISTORICAL_SUMMARY_PREFIXES + # Detection + strip must work for every frozen prefix. + for old_prefix in _HISTORICAL_SUMMARY_PREFIXES: + content = old_prefix + "\n## Summary body" + assert ContextCompressor._is_context_summary_content(content) + stripped = ContextCompressor._strip_summary_prefix(content) + assert not stripped.startswith(old_prefix)