Title: Forking a compacted session re-injects discarded history and overflows the context window
Steps to reproduce
- Run a long session until auto-compaction fires (history is moved to a closed context window).
- Fork the session from any message.
- Send a new message in the forked session.
Actual behavior
The first LLM request in the fork contains the full pre-compaction history. Compaction is silently undone, and the payload can exceed the model's context window.
Expected behavior
The fork should contain only the current context window (the compacted summary and messages after it), like the parent session sees.
Root cause
forkSession (src/server/session/manager.ts) copies messages by index and rewrites every message's contextWindowId to the fork's new window. Compaction keeps old messages in state and isolates them only by window id, so this remap turns discarded history into "current window" messages. Context building trusts the window id, so everything is re-injected. The fork also resets contextState (tokens = 0, canCompact = false) and drops context.compacted events, so no protective compaction fires and compaction history is lost.
Why it went unnoticed
For non-compacted sessions all messages share one window, so the remap is a no-op and forks work fine. The bug only triggers after a compaction.
Introduced in: v2.0.89 (PR #166, 1f54d6aa) · Still present in: v2.0.143
Title: Forking a compacted session re-injects discarded history and overflows the context window
Steps to reproduce
Actual behavior
The first LLM request in the fork contains the full pre-compaction history. Compaction is silently undone, and the payload can exceed the model's context window.
Expected behavior
The fork should contain only the current context window (the compacted summary and messages after it), like the parent session sees.
Root cause
forkSession(src/server/session/manager.ts) copies messages by index and rewrites every message'scontextWindowIdto the fork's new window. Compaction keeps old messages in state and isolates them only by window id, so this remap turns discarded history into "current window" messages. Context building trusts the window id, so everything is re-injected. The fork also resetscontextState(tokens = 0, canCompact = false) and dropscontext.compactedevents, so no protective compaction fires and compaction history is lost.Why it went unnoticed
For non-compacted sessions all messages share one window, so the remap is a no-op and forks work fine. The bug only triggers after a compaction.
Introduced in: v2.0.89 (PR #166,
1f54d6aa) · Still present in: v2.0.143