1.2 KiB
Fix: stale pending writes cannot roll back the latest LangGraph checkpoint
Problem
RepositoryCheckpointSaver.aput_writes() used the latest full checkpoint payload, appended pending writes and persisted that payload as a new checkpoint row. Because the repository is append-only, an aput_writes() from an older super-step could finish after a newer aput() and become the newest database row. The next request would then restore an older transaction state.
Observed symptom in a single session:
- turn N opens a new transaction and asks for confirmation;
- turn N+1 restores an older completed transaction;
- a standalone confirmation such as
simis routed to no-match.
Fix
aput_writes() now compares config.configurable.checkpoint_id with the durable latest checkpoint id. If the write belongs to an older checkpoint, it is ignored instead of re-persisting the stale full checkpoint as latest.
Writes for the actual latest checkpoint continue to be persisted normally.
Invariant
For a thread/session, checkpoint ordering is monotonic: a delayed pending write may enrich its own checkpoint, but it must never make a previous checkpoint become the session's latest state.