Feature proposal: speculative pre-turn compaction for long-context sessions

Open 💬 2 comments Opened Jun 25, 2026 by NaxAlpha

Problem

Auto-compaction currently runs when Codex is already at the compaction threshold. For long sessions, this can make the next turn stall while Codex performs a full compaction request synchronously.

I would like to propose a conservative speculative-compaction design: prepare a compacted summary in the background once a thread crosses an earlier threshold, then install it later only if it is still valid.

Proposed behavior

When a completed turn crosses a configurable precompute threshold, Codex starts a background remote-v2 compaction for the frozen history prefix.

Later, when normal pre-turn auto-compaction would run, Codex can install the prepared result instead of waiting for a new compaction request.

If the prepared result is stale, incomplete, failed, too large, or not applicable, Codex should fall back to the existing synchronous compaction path.

Suggested initial scope

Keep the first version intentionally narrow:

  • pre-turn auto-compaction only
  • remote compaction v2 only
  • default off behind an under-development feature flag
  • no mid-turn speculative install
  • no token-budget reset mode change
  • no user-visible history rewrite outside the existing CompactedItem / replace_compacted_history path

This avoids changing the current mid-turn compaction invariants, where replacement-history placement is more sensitive.

Safety / correctness checks

A prepared compaction result should only be installed when:

  • the current context window id still matches
  • the model/provider/compaction hash still match
  • the current history still starts with the exact frozen prefix
  • the replacement history estimate remains under the relevant auto-compact limit
  • pre-compact hooks allow installation

Otherwise, fallback should use the current compaction behavior.

Possible config shape

[features.speculative_compaction]
enabled = true
trigger_ratio = 0.75
install_wait_ms = 100

trigger_ratio would apply to the existing auto-compact limit. For example, if auto-compaction is configured around 80% of the context window, 0.75 prepares around 60%.

Why this seems aligned with the current code

The current code already has the needed primitives:

  • token status calculation in session/context_window.rs
  • auto-compaction dispatch in session/turn.rs
  • remote-v2 compaction request/build path in compact_remote_v2.rs
  • durable replacement through Session::replace_compacted_history
  • context-window IDs in AutoCompactWindow
  • session-owned background task precedent in session_startup_prewarm.rs

The proposal should reuse those instead of introducing a parallel transcript-rewrite path.

Tests that should cover the change

  • precompute starts after threshold crossing without emitting compact lifecycle events
  • prepared result is consumed by the next pre-turn compaction
  • stale prefix falls back to normal compaction
  • failed background compaction falls back
  • replacement estimate over limit falls back
  • mid-turn compaction ignores speculative result
  • hooks run only during actual install
  • persisted replacement history resumes correctly

Related context

This proposal is related to context/compaction performance and reliability issues, but is narrower than changing compaction quality or compaction prompts generally.

Related issues that seem adjacent:

  • #27545: auto-compact fires post-sampling causing inflated token costs
  • #29356: context compaction loses operational continuity in long tasks
  • #29816: additive compaction guidance without overriding the built-in prompt
  • #29947: context burn remains high after compaction/new session

Maintainer questions

  • Should this be a new feature flag, or should it live under an existing compaction/token-budget feature?
  • Is remote-v2-only acceptable for the first implementation?
  • Would telemetry for prepared/used/stale/failed/fallback outcomes be required before considering this behavior?

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗