Skip to content

fix(compression): preserve goal, platform, and session indexing across rotation - #49772

Merged
teknium1 merged 1 commit into
mainfrom
fix/compression-rotation-state-loss
Jun 21, 2026
Merged

fix(compression): preserve goal, platform, and session indexing across rotation#49772
teknium1 merged 1 commit into
mainfrom
fix/compression-rotation-state-loss

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

Three pieces of state that used to be lost or corrupted when context compression rotates session_id to a continuation child now survive the boundary. They're fixed together because all three live in the same ~80-line rotation block in agent/conversation_compression.py — separate PRs would cascade-conflict in that exact region.

What changed

Validation

Bug Guard test Verified
#33618 test_goal_follows_compression_rotation + 5 migrate_goal_to_session unit tests
#33906 test_rolls_back_to_parent_when_child_create_fails fails without fix → passes with
#27633 test_on_session_start_receives_platform

Real SessionDB + real compress_context integration tests (tests/agent/test_compression_rotation_state.py). 161 passing across the compression + goals suites; orphan-rollback confirmed as a true regression guard.

Credit

Combines the substantive fixes from three contributor PRs into one conflict-free rotation-block change, authorship preserved via co-author trailers: #33620 (denisqq, goal migration), #34048 (zccyman, orphan rollback), #42679 (liuhao1024, platform forward). Those PRs will be closed pointing here.

Infographic

compression-rotation-hardening

@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 comp/cli CLI entry point, hermes_cli/, setup wizard P1 High — major feature broken, no workaround labels Jun 20, 2026
@github-actions

github-actions Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

🔎 Lint report: fix/compression-rotation-state-loss vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 11278 on HEAD, 11276 on base (🆕 +2)

🆕 New issues (2):

Rule Count
unresolved-attribute 2
First entries
tests/agent/test_compression_rotation_state.py:56: [unresolved-attribute] unresolved-attribute: Unresolved attribute `context_compressor` on type `AIAgent`
tests/hermes_cli/test_goals.py:576: [unresolved-attribute] unresolved-attribute: Attribute `goal` is not defined on `None` in union `GoalState | None`

✅ Fixed issues: none

Unchanged: 5913 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

…s rotation

Three state-loss bugs at the compression rotation boundary, fixed together
because they all live in the same ~80-line rotation block:

- #33618: a persistent /goal did not follow the rotation. load_goal does a
  flat per-session lookup with no lineage walk, so a goal silently died when
  compression minted a fresh child id. Added migrate_goal_to_session() and
  call it after the child session is created (move-not-copy: the parent row
  is archived as cleared so exactly one active goal row exists).

- #33906/#33907: if the child create_session raised (FK constraint,
  contended write), the outer handler only warned and let the agent continue
  on the NEW id — which has no row in state.db — producing an orphan session.
  Now the rotation rolls agent.session_id back to the still-indexed parent
  (reopening it) instead of stranding the conversation on a phantom id.

- #27633: the compaction-boundary on_session_start notification omitted the
  platform kwarg, so context-engine plugins saw source=unknown for every
  message after the boundary. Forward platform (matching the initial
  session-start call in agent_init.py).

Co-authored-by: denisqq <21260182+denisqq@users.noreply.github.com>
Co-authored-by: zccyman <16263913+zccyman@users.noreply.github.com>
Co-authored-by: liuhao1024 <sunsky.lau@gmail.com>
@PaddyPatPat

Copy link
Copy Markdown

Follow-up observation on the goal migration added here: this is not a recurrence of the original “goal was not copied” bug, but there still appears to be a race/crash-consistency gap in the migration implementation.

The migration reads the parent metadata, writes the child, and clears the parent as separate operations. Real SQLite-backed concurrency and failure tests reproduced:

  • a child appearing after the absence check being overwritten;
  • a child write surviving a failed parent clear, leaving both the parent and child goal records active.

The previously suspected stale-parent-clear case did not reproduce: clear_goal() reloads the parent immediately before marking it cleared, so a concurrent parent update remained unchanged while the child received the earlier snapshot.

A narrow hardening would be an atomic compare_and_move_meta operation that:

  • compares the parent against the exact expected value;
  • requires the child key to be absent;
  • writes the child and removes the matching parent in one transaction;
  • makes no changes if either precondition fails.

Focused regressions would cover a child appearing after the absence check, an interruption after the child write, and successful movement. This would preserve the behavior landed here while tightening only the remaining race boundary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard P1 High — major feature broken, no workaround type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants