Skip to content

fix(compression): serialize session rotation with durable leases - #64373

Open
yingliang-zhang wants to merge 2 commits into
NousResearch:mainfrom
yingliang-zhang:fix/compression-rotation-durable-lock
Open

fix(compression): serialize session rotation with durable leases#64373
yingliang-zhang wants to merge 2 commits into
NousResearch:mainfrom
yingliang-zhang:fix/compression-rotation-durable-lock

Conversation

@yingliang-zhang

Copy link
Copy Markdown
Contributor

Summary

  • prevent stale/concurrent agents from rotating one completed parent session into sibling continuation sessions
  • keep compression rotation admission in the existing SQLite transaction and durable per-session lease
  • preserve rollback/reopen and legacy lightweight SessionDB compatibility

Problem

Two agent instances can hold the same parent session. After one finishes compression rotation, a late caller could reacquire the now-free lease and rotate the completed parent again, creating a sibling continuation.

Changes

  • reject compression-lock acquisition atomically when the parent already has end_reason="compression"
  • keep expiry reclamation, holder-qualified refresh/release, and rollback/reopen behavior intact
  • make lock rejection messaging cover held, unavailable, and already-rotated states
  • add deterministic concurrent coverage proving the winner released its lease and completed the parent before the stale caller attempts acquisition

Verification

  • focused compression suites: 37 passed
  • gateway concurrent-session tests: 2 passed
  • lock refresh/reclaimability test: 1 passed
  • independent final review: ACCEPT, no P0–P2 findings
  • py_compile: passed
  • ruff check: passed
  • git diff --check: passed

Residual behavior

The exact legacy hot-reload compatibility path still proceeds unlocked when the live SessionDB class structurally lacks the lock API. This preserves the existing compatibility contract until process restart.

@alt-glitch alt-glitch added type/bug Something isn't working comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state P2 Medium — degraded but workaround exists labels Jul 14, 2026

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for isolating the late-acquirer race and adding deterministic concurrent coverage.

Problems

  • Blocking — hermes_state.py:2427: the new marker check treats any end_reason='compression' row as a completed rotation. Rotation is not atomic on current main: agent/conversation_compression.py:868 ends the parent, while create_session() follows at agent/conversation_compression.py:896-902. If the process dies in that interval, the lease eventually expires but this check rejects every recovery attempt despite there being no continuation child.

Suggested changes

  • Gate the durable rejection on a verified valid continuation child, using the existing child exclusions in hermes_state.py:3265-3272, or make completion atomic.
  • Add a test for a compression-ended parent with no child after lease expiry; it should remain recoverable. Keep the new stale-caller test for the completed-child case.

Automated hermes-sweeper review.

Comment thread hermes_state.py Outdated
@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform area/sessions Session lifecycle, resume, persistence, history area/compression Context compression and continuation sessions labels Jul 16, 2026
@yingliang-zhang
yingliang-zhang force-pushed the fix/compression-rotation-durable-lock branch 3 times, most recently from a3e939f to 13cfae6 Compare July 30, 2026 05:55
@yingliang-zhang
yingliang-zhang force-pushed the fix/compression-rotation-durable-lock branch 3 times, most recently from 2e866f0 to ed0d9f0 Compare August 12, 2026 05:51
…ation

Rebuild on current upstream: keep upstream's _session_was_rotated_by_compression
recovery path in conversation_compression.py as the sole already-rotated gate.
Remove the PR's redundant already_rotated check from try_acquire_compression_lock
(it blocked the recovery path). Update PR tests to match upstream semantics.
@yingliang-zhang
yingliang-zhang force-pushed the fix/compression-rotation-durable-lock branch from ed0d9f0 to 962bc6a Compare August 12, 2026 06:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/compression Context compression and continuation sessions area/sessions Session lifecycle, resume, persistence, history comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P2 Medium — degraded but workaround exists sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants