Skip to content

fix(sessions): recover compression parents without continuations - #80380

Closed
izumi0uu wants to merge 2 commits into
NousResearch:mainfrom
izumi0uu:fix/session-orphan-recovery-80337
Closed

izumi0uu wants to merge 2 commits into
NousResearch:mainfrom
izumi0uu:fix/session-orphan-recovery-80337

Conversation

@izumi0uu

@izumi0uu izumi0uu commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Recovers legacy or malformed sessions that are marked end_reason=compression but have no continuation row. Current compression publication is already atomic, so this does not replace or weaken that path; it adds a conservative repair for orphaned state that can otherwise reject every future transcript write.

At turn start, Hermes still prefers adopting the unique live compression child. If none exists, the new database operation reopens the parent only when one write transaction confirms all of these invariants:

  • the parent is compression-ended
  • no active compression lease exists
  • no canonical continuation child exists, including an ended child

If a child or active lease exists, recovery remains fail-closed rather than guessing which session owns subsequent messages. Branch, delegate, and tool children do not count as compression continuations.

Related Issue

Fixes #80337

Related: #71001 established atomic parent/child publication for new compression rotations.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • Tests (adding or improving test coverage)

Changes Made

  • Add SessionDB.reopen_orphaned_compression_session() with transactionally checked lineage and lease guards.
  • Invoke orphan recovery after normal child adoption cannot find a continuation and no live lease remains.
  • Add regression coverage for recovery, existing children, non-continuation children, and active leases.

How to Test

  1. Create a session row with messages, then mark it ended with end_reason=compression without creating a child.
  2. Start the next agent turn and verify the parent is reopened and accepts transcript writes.
  3. Add a canonical child or active compression lease and verify the parent remains closed.

Validation

  • pytest -q tests/state tests/agent/test_compression*.py - 151 passed
  • focused compression, turn-context, gateway session suite - 144 passed
  • ruff check on changed Python files
  • git diff --check

Checklist

  • Read the contributing guide
  • Commit follows Conventional Commits
  • Searched open issues and PRs for overlap
  • PR contains only issue-scoped changes
  • Added regression tests
  • Documentation/config/schema updates are not applicable
  • Considered cross-platform impact: recovery uses the existing SQLite transaction layer and no platform-specific APIs

@alt-glitch alt-glitch added type/bug Something isn't working P1 High — major feature broken, no workaround comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint area/sessions Session lifecycle, resume, persistence, history area/compression Context compression and continuation sessions sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state labels Aug 6, 2026
@kshitijk4poor

Copy link
Copy Markdown
Contributor

Merged via #80487 with your commits cherry-picked and authorship preserved (rebase-merge — both fix(sessions): recover compression parents without continuations and fix(sessions): fence expired orphan recovery leases are on main under your name). Thank you — the transactional lineage+lease guards and the refresh-vs-reclaim fencing were the right design, and adversarial review confirmed the BEGIN IMMEDIATE serialization holds against a late compressor.

One follow-up commit rode along in the salvage: compression continuations inherit the rotated agent's model_config verbatim, so a delegate subagent's continuation carries a foreign _delegate_from — the marker-presence filters misread that as a delegate child (reopen would have forked the lineage). The markers are now bound to the queried parent via a shared SQL fragment used by both find_live_compression_child and the reopener, with a regression pair covering both directions.

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 P1 High — major feature broken, no workaround 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.

[Bug]: Compression-closed session with no continuation becomes an orphan that rejects all writes — turns die with session_persistence_failed

3 participants