Repository navigation
fix(cli): don't advance the flush cursor past on-disk rows /undo failed to soft-delete - #93775
chandlerm923 wants to merge 1 commit into
Conversation
…ed to soft-delete undo_last() always truncates conversation_history in memory (unchanged, intentional design — see 3f7d1c8's "keep the in-memory undo but skip the soft-delete"). But when the DB soft-delete raises (cross-session handle, non-user target skew, DB locked, etc.), the flush cursor (agent._last_flushed_db_idx) was still unconditionally reset to the truncated length, silently assuming the DB agreed. It doesn't: those rows stay active=1 on disk. The next flush then appends new rows alongside them instead of replacing them, so the "undone" content resurfaces on reload/resume/crash and stays a hit in FTS search — while the failure itself was only ever logged at DEBUG. Track whether the on-disk transcript is actually known to agree (db_reconciled) and gate the cursor reset on it. No DB in play at all is still harmless (nothing to diverge from). Upgrade the swallowed exception to a WARNING and surface a one-line notice to the user instead of silence. Sabotage-verified: 4/7 new tests fail without this fix (the 3 success/ no-DB controls still pass unaffected).
Overall: a carefully-reasoned fix for a subtle persistence bug — gating the flush-cursor advance on a
Minor: the new test module imports |
|
Resolved on current main by #93784 (carrying #81234). The upstream implementation now completes the durable rewind before publishing the shorter in-memory history and returns without mutating history when persistence fails, so the flush cursor can no longer advance past unreconciled on-disk rows. This supersedes the narrower guard in this PR, and the branch now conflicts with that implementation. Closing as superseded — thanks. |
Summary
undo_last()always truncatesconversation_historyin memory (intentional,3f7d1c801d). When the DB soft-delete raises, the flush cursor was reset to the truncated length anyway, assuming the DB agreed. It doesn't — those rows stayactive=1. The next flush appends new rows next to them, so undone content resurfaces on reload/resume and stays a hit in FTS search.Changes
cli.py: gate the flush-cursor reset on whether the soft-delete actually succeeded (db_reconciled). Swallowed exception → WARNING + one-line user notice.tests/cli/test_undo_persistence_atomicity.py: 7 tests covering success/failure/no-DB paths.Validation
test_slash_undo_title_robustness.py