fix(compression): preserve goal, platform, and session indexing across rotation - #49772
Conversation
🔎 Lint report:
|
| 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>
0b25f46 to
34ef945
Compare
|
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:
The previously suspected stale-parent-clear case did not reproduce: A narrow hardening would be an atomic
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. |
Summary
Three pieces of state that used to be lost or corrupted when context compression rotates
session_idto a continuation child now survive the boundary. They're fixed together because all three live in the same ~80-line rotation block inagent/conversation_compression.py— separate PRs would cascade-conflict in that exact region.What changed
/goalsurvives rotation.load_goaldoes a flat per-session lookup with no lineage walk, so an active goal silently died when compression minted a fresh child id. Addedmigrate_goal_to_session()(hermes_cli/goals.py) — move-not-copy: copies the goal to the child and archives the parent row asclearedso exactly one active goal row exists. Called after the child session is created.create_sessionraised (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 (compression_parents_with_no_childin the wild). Now the rotation rollsagent.session_idback to the still-indexed parent (reopening it) instead of stranding the conversation on a phantom id.source=unknownfixed. The compaction-boundaryon_session_startnotification omitted theplatformkwarg, so context-engine plugins (e.g. hermes-lcm) sawsource=unknownfor every message after the boundary. Now forwardsplatform=(matching the initial session-start call inagent_init.py).Validation
test_goal_follows_compression_rotation+ 5migrate_goal_to_sessionunit teststest_rolls_back_to_parent_when_child_create_failstest_on_session_start_receives_platformReal
SessionDB+ realcompress_contextintegration 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