From dde424783fe43cc583bda0774ff7f0142be9341d Mon Sep 17 00:00:00 2001 From: Kiryu Tsukimiya <71832+tsukimiya@users.noreply.github.com> Date: Sat, 27 Jun 2026 13:34:19 +0900 Subject: [PATCH] fix(read-lifecycle): persist STALE Read originals in the CCR store MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ContentRouter.transform instantiated ReadLifecycleManager with compression_store=kwargs.get("compression_store"), but no caller ever sets that kwarg. self.store was therefore always None, so STALE/SUPERSEDED Read markers were emitted with a SHA-256 hash but the original content was never stored — headroom_retrieve(hash) 404'd on every Read marker, breaking the CCR contract for the common Claude Code flow (read a file, edit it, then want the prior content back). Fall back to get_compression_store() when no store is explicitly injected, matching how SmartCrusher, Kompress, and the search/log/diff/code compressors already resolve theirs. The kwargs injection point is kept so explicit overrides still work. --- headroom/transforms/content_router.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/headroom/transforms/content_router.py b/headroom/transforms/content_router.py index 53c03be75..310c98cb5 100644 --- a/headroom/transforms/content_router.py +++ b/headroom/transforms/content_router.py @@ -2417,11 +2417,12 @@ class ContentRouter(Transform): """ # Pre-process: Read lifecycle management (stale/superseded detection) if self.config.read_lifecycle.enabled: + from ..cache.compression_store import get_compression_store from .read_lifecycle import ReadLifecycleManager lifecycle_mgr = ReadLifecycleManager( self.config.read_lifecycle, - compression_store=kwargs.get("compression_store"), + compression_store=kwargs.get("compression_store") or get_compression_store(), ) lifecycle_result = lifecycle_mgr.apply( messages,