You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
#86775 fixed direct branch resumes on main, but its tip-only branch check still walks through the original parent after a branch is compressed. The result is a duplicated fork snapshot plus post-fork parent turns in the resumed continuation.
This PR detects a branch boundary on each traversed edge. Inherited _branched_from provenance on compression continuations is not treated as a new fork unless it names that row’s immediate parent.
Regression coverage
Real SessionDB tests cover:
direct branch resume excludes parent turns written after the fork
nested branch resume excludes parent turns written after the nested fork
ordinary compression continuation still replays ancestors
compression after a branch replays from the branch boundary, including inherited branch provenance
resume counts and size guards match the branch-aware transcript actually materialized
TDD evidence
current main + the regression file: 3 passed / 1 failed at test_compression_after_branch_replays_from_branch_boundary
inherited-marker variant before the edge comparison: 3 passed / 1 failed
AI code review — automated review for reference, author can ignore or act on any point.
fix(state): stop branch replay at fork snapshot
hermes_state.py:10479-10500 — _session_replay_lineage_root_to_tip caps the walk at 100 iterations (parity with _session_lineage_root_to_tip, which also caps at 100). The new call sites change the consequences of that cap: get_resume_message_count and assert_resume_safe now count the capped lineage, so a lineage deeper than ~100 compression continuations would undercount and assert_resume_safe could green-light a resume that then exceeds the message cap at materialization time. Pre-existing cap, but now it gates a safety check — worth a comment or a shared constant so the limit is visible in both functions.
The boundary condition branch_parent == parent_id (line 10492-10494) depends on _branched_from always naming the immediate parent edge. The compression-inheritance case is well covered by tests, but if any branch-creation path ever writes _branched_from with a non-parent value (or a legacy row records it differently), the boundary is not recognized and live parent turns leak into the branch — the exact bug class this PR fixes. Consider asserting the invariant (marker == parent) at branch creation time, or documenting that the marker must name the fork edge.
get_conversation_root still uses the old _session_lineage_root_to_tip full walk, which crosses fork edges — so a branch session's "conversation root" resolves into the live parent chain while replay stops at the fork. If any UI derives breadcrumbs/display lineage from get_conversation_root, it may show the parent turns that resume no longer includes. Confirm this split (presentation lineage vs replay lineage) is intended, or align the two functions.
Verified: _is_explicit_branch_session has no remaining callers after removal, and the new tests (nested branches, compression-after-branch) cover the tricky boundary cases well.
This branch has not been deployed
No deployments
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
comp/desktopElectron desktop app (apps/desktop/*)P2Medium — degraded but workaround existssweeper:risk-session-stateSweeper risk: may lose/corrupt/mis-associate session or context statetype/bugSomething isn't working
3 participants
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Why this remains needed after #86775
#86775 fixed direct branch resumes on
main, but its tip-only branch check still walks through the original parent after a branch is compressed. The result is a duplicated fork snapshot plus post-fork parent turns in the resumed continuation.This PR detects a branch boundary on each traversed edge. Inherited
_branched_fromprovenance on compression continuations is not treated as a new fork unless it names that row’s immediate parent.Regression coverage
Real
SessionDBtests cover:TDD evidence
main+ the regression file: 3 passed / 1 failed attest_compression_after_branch_replays_from_branch_boundary8 != 6)Validation
scripts/run_tests.sh tests/hermes_state tests/test_hermes_state.py -q→ 375 passed, 0 failed, 2 skippeduv run ruff check hermes_state.py tests/hermes_state/test_branch_replay_lineage.py→ cleanpython -m py_compile,git diff --check, and ancestry check against currentorigin/main→ cleanCloses #77375