fix(state): stop delegate/tool children corrupting compression lineage - #79193
Merged
kshitijk4poor merged 1 commit intoAug 5, 2026
Merged
Conversation
kshitijk4poor
enabled auto-merge (rebase)
August 5, 2026 08:13
kshitijk4poor
disabled auto-merge
August 5, 2026 08:14
get_compression_lineage's forward walk accepted any non-branch child as the compression continuation. Delegate subagent rows (_delegate_from) and tool-tagged rows (source=tool) created before the real continuation were picked as the lineage successor, so the lineage — and session .md export built on it — followed a subagent's transcript instead of the actual conversation continuation. Rename _is_branch_child_row to _is_explicit_fork_child_row, treat _delegate_from and source=tool rows as explicit forks alongside _branched_from, and require _is_compression_child_row in the forward walk instead of merely excluding branches. Sliced from PR NousResearch#79024 by @RyderFreeman4Logos (the cache-scope portion of that PR is tracked separately in NousResearch#79017).
kshitijk4poor
force-pushed
the
fix/79024-lineage-fork-children
branch
from
August 5, 2026 08:16
829cf6a to
86ff5f6
Compare
kshitijk4poor
enabled auto-merge (rebase)
August 5, 2026 08:16
kshitijk4poor
added a commit
that referenced
this pull request
Aug 15, 2026
…ation Legacy compaction mode (compression.in_place: false) rotates the physical session_id mid-conversation. The prompt-cache scope introduced in #79161 was derived from that physical id, so every rotation moved the same conversation into a fresh cache bucket - the prompt cache went cold at every rotation boundary (#79017). Fix: resolve a rotation-stable logical scope - the compression-lineage ROOT of the current session (SessionDB.get_compression_lineage, fork-aware post-#79193) - once per turn, memoized per transcript segment, and prefer it over the physical session_id at every prompt_cache_key derivation site: - agent/prompt_cache_scope.py (new): resolve_prompt_cache_scope(agent) - lineage-root walk with per-segment memo; falls back to the physical id when no DB is attached or the walk fails, degrading to pre-fix behavior. - transports/codex.py: build_kwargs accepts cache_scope_id and prefers it for the body prompt_cache_key, the xAI x-grok-conv-id header, and the Codex x-client-request-id routing header. The Codex session_id header keeps the raw physical id (transcript identity, #57012 contract). - transports/chat_completions.py: _add_prompt_cache_key accepts cache_scope_id with the same precedence. - chat_completion_helpers.py: build_api_kwargs threads the resolved scope into all three build_kwargs call sites (codex, profile, legacy). - auxiliary_client.py: set_runtime_main carries cache_scope; the aux Responses cache-key site prefers it over the physical session_id. - turn_context.py: resolves the scope once per turn and threads it through set_runtime_main (no DB walk on the per-API-call hot path). Scope semantics preserved from #79161: /new starts a fresh scope (new lineage), /branch children, delegate subagents, and tool children stay isolated (explicit-fork exclusion in get_compression_lineage), unrelated sessions keep distinct buckets, and cron per-fire timestamps still normalize via _cache_scope_from_session_id. Default installs compact in place (session_id never rotates), so they hit the memo and produce byte-identical keys to before. Fixes #79017
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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
Delegate and tool child sessions no longer corrupt a conversation's compression lineage — session
.mdexport now follows the real continuation instead of a subagent's transcript.Root cause:
get_compression_lineage's forward walk accepted any non-branch child of a compressed session as the compression continuation. A delegate subagent (_delegate_from) or tool-tagged (source="tool") child created before the real continuation row — the common runtime ordering, since the subagent exists before compression rotates the session — was picked as the lineage successor.Context (real-world impact)
Reproduced on current
main: a CLI session that spawns a delegate child and then compresses exports the delegate's private transcript as its continuation:Anyone using
/export(or anything built onexport_session_lineage/get_compression_lineage) on a session that delegated work before compressing gets the wrong transcript today.Changes
hermes_state.py: rename_is_branch_child_row→_is_explicit_fork_child_row; treat_delegate_fromandsource="tool"rows as explicit forks alongside_branched_from; the forward walk now requires_is_compression_child_rowinstead of merely excluding branches.tests/hermes_state/test_session_md_export.py: extend the lineage test with delegate/tool isolation asserts; new regression test for the fork-child-before-continuation ordering including export content (mutation-checked — fails onmain, passes with the fix).Validation
hermes_state.py, passes with fixSliced from #79024 by @RyderFreeman4Logos — cherry-picked with authorship preserved. The prompt-cache-scope portion of that PR is a design question tracked in #79017 (alongside #78956) and is intentionally not included here.