fix(checkpoint): repair stale session cursors after cleanup#324
fix(checkpoint): repair stale session cursors after cleanup#324Arreboi06 wants to merge 5 commits into
Conversation
…l data After cleanup operations (deleting test pipeline states, running memory-cleaner, or manual JSONL pruning), checkpoint counters drift from actual data because all increment methods lack decrement counterparts. This adds a recalibrate() method that allows callers to reset counters to their actual values by providing the true counts from the data layer. The method recalculates: - l0_conversations_count - total_memories_extracted - total_processed - memories_since_last_persona (derived from last_persona_at) Fixes: TencentCloud#157 Co-authored-by: Cursor <cursoragent@cursor.com>
7ed86cb to
9cacd0e
Compare
This commit enhances the checkpoint recalibration PR with: ## Documentation (checkpoint.ts) - Complete checkpoint data flow diagram showing: - L0/L1/L2/L3 pipeline paths - Cleanup scenarios and counter drift causes - Solution implementation (recalibrate + decrement methods) - Counter drift impact analysis table - Design pattern analysis (event-sourced, storage-first, hybrid) - Acceptance criteria coverage matrix ## Test Coverage (checkpoint.test.ts) New test suites covering: 1. Cleanup Scenarios - Manual JSONL pruning (user deletes old shards) - Test data cleanup (developer removes test records) - Session reset (user resets a specific session) - Incremental processing (prevents L1/L2 from skipping records) - Automatic cleaner integration (memory-cleaner.runOnce) 2. Design Pattern Validation - Hybrid cursor-first approach - Backward compatibility - Atomic concurrent operations Total: 37 tests (previously 17), all passing Fixes: TencentCloud#157 Co-authored-by: Cursor <cursoragent@cursor.com>
…tup/cleaner This commit adds the complete implementation to fix checkpoint counter drift: ## New Features ### 1. recalculate() auto-scan method - Automatically scans conversations/YYYY-MM-DD.jsonl for L0 counts - Automatically scans records/YYYY-MM-DD.jsonl for L1 counts - Clamps stale last_l1_cursor to newest retained L0 recordedAt - Clamps stale last_extraction_updated_time to newest retained L1 updatedAt - Resets session cursors to 0/"" for sessions with no retained data - Returns cursor correction statistics ### 2. Startup integration (TdaiCore.ensureSchedulerStarted) - Calls recalculate() before scheduler starts - Uses VectorStore counts when available (preferred over JSONL scan) - Non-fatal: proceeds with stale checkpoint if recalculation fails ### 3. Memory-cleaner integration (LocalMemoryCleaner.runOnce) - Recalculates checkpoint after cleanup completes - Supports optional checkpoint manager injection - Supports optional callback for recalculation results ## Test Coverage - 44 unit tests (added 7 new tests for recalculate()) - Covers auto-scan, cursor correction, store count override - All tests pass Fixes: TencentCloud#157 Co-authored-by: Cursor <cursoragent@cursor.com>
|
Hi @Arreboi06 👋, |
…llback, concurrency, crash recovery, and cleaner integration - Extend RecalibrateOptions with totalProcessedCount and memoriesSincePersonaCount (absorb PR TencentCloud#253 L2ncE) - Add RecalibrationResult interface with before/after snapshots (absorb PR TencentCloud#324 Arreboi06) - Add integration tests: JSONL end-to-end, 10k-line perf, corrupt recovery (9 tests) - Add concurrent safety tests: lock sharing, multi-instance, capture+recalibrate atomicity (5 tests) - Add crash recovery tests: atomic write, tmp residue, truncated JSON (5 tests) - Add memory-cleaner integration: onAfterCleanup -> recalibrate chain (5 tests) - Total: 54 checkpoint tests (+34 new), 121 full suite
|
Triage note: #177 has been locally verified and approved as the canonical #157 fix. It recalibrates checkpoint counters against actual store counts, adjusts memories_since_last_persona safely, and wires recalibration after cleanup plus scheduler startup. This PR appears to cover the same checkpoint-counter drift scope, so I recommend treating it as superseded unless it intentionally adds behavior beyond #177. |
|
Addressed the superseded-scope concern in the latest push ( I agree that #177 is the canonical fix for the aggregate checkpoint-counter drift in #157. This branch now keeps that same safety model: The intentional behavior beyond #177 is narrower: session-aware cursor repair. Cleanup/startup can leave per-session cursors ahead of retained data:
Local verification after this update:
So I would frame this PR as: #177 fixes the canonical aggregate counter drift; this PR is only worth keeping if the maintainers want the extra session-cursor recovery behavior as a follow-up on top of that fix. |






Related to #157. Complements #177.
Summary
This PR keeps #177 as the canonical aggregate checkpoint-counter recalibration fix, and narrows this branch to the additional behavior that #177 does not cover: repairing stale per-session cursors after cleanup/startup.
The extra failure mode is not just a wrong displayed count. After JSONL/DB cleanup, a session cursor can point past the newest retained record for that same session. When the scheduler restores from that stale checkpoint, incremental L1/L2 reads can skip retained or newly written data.
Relationship to #177
#177 should remain the reference fix for the aggregate counter drift in #157:
memories_since_last_personasafely;This branch now follows that same safety model. In particular,
memories_since_last_personais adjusted only by the number of removed L1 memories. It is not recomputed fromlast_persona_at, becauselast_persona_atis atotal_processedcursor, not an L1 memory counter.Intentional Behavior Beyond #177
This PR adds session-aware cursor recovery:
runner_states[session].last_l1_cursorto that session's newest retained L0recordedAtwatermark;runner_states[session].last_captured_timestamponly when retained L0 evidence proves it is stale;pipeline_states[session].last_extraction_updated_timeto that session's newest retained L1updatedAt/updated_timewatermark;The key point is that cursor correction is per-session, not global. A global newest timestamp can hide a stale cursor in one session when another session has newer retained data.
Implementation Notes
recalibrate()handles explicit count reconciliation when callers already know actual counts.recalculate()scans retained JSONL shards, accepts optional VectorStore counts, updates aggregate counters, and repairs per-session cursors from retained watermarks.LocalMemoryCleaner.runOnce()invokes recalculation after JSONL/DB cleanup.recall_checkpoint.json.Verification
Latest verified commit:
cd026e6High-Value Scenarios Covered
memories_since_last_personais reduced by removed L1 memories, not by mixing L1 counts withlast_persona_at;