fix(openviking): re-arm the commit guard after in-place compression (#74695) - #75046
jeff-mettel wants to merge 2 commits into
Conversation
`_committed_session_ids` is a permanent per-sid latch, and `_session_needs_commit` checks it before the turn counter by design — a racing sync_turn can re-increment `_turn_count` after commit+reset, so the guard must win to stop a double-commit. That is correct for a session being left behind. It is wrong for one that keeps its id. `compress_context()` commits before rewriting the transcript in both modes, and with `compression.in_place: true` (the default) `on_session_switch` receives the same id and does not rotate. The latch then rejects every later commit for a still-live session — the next compression, /new, normal session end, startup recovery — so every post-compression turn is silently never extracted. Rotation mode is unaffected because a fresh child id is minted and starts clean, which is what confirms the latch's intent was only ever to dedupe the departing id. Clear the latch when compression completes without rotation. Turns arriving after that point are genuinely new, and this is a defined moment rather than a race. The rotation path is untouched, so the old id stays latched and its _finalize_session_async still dedupes against the compression commit. Fixes NousResearch#74695 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Thanks for the focused fix. The premise is confirmed on the checked-out main: Problems
Suggested changes
Automated hermes-sweeper review. |
Review feedback: the previous test called _mark_session_committed directly, so it verified the guard's behavior but not the wiring that sets it — a future break in the commit_memory_session -> same-id compression-boundary path would not be caught. Add a lifecycle regression that drives the real sequence: on_session_end commits through the actual path, on_session_switch(same id, reason="compression") crosses the boundary, sync_turn records a genuinely new turn, and a second on_session_end must produce a second commit POST. Without the fix it fails showing exactly one commit call, which is the reported data loss: every turn after the first compression is dropped. The rotation and /undo tests stay as scope guards. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Accepted and added.
Without the production change it fails on step 4 with exactly one commit call recorded: That single call is the reported data loss stated as a test: everything after the first compression is silently dropped. The rotation and Filed by an AI agent (Claude Opus 5) operating autonomously on @jeff-mettel's behalf. The failing output above was produced by running the new test against |
|
Merged via #77747 — your commits cherry-picked with authorship preserved (rebase merge). This PR consolidated your port-occupancy guard and compression re-arm fixes together with 4 other OpenViking fixes into one coherent integration so the complete runtime behavior could be validated as a unit. Thanks for the contributions! |
What & why
Fixes #74695.
_committed_session_idsis a permanent per-sid latch, and_session_needs_commitchecks it before the turn counter deliberately:That is correct for a session being left behind. It is wrong for one that keeps its id.
compress_context()commits before rewriting the transcript in both modes. Withcompression.in_place: true— the default —on_session_switchreceives the same id, sorotate = not (rewound or new_id == old_session_id)isFalseand nothing rotates. The latch is now set on a session that is still live, and every later commit for it is rejected: the next compression,/new, normal session end, and startup recovery all silently do nothing. Post-compression turns are never extracted.Rotation mode (
in_place: false) doesn't have the problem — a fresh child id is minted and starts clean. As the issue notes, that asymmetry is what confirms the latch's intent was only ever to dedupe the departing id's_finalize_session_asyncagainst the compression commit.The change
Clear the latch when compression completes without rotation.
This is a defined moment, not a race: compression has finished and the transcript is rewritten, so any turn arriving afterwards is genuinely new. The concern the guard exists for — a
sync_turnracing the commit+reset — is unchanged, because that race is about the departing id, and the rotation path is untouched.Scoped deliberately:
rotate == True(rotation mode) → old id stays latched, so its_finalize_session_asyncstill dedupes against the compression commit.rewound(/undo) → not compression, so the latch is untouched.reason == "compression".Tests
tests/plugins/memory/test_openviking_provider.py:test_in_place_compression_rearms_commit_guard— latch set, same-id switch, then a later commit is allowed againtest_rotating_compression_keeps_old_session_latched— rotation still latches the old idtest_undo_rewind_does_not_rearm_commit_guard—/undodoes not re-armOnly the first fails on unmodified
main:The other two pass both with and without the patch by design — they exist to prove the change doesn't over-reach into the behavior the guard is there for. The pre-existing
test_session_needs_commit_guard_wins_over_stale_turn_count(the #28296 M3 regression) also still passes unchanged.Platforms
macOS 15 (Darwin 25.5.0), Python 3.11. In-memory set handling under an existing lock; no platform-specific behavior and no I/O added.
Duplicate check
gh search prsfor_committed_session_idsreturns nothing open or closed. No PR links #74695.Authored by an AI agent (Claude Opus 5) operating autonomously on @jeff-mettel's behalf: the defect was traced, the patch written, and the tests run and verified end-to-end before submission.