Skip to content

feat(operations): quota-independent context planning with deterministic shrink #24

Closed

Description

@Juliusolsson05

Motivation

planConversationContext returns requires-portable-handoff whenever the latest compaction is native-only (Codex encrypted compacted record) and the target is another provider, regardless of size, and requires-compaction whenever the effective history exceeds the target budget. Both outcomes demand a live turn on the source provider. When the source has exhausted its subscription window, that turn cannot happen, so exactly the sessions that most need switching cannot switch. A census of the last 300 local Codex rollouts shows 146 with a compacted record.

The raw pre-compaction records remain on disk in plaintext for both providers; only Codex's summary is encrypted (server-held key, no client-side decryption exists in codex-rs). Anthropic's context editing and OpenAI's own Claude-session importer both shrink transcripts deterministically (clearing or narrating tool results) without a model call.

Intended behavior

  • planConversationContext(conversation, target, budget, { allowSourceTurns: false }) never returns a plan that needs a source turn. New outcomes: raw-history (native-only compaction entries dropped, raw entries fit) and shrunk (deterministic shrink applied; carries a report), plus a hard unfittable error only when the last complete user turn alone exceeds the budget.
  • New isolated module operations/shrink.ts: strip native-only compactions → clear tool results oldest-first (bounded placeholder, keep recent turns intact, edit inputs preserved) → drop oldest complete user turns with a synthetic compaction entry that indexes the dropped prompts. Pure, reported, no provider names inside.
  • compactionAvailability returns rejected for a Claude carrier whose text starts with a rate-limit prefix (You've hit your, You've used, You're now using extra usage, You're close to, You're out of extra usage). Hosts must never accept such a record as a portable summary.
  • Claude assistant records with isApiErrorMessage: true decode as opaque entries instead of assistant messages, so a limit error is never projected into the target as model output.
  • Existing outcomes and the default allowSourceTurns: true behavior are unchanged.

Acceptance criteria

  • Unit tests run against redacted real fixtures extracted with the existing observed-fixture tooling: a Codex rollout with one and with several compacted records, a Claude transcript with a compact boundary, a Claude transcript containing a rate_limit API error record, and an oversized transcript for the shrink ladder.
  • Structural projection tests prove Claude and Codex native projectors accept cleared tool results and the synthetic drop marker.
  • The live resume probe gains a shrunk-projection case (opt-in, real headless resume with a read-only marker prompt).
  • No change to any provider's native persistence rules in docs/design/provider-switching.md other than the new planner outcomes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions