Skip to content

[Bug]: "Compact next" is selected on a stale Claude thread, but the send goes out uncompacted (desktop, v0.1.3) #27966

Closed as not planned

Description

@Coinsteamio

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/web (desktop composer), possibly apps/server

Steps to reproduce

  1. Settings: "Compact idle threads" = When you return (idleCompaction: "onReturn").
  2. Run a long Claude thread (claudeAgent, claude-opus-5-5) well past 200K tokens.
  3. Leave it idle about 4 hours, far past the prompt-cache TTL.
  4. Come back. The composer shows the Compact next pill (tooltip: "Next send compacts N tokens first").
  5. Leave it on Compact next and send an ordinary message.

Expected behavior

The send runs /compact first, then delivers the message on the compacted context.

Actual behavior

The message goes straight to the model on the full, uncached history. No compaction turn item is recorded for that run or for the turns after it. The only compaction in the thread is a manual /compact sent later.

Reproduced on two threads at the same time, on two separate environments of the same desktop install (a WSL server and a Windows server), so it is not specific to one thread or one environment:

Thread A (WSL env) Thread B (Windows env)
Previous run completed 2026-10-30 23:02:20Z 2026-10-30 23:01:18Z
Send with Compact next selected 2026-10-31 02:53:21Z (~3h51m idle) 2026-10-31 02:54:11Z (~3h53m idle)
Compaction before that run none (first assistant output 8 s later) none
Uncompacted runs before manual fix 3 2
First compaction in thread manual /compact, 03:07:55Z manual /compact, 03:07:41Z

Diagnosis

  • The client never dispatched the /compact. The effect outbox has exactly one provider-turn.start for each stale send (A: 02:53:21.647Z, B: 02:54:11.037Z), for the user's message only. Per Idle compaction is skipped when the server restarts, including for a desktop update, during the wait #27915, the "When you return" path normally dispatches /compact with idleCompaction: "onReturn" first and queues the message behind it. No such turn exists, so the compact-before-send step was skipped before anything reached the server. That points to the web composer's send path, not the server.
  • The full cost was paid. The Claude SDK result for each stale send shows the whole history re-written to the cache, with no compact_boundary in the session:
    • A: cache_creation_input_tokens: 615301, cache_read_input_tokens: 12825
    • B: cache_creation_input_tokens: 420385, cache_read_input_tokens: 18270
  • In both orchestration_v2_projection_runs rows, contextHandoffId is null and no compaction turn item exists for the run. The only compaction item in each thread belongs to the later manual /compact run.
  • The pill showed "Compact next", not "Keep full", at send time on both threads. Nothing was toggled between seeing the pill and pressing Enter.

Impact

Major degradation: the two sends together re-wrote over a million tokens to the cache, and the follow-up turns kept paying on the uncompacted context, while the UI said they would compact first.

Version or commit

Desktop + server 0.1.3 (Windows desktop, servers on Windows and on WSL). I checked the v0.1.4 and v0.1.5 release notes and found no fix for this path.

Environment

Windows 11 desktop app; one server on Windows, one on WSL2 (Ubuntu), both 0.1.3. Provider: Claude (claudeAgent).

Related, but not the same

Logs or stack traces

orchestration_v2_events had already been pruned for these threads; the outbox rows and provider logs above are what remains. I can share sanitized excerpts on request.

Activity

  1. juliusmarminge commented on Oct 31, 2026

    @juliusmarminge
    Member

    I tried this on current main (80a2351) with the web client and a Claude thread (claudeAgent), with "Compact idle threads" set to When you return. To get there in minutes, I lowered the client's stale-thread thresholds; the send path itself was unchanged. The server had already released the idle Claude session, so the next turn resumed it, as it would after 4 hours.

    • Same tab, open the whole time: the Compact pill appeared and I pressed Enter on an ordinary message. The thread recorded a /compact run (idleCompaction: "onReturn", compaction item completed), and then the message's run. Each had its own provider-turn.start.
    • Page reloaded on the stale thread, then send: same result. /compact ran first, then the message.

    So the composer does send /compact ahead of the message there. To find where it got lost on your two threads, could you share these rows for one of them, from the previous run's completion to the stale send (02:53Z on thread A)? Sanitized text is fine.

    1. orchestration_v2_projection_messages: any user message whose text is /compact, with its idleCompaction value and timestamp.
    2. orchestration_v2_projection_runs: every run in that window, with status, requested_at, completed_at, and its userMessageId. A /compact run that was stopped or failed before it reached the provider would never get a provider-turn.start.
    3. orchestration_v2_effect_outbox: every row for the thread in that minute (all effect_types, plus status and last_error), not only provider-turn.start.
    4. Did a "Resume session" question appear in the thread around the send? Was the queued message shown with a Steer option, and did anything get clicked?
  2. shivamhwp commented on Nov 11, 2026

    @shivamhwp
    Collaborator

    [Fable 5.2][Claude Code] on behalf of shivam.

    Closing this as not planned for now. It did not reproduce on main at 80a2351 on 2026-10-31. With "Compact idle threads" set to When you return, /compact ran before the message, both in a tab left open and after a reload.

    If it still happens on a current build, please reply here with the details asked for above and we'll reopen it.

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