Skip to content

[Bug]: Switching from an idle Claude thread to Codex still triggers automatic /compact #25943

Open

Description

@Alb11747

What happened

On a long, idle Claude thread, selecting Codex and sending a message can still trigger T3's Claude cold-cache resume compaction first. T3 hands off to Codex, sends an automatic /compact on Codex with idleCompaction: "onReturn", and queues the user's actual message behind it. The stale Compact next pill can remain visible after selecting Codex.

Expected: switching away from Claude sends the original message through the normal provider handoff, without inheriting Claude's automatic compaction recommendation. Deliberate manual /compact should remain available. Returning to a saved, long, cold Claude conversation should evaluate that destination conversation and offer compaction when eligible.

Diagnosis

The parent chat view and composer resolve provider selection differently:

  • ChatView.tsx uses the existing conversation's lockedProvider.
  • ChatComposer.tsx uses modelPickerLockedProvider, which permits provider selection when handoff is supported.
  • Consequently, after selecting Codex, the parent can continue supplying a Claude resume-compaction recommendation while the composer's live getSendContext() correctly reports Codex. This persists after rendering; a particular React race is not required.
  • planComposerTurn receives an unscoped resumeCompactionTokens count, without destination provider/conversation identity.
  • useComposerSend uses that recommendation to send /compact with the actual selected model, then queues the user's message.

This is the client-side onReturn path, separate from the before-cache-expiry idle timer.

Steps to reproduce

Reproduced in the full web AppRoot with an in-process mocked environment, using the affected source revision:

  1. Open a stopped thread whose saved native Claude conversation has 250k context tokens and last activity older than its prompt-cache TTL. Enable the existing on-return compaction behavior.
  2. Confirm that the composer offers Compact next.
  3. Select Codex using the normal provider/model picker.
  4. Observe that the compaction pill remains visible.
  5. Enter an ordinary message and send it.
  6. Inspect the outgoing turn dispatches: the first is automatic /compact on Codex; the second is the original message queued behind it.

No model calls or database are needed for this reproduction.

Version

Observed installation: 0.1.3-nightly.20261026.3717.fork.2, source commit 54aeb9ba2df2f3ffbe288f529f1229b5d409b8f0.

The deterministic browser reproduction used that source revision. These results are not a claim of reproduction against the latest upstream HEAD.

Environment

T3 Code web composer on a Linux-hosted fork server; native Claude Agent provider as the source and Codex as the selected destination. The isolated verification used mocked provider dispatch and no provider CLIs.

Evidence

Two user-supplied production activity sequences showed Claude-to-Codex handoff followed by automatic Codex compaction before the actual message. In one, on 2026-10-26 UTC, the unwanted compaction ran from approximately 19:26:39 to 19:28:43; the actual message started afterward. The preceding Claude run had ended at 18:10:54, with no intervening Claude run for this compaction.

Independently reproduced outgoing dispatches, with fixture message text:

Affected source, after selecting Codex:
1. text="/compact"
   instanceId=codex
   dispatchMode=start_immediately
   idleCompaction=onReturn
2. text="Verify provider handoff without automatic compaction."
   instanceId=codex
   dispatchMode=queue_after_active

Local fix, same selection:
1. text="Verify provider handoff without automatic compaction."
   instanceId=codex
   dispatchMode=start_immediately

Fix applied or workaround

A local fix aligns parent/composer selection, scopes the recommendation to the destination provider instance and saved conversation/context, hides mismatched suggestions, and revalidates immediately before dispatch after uploads/settings preparation. A refreshed or compacted conversation invalidates the old recommendation even when its conversation ID stays the same.

Validation completed:

  • 65 focused tests passed across ChatView.logic.test.ts, ContextWindowMeter.logic.test.ts, and useComposerSend.browser.test.tsx.
  • Regression tests failed before the relevant fixes. They cover stale parent Claude eligibility with live Codex selection; provider-instance/conversation mismatches; and conversation replacement, refreshed usage, or compaction while attachment upload is paused. Invalidated eligibility produces exactly one original message dispatch with its attachment and no forced compaction queue.
  • Controls cover intended same-Claude compaction, manual /compact, full-history opt-out, and warm/small context behavior.
  • An integrated mocked browser pass confirmed that Claude-to-Codex hides the pill and sends directly, while Codex-to-saved-cold-Claude shows the pill and retains the intended compaction/message sequence.
  • vp run check:changed checks passed, including formatting, lint, knip, affected typechecks, and the focused tests.
  • Two independent Codex reviews found send-preparation freshness gaps; both findings were addressed with regression coverage.

The proposed fix is now published on the fork's check branch: f2313c83895b1dfa4a305710e0c67c73f7cb5b06. After rebasing onto the fork containing upstream nightly v0.1.4-nightly.20261027.3770, all 63 current focused tests and vp run check:changed passed, and an independent Codex integration review approved the result. The earlier 65-test result above describes the original source baseline; upstream removed two existing cases. Exact-commit fork checks passed on c3f2943bafcdf5ad683dde3870ae4619889ba654, which includes the compaction fix plus a separate compatibility fix for an existing Git diagnostic failure in server cleanup. Both commits are now on fork main. Combined local checks passed 185 tests. The current-main fork release build passed all required checks and published 0.1.4-nightly.20261027.3770.fork.2, from descendant commit 311003447f01db2a2548b1661e638e462b91fac7, which includes this fix. Upstream PR: #26142 — scope resume compaction to the selected provider conversation. Its current upstream-only head bc2ce013fdf27d591919c8cc52d5b8d1f022fe50 also fixes optimistic queue display and anchoring after compaction becomes stale during preparation. All 65 focused tests, local checks, and all exact-commit CI jobs pass on this head. The preceding head 1fe0a60 passed all exact-commit CI jobs. Public before/after screenshots are attached in the PR. Installation and post-update runtime verification are still pending. Verification establishes client UI/dispatch behavior with mocked providers, not post-install execution against a paid model. No live database writes or paid model calls were used for verification.

Related issues

#23086 concerns switching back to a Claude provider instance and evaluating its own larger, cold saved context. That destination-scoping concern is related, but this report isolates the opposite failure: a stale Claude recommendation causes automatic compaction on a newly selected Codex destination.

This report does not infer billing amounts or quota consumption.

Filed by

GPT-6.1 Sol through the Codex harness in T3 Code. Investigation and independent reviews used OpenAI/Codex models only; the t3 triage launcher was not run.

Activity

  1. Alb11747 commented on Oct 27, 2026

    @Alb11747
    ContributorAuthor

    Proposed upstream fix: PR #26142.

    The PR contains only the provider-scoped resume-compaction repair and its regression tests. It includes before/after screenshots and the reverse Codex-to-cold-Claude control. All 63 focused tests and exact-commit fork CI passed on 1fe0a60a58fcbb11e3f52663abf06ef91a9bdf98. No maintainer approval or post-install live-provider verification is claimed.

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions