mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-08-23 08:02:23 +02:00
Stage 1 of the sqlite delta history filtered `checkpoint_id <= target` and streamed `ORDER BY checkpoint_id DESC`. Both predicates encode the same extra assumption: that every child's checkpoint id sorts above its parent's. Ancestry is defined by `parent_checkpoint_id`, and nothing in the contract requires ids to be monotonic. A parent whose id sorted above its child's was dropped from the stream, so its stored value and its writes were lost with no error raised. Removing the range filter alone would not help: in DESC order that parent arrives before the target, so the walk passes it before it has started. A single-pass ordered stream cannot express this walk. Replace it with a recursive CTE anchored at the target that follows `parent_checkpoint_id`. Rows arrive in walk order, so `step_walk_with_row` keeps its existing shape, and the query now reads only true ancestors instead of every row at or below the target, which is strictly less IO than before. Following pointers can loop where a bounded id scan could not, and a loop is reachable through `put` alone rather than only by corruption: it writes with `INSERT OR REPLACE`, so re-putting an existing checkpoint id under a descendant's config repoints that checkpoint at its own descendant. The walk therefore stops on a repeated checkpoint id. sqlite yields recursive rows lazily, so abandoning the cursor ends the recursion instead of waiting on it. Postgres needs no equivalent change. It pages the whole thread and follows parent pointers already, so it returns the correct history for this scenario. Fixes #8550 Co-authored-by: lylelllll <59271327+lylelllll@users.noreply.github.com>