fix(retain): preserve oversized document deltas#2728
Conversation
Compare replacements against the complete logical document before transport splitting, then process only bounded changed chunks. Preserve result cardinality, Memory Defense, race fallback, and transactional outbox behavior across exact chunk-batch boundaries. Co-Authored-By: OpenAI GPT-5.6-Sol High <support@openai.com>
|
Closing in favor of a focused replacement. After tracing the retain pipeline on The stated failure mode is not what The real cost blowup is narrower: it's a one-time full re-extraction when slice 1 itself differs (a head edit, or the first append that crosses the threshold), caused by the The What we'll take forward in a focused PR:
Thanks for the thorough write-up and repro scaffolding — the multi-chunk extraction-recording test harness here is reusable and we'll carry the idea over. |
Summary
Preserve Delta Retain's changed-chunk-only extraction for oversized full-document replacements.
This matters for append-only documents such as chat transcripts: callers can safely keep sending the canonical full transcript with
update_mode=replace, while unchanged history is excluded from LLM extraction whenever the actual delta fits the configured retain bounds.Failure mode
Assume the stored transcript has logical retain chunks:
A B C D EThe next scheduled retain submits the canonical replacement document:
A B C D E + new tailWhen that document exceeded
retain_batch_tokens, the old flow split it into transport-sized fragments before running Delta Retain. Those transport boundaries do not necessarily align with the logical chunks stored for the document, so unchanged history could no longer be matched reliably. The result was that an incremental update could re-enter LLM extraction as if it were new content, defeating Delta Retain's cost-saving behavior.Root cause
MemoryEngine.retain_batch_asyncapplied transport/OOM splitting beforeorchestrator._try_delta_retain.Delta Retain therefore compared partial transport slices instead of comparing the complete canonical replacement document with the previously stored logical document chunks.
Why this required a deeper fix
The motivating workload is a periodically retained chat transcript. The caller intentionally resubmits the full canonical transcript with
update_mode=replaceso retries are idempotent and the stored document remains correct. Only the newly changed logical chunks should incur extraction cost. Once a transcript crossed the transport batch limit, however, the order of operations silently broke that cost guarantee.Fixing this safely was more involved than moving Delta Retain ahead of the splitter. That change crosses several retain invariants at once:
The implementation therefore required tracing the full retain pipeline, reproducing the oversized replacement behavior with realistic multi-chunk documents, defining bounded eligibility for the pre-split delta path, and adding regression tests around every affected fallback and completion contract. The result preserves the existing resilience mechanisms while restoring Delta Retain's intended LLM-cost behavior for growing documents.
How this fixes it
For a single oversized
update_mode=replaceitem with adocument_id, the retain path now:retain_batch_tokensand the changed chunk count fitsretain_chunk_batch_size.Additional correctness fixes included in the same path:
retain_chunk_batch_size, ensuring the transactional outbox callback is not skipped.Safety properties
processed_content_tokensreflects changed work rather than the full replacement document.update_mode=appendbehavior is unchanged.Verification
Added regression coverage proving that:
Validation completed locally:
ty check hindsight_api/passed.