From 373b16f02b6e2cff3ac4c982dc1d371e227c6bdc Mon Sep 17 00:00:00 2001 From: youchi Date: Thu, 30 Apr 2026 11:18:20 +0200 Subject: [PATCH] fix(retain): thread ops into handle_document_tracking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regression from #1325 (perf(db): eliminate ResultRow wrapping). Line fact_storage.py:312 was changed to pass ops=ops to delete_stale_observations_for_memories, but ops was never added to handle_document_tracking's signature, so every first-batch retain hit NameError: name 'ops' is not defined. Effect: every batch_retain task fails on the first-batch document tracking path. The poller schedules a retry, the retry fails the same way, and after the retry budget is exhausted the parent operation is marked failed. No memories get stored. The gateway's "hindsight: 1 retains (...) captured" log is misleading — that just means dispatch succeeded; the daemon's actual write path was raising all along. Fix is to give handle_document_tracking an ops parameter (defaulting to None to preserve the Oracle/junction-table fallback) and pass pool.ops from both call sites in orchestrator._streaming_retain_batch. Reproducible on any retain that triggers a first-batch document upsert. Verified against the daemon's structured log on a live deployment running main as of d8ec2d7f. --- hindsight-api-slim/hindsight_api/engine/retain/fact_storage.py | 1 + hindsight-api-slim/hindsight_api/engine/retain/orchestrator.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/hindsight-api-slim/hindsight_api/engine/retain/fact_storage.py b/hindsight-api-slim/hindsight_api/engine/retain/fact_storage.py index 251410101a..11d2827b5a 100644 --- a/hindsight-api-slim/hindsight_api/engine/retain/fact_storage.py +++ b/hindsight-api-slim/hindsight_api/engine/retain/fact_storage.py @@ -269,6 +269,7 @@ async def handle_document_tracking( is_first_batch: bool, retain_params: dict | None = None, document_tags: list[str] | None = None, + ops=None, ) -> None: """ Handle document tracking in the database (full-replace mode). diff --git a/hindsight-api-slim/hindsight_api/engine/retain/orchestrator.py b/hindsight-api-slim/hindsight_api/engine/retain/orchestrator.py index 512b22ce32..d4077aa994 100644 --- a/hindsight-api-slim/hindsight_api/engine/retain/orchestrator.py +++ b/hindsight-api-slim/hindsight_api/engine/retain/orchestrator.py @@ -1103,6 +1103,7 @@ async def _process_db_batch( is_first_batch, retain_params, merged_tags, + ops=pool.ops, ) doc_tracking_done[0] = True log_buffer.append(f"[streaming] Document {effective_doc_id} tracked (0 facts in first batch)") @@ -1205,6 +1206,7 @@ async def _run_mini_batch_db_work() -> None: is_first_batch, retain_params, merged_tags, + ops=pool.ops, ) log_buffer.append(f"[streaming] Document {effective_doc_id} tracked (full content)") doc_tracking_done[0] = True