fix(muse): a declined /compact reports its reason and no longer wedges the thread#28454

merged9
main
fix/issue-28436
opened9d agobyJJulius Marminge
View on GitHubTwo-way sync enabledPR last imported 2d ago

Problem

On a Muse thread, a /compact that the Muse host refuses at admission (for example session/compact … rejected: run_active while a background wake run is active) showed the generic "Provider turn failed." instead of the host's reason. The next ordinary message then failed with "Provider turn recovery failed — This Muse turn is no longer active", and so did every message after it, so the thread was wedged.

Change

  • A declined compaction ends its own turn. When session/compact is rejected, returns noop, or returns a status the adapter does not know, the adapter ends the compaction turn as failed and reusable, with the host's reason. compactThread then succeeds, the same way the existing noop path already did. The server previously treated the rejection as a start failure: it stopped reading the adapter's events, recorded the generic message, and left the provider turn stored as running. compactThread still fails when the request broke the host, for example on a timeout.
  • A compaction leaves a running background wake alone. A /compact sent while Muse runs a background wake no longer takes that wake over, so the wake stays held for its own continuation instead of losing its output when the host declines the compaction. While a wake is held, a compaction item that names the wake's run still ends the compaction, because Muse compacts the latest run. Stopping a compaction, which closes the host, drops the held wake with it.
  • Recovering an ended turn succeeds. interruptTurn with requestRuntimeRestart (the server's recovery of an abandoned turn, and Stop) now returns successfully when no Muse turn is active and no Muse background work remains (no observed subagents and no held wake run). This matches the Codex, Claude, Cursor and Pi adapters. While background work remains, it keeps failing as before, because the adapter cannot stop that work and reporting success would mark it stopped.

Scope and approval

Fixes pingdotgg/t3code#28436

Verification

Focused tests in packages/provider-muse/src/server/adapter.test.ts, using the adapter's fake Muse host:

  • reports a compaction rejected at admission on its own terminal: a session/compact rejected with run_active yields a failed, reusable terminal that contains run_active, and the next turn starts. Fails on main.
  • treats recovering an already ended turn as done: recovery of an ended turn succeeds and the next turn starts. Fails on main with "This Muse turn is no longer active".
  • does not acknowledge Stop on an ended turn while a background subagent runs: guards the narrowed condition. It would fail with an unconditional no-op.
  • keeps a running wake held when Muse declines compaction: after a rejected compaction the wake is still pending and Stop does not report it stopped. Fails on main.
  • ends a compaction whose item names the held wake as its run: the compaction completes and the wake stays pending. Fails on main, where the wake is dropped.
  • drops a held wake when Stop closes the compacting host: after Stop, no background work is reported and the wake's continuation no longer dispatches.

Test transcript (base 575579d68a adapter against the new tests, then the branch head):

text
1## Before: adapter.ts at main 575579d68a, tests at f91f8cff62
2 × ends a compaction whose item names the held wake as its run
3 × keeps a running wake held when Muse declines compaction
4 × reports a compaction rejected at admission on its own terminal
5 × treats recovering an already ended turn as done
6ProviderAdapterProtocolError: muse provider protocol error: Muse session/compact failed: command rejected: run_active.
7Caused by: ProviderAdapterProtocolError: muse provider protocol error: This Muse turn is no longer active.
8 Tests 4 failed | 2 passed | 40 skipped (46)
9
10## After: fix/issue-28436 at f91f8cff62
11 Tests 46 passed (46)

vp run check:changed passes: format, lint, knip, typecheck (10 packages), tests.

Not checked: Muse Code cannot run in our verification environment, so the change has not been exercised against a live Muse host. The separate ~30-minute hang, where the host fails compaction (InvalidTarget) without emitting a terminal compaction item, is not addressed here.

No UI change. This is a server-side adapter fix, so there are no captures.

Model and harness: Claude Opus 5.5 (lead, red tests, implementation) and GPT-6.1-Sol (review) in Claude Code and Codex, orchestrated through T3 Code.

🤖 Generated with Claude Code

Checks

25 successful · 16 skipped
All checks passed
f91f8cf

Added 9 commits

  • fix(muse): a compaction item for the held wake's run ends the compaction1a5c1b7
  • test(muse): reproduce rejected compaction wedging the thread (#28436)6fa979e
  • fix(muse): stopping a compaction drops the held wake with its host80ecbc9
  • fix(muse): rejected /compact no longer wedges the thread88ba791
  • fix(muse): a declined compaction keeps the running wake held97f41ed
  • Merge remote-tracking branch 'origin/main' into fix/issue-284369f4fa4b
  • test(muse): Stop keeps failing while a Muse subagent outlives its turnd45ce36
  • fix(muse): keep Stop's error while Muse background work remainsdb7a539
  • test(muse): assert the optional continuation dispatcher existsf91f8cf

[gpt-6.1-sol][Codex] on behalf of shivam.

Handing over our independent findings for https://github.com/pingdotgg/t3code/issues/28436. On main 575579d68ac4bae09f8426a345d4a3eac1e90c67, an injected typed compaction admission rejection makes compactThread throw after queuing its detailed failed terminal. The start-error fallback then reads Provider turn failed. Our adapter runtime also confirmed compaction being sent while a background wake remained active. These are synthetic SDK-host reproductions, not a live Muse run.

Our overlapping work is https://github.com/pingdotgg/t3code/pull/28455 at 5898ff16d25aaeefbfdf99591ba19ebb7aa66319. Its attached evidence shows the before/after runtime, 99 passing Muse package tests, and passing changed-file checks on Boat, including 46 focused tests and affected-package typechecks. Coverage includes both rejection/completion orderings, fresh retry command IDs, cancelling a waiting compaction without losing wake ownership or output, and stale resume activity. The final independent review had no open findings. We have stopped testing and pushing now that your PR owns the issue.

The accepted-compaction InvalidTarget case with no terminal item remains unverified and unfixed in our work. Neither corex nor shiv has a native Muse CLI available for checking Muse 1.4.14; that case still needs a sanitized host wire trace or an upstream fix.

Thanks for the handover. I compared it with #28455 at 5898ff16d2. Both PRs make the same two routing changes: a compaction does not adopt a held wake, and a compaction item that names the wake's run ends the compaction.

This PR keeps the smaller shape. When Muse declines a compaction (run_active, noop, or an unknown status), it fails promptly on the turn's own terminal with the host's reason. It does not wait for the session to go idle and retry. Queuing compaction behind a running wake, as #28455 does, is a separate decision, so it is left out of scope here.

The accepted-compaction InvalidTarget case with no terminal item is still open here too.

Synced from GitHub

Approvability

Verdict: Approved at f91f8cf

Macroscope's review found this PR approvable — Declined Muse compaction now reports its reason and releases the active turn without discarding held continuation work. The changes are confined to compaction and recovery lifecycle handling, with no product-default changes or obvious material risk.

You can add or adjust custom eligibility rules. Learn more.

Synced from GitHub

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ℹ️ The exact PR base did not have a successful artifact. Baseline uses the latest successful main measurement shown below.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire5.0 KiB5.0 KiB+29 B (+0.6%)6.8 KiB✅
CodexThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiB✅
CodexLive turn WebSocket wire1.2 KiB1.2 KiB+29 B (+2.3%)2.0 KiB✅
CodexLive turn WebSocket decoded21.5 KiB21.6 KiB+41 B (+0.2%)24.4 KiB✅
CodexLive turn messages12+1 (+100.0%)8✅
ClaudeTotal thread wire5.0 KiB5.0 KiB0 B (0.0%)6.8 KiB✅
ClaudeThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiB✅
ClaudeLive turn WebSocket wire1.3 KiB1.3 KiB0 B (0.0%)2.0 KiB✅
ClaudeLive turn WebSocket decoded21.9 KiB21.9 KiB0 B (0.0%)24.4 KiB✅
ClaudeLive turn messages220 (0.0%)8✅

Baseline: 575579d · PR result: f91f8cf · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 108.5 KiB
  • Claude decoded thread snapshot: 108.8 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

Synced from GitHub

Review in Change Stack →

No actionable comments were generated in the recent review.

External image Recent review info
External image Run configuration
External image Commits

Reviewing files that changed from the base of the PR and between 8b74a69019e3d0f5be62dc118c526669002fc195 and f91f8cff625c55f92e0a3facdace5947eeca39f4.

External image Files selected for processing: 2
  • packages/provider-muse/src/server/adapter.test.ts
  • packages/provider-muse/src/server/adapter.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Walkthrough

The Muse adapter changes compaction failure handling and held-wake behavior. It also updates interruption and Stop handling for completed turns and background work.

Changes: Muse turn lifecycle

Layer / File(s)Summary
Compaction and held-wake handling
packages/provider-muse/src/server/adapter.ts, packages/provider-muse/src/server/adapter.test.ts
Compact turns retain held wakes and route their compaction items to compact-turn handling. Declined, unsupported, and failed compaction requests now follow explicit failure handling. Tests cover admission rejection, wake retention, compaction completion, and Stop during compaction.
Interruption after turn completion
packages/provider-muse/src/server/adapter.ts, packages/provider-muse/src/server/adapter.test.ts
An interrupt with runtime restart succeeds when no turn, observed children, or held wake remain. Tests cover interruption after a completed turn and Stop while background work remains pending.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: t3dotgg

Merge Risk: External image Minimal · up to f91f8

No actionable merge-blocking issue remains; merge after normal checks.

Pre-merge checks: Passed 3 · Failed 1

Failed Failed checks: 1 warning

Check nameStatusExplanationResolution
Linked Issues checkWarningIssue #28436 requires three coding outcomes: prompt success or the host failure reason, queuing compaction while the session is busy, and a reusable thread after failure. This PR implements the failur…Handle a compaction request that produces no terminal compaction item so it completes promptly with the host error. Queue or otherwise defer compaction while an active or wake run is busy, then dispatch it when the session is idle. Add auto…
Passed Passed checks: 3 passed
Check nameStatusExplanation
Title checkPassedThe title clearly and concisely describes the main Muse compaction fix and its effect on thread recovery.
Description checkPassedThe description includes Problem, Change, Scope and approval, and Verification sections. It explains the failure, implementation, focused tests, test results, limitations, and lack of UI changes. The …
Out of Scope Changes checkPassedThe adapter changes and tests are directly connected to issue #28436. They preserve held wake state after a declined compaction, complete compaction items for held wake runs, clear held wakes when Sto…
Full details: Description check

Explanation

The description includes Problem, Change, Scope and approval, and Verification sections. It explains the failure, implementation, focused tests, test results, limitations, and lack of UI changes. The linked issue provides scope context.

Full details: Out of Scope Changes check

Explanation

The adapter changes and tests are directly connected to issue #28436. They preserve held wake state after a declined compaction, complete compaction items for held wake runs, clear held wakes when Stop closes the host, and allow recovery after an ended turn. These changes support the issue's compaction failure and thread recovery behavior. No unrelated UI or provider changes are shown.

Full details: Linked Issues check

Explanation

Issue #28436 requires three coding outcomes: prompt success or the host failure reason, queuing compaction while the session is busy, and a reusable thread after failure. This PR implements the failure reason and reusable-turn behavior. The new tests cover admission rejection, held wakes, and ended-turn recovery. However, the PR description states that the InvalidTarget case with no terminal compaction item remains unaddressed, so that compaction can still hang. The adapter still sends compaction without waiting for an active or wake run to finish, so the busy-session queue requirement is not met.

Resolution

Handle a compaction request that produces no terminal compaction item so it completes promptly with the host error. Queue or otherwise defer compaction while an active or wake run is busy, then dispatch it when the session is idle. Add automated tests for both requirements.

Finishing Touches
Generate docstrings
  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts