fix(queue): send selected held messages when a thread is stopped#22790

merged1
main
t3/investigate-queue-steer-failure
opened22d agobyYYash-Singh1
View on GitHubTwo-way sync enabledPR last imported 22d ago

Problem

After a thread stops with queued messages held, users cannot steer a message to restart the thread. The steer control is disabled because there is no active turn, and resuming the queue would start the first queued message instead of the one the user selected.

Change

Add a command to start a selected queued message while the thread is stopped. Keep the remaining messages queued in their existing order. Show Send now for stopped threads and retain Steer for running threads across web, desktop, and mobile. Update the web keybinding to use the selected-message behavior in either state.

Scope and approval

This is a focused fix for the queue control becoming unavailable after a thread stops. The shared command, server handling, and client controls are all needed to send the selected message on each supported client. The regression test selects the middle message in a held queue and confirms that it starts first while the other messages keep their order.

Verification

The focused server regression tests passed, including the race case where a send-now request arrives while a turn is running. Focused client and mobile tests passed, as did scoped typechecks for the server, contracts, mobile, and client runtime. Lint reported two warnings in changed files. No live browser or device verification was performed.

Checks

23 successful · 9 skipped · 1 neutral
All checks passed
7b48ba2

Added 1 commit

  • fix(queue): send selected held messages when a thread is stopped7b48ba2
Synced from GitHub

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval — This PR introduces a new cross-layer workflow for selecting and immediately starting a held queued message, including a new orchestration command and UI behavior on web and mobile. The runtime and queue-state impact extends beyond a small isolated fix.

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

Synced from GitHub

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire5.0 KiB5.0 KiB0 B (0.0%)6.8 KiB✅
CodexThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiB✅
CodexLive turn WebSocket wire1.2 KiB1.2 KiB0 B (0.0%)2.0 KiB✅
CodexLive turn WebSocket decoded20.9 KiB20.9 KiB0 B (0.0%)29.3 KiB✅
CodexLive turn messages220 (0.0%)8✅
ClaudeTotal thread wire5.0 KiB5.0 KiB−7 B (−0.1%)6.8 KiB✅
ClaudeThread snapshot wire3.8 KiB3.8 KiB0 B (0.0%)4.9 KiB✅
ClaudeLive turn WebSocket wire1.2 KiB1.2 KiB−7 B (−0.6%)2.0 KiB✅
ClaudeLive turn WebSocket decoded21.2 KiB21.2 KiB0 B (0.0%)29.3 KiB✅
ClaudeLive turn messages220 (0.0%)8✅

Baseline: 1dfb572 · PR result: 7b48ba2 · 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. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Team
  • Run ID: abe43717-9ca5-4611-8853-44a8839a02e0
📥 Commits

Reviewing files that changed from the base of the PR and between 1dfb57287174230e5c386e452f54bb0cce2fc32f and 7b48ba2f733957c0635536e1cec496fb714ec9e1.

📒 Files selected for processing: 14
  • apps/mobile/src/features/threads/ThreadQueueControl.tsx
  • apps/mobile/src/features/threads/threadQueueControlPresentation.test.ts
  • apps/mobile/src/features/threads/threadQueueControlPresentation.ts
  • apps/server/src/orchestration-v2/Orchestrator.ts
  • apps/server/src/orchestration-v2/SteeringCompletion.integration.test.ts
  • apps/server/src/orchestration-v2/testkit/OrchestratorScenario.ts
  • apps/web/src/components/chat/QueuedRunsControl.tsx
  • apps/web/src/components/settings/KeybindingsSettings.logic.ts
  • packages/client-runtime/src/operations/commands.test.ts
  • packages/client-runtime/src/operations/commands.ts
  • packages/client-runtime/src/state/threadCommands.ts
  • packages/client-runtime/src/state/threadWorkflows.test.ts
  • packages/client-runtime/src/state/threadWorkflows.ts
  • packages/contracts/src/orchestrationV2.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 change adds a targeted command to start a selected queued message when no run is active. Workflow state and mobile and web controls expose that option. When a run is active, controls retain the existing promotion-to-steer path.

Changes: Queued message sending

Layer / File(s)Summary
Workflow availability and command contract
packages/contracts/src/orchestrationV2.ts, packages/client-runtime/src/state/threadWorkflows.ts, packages/client-runtime/src/state/threadWorkflows.test.ts, packages/client-runtime/src/operations/commands.ts, packages/client-runtime/src/operations/commands.test.ts, packages/client-runtime/src/state/threadCommands.ts
ThreadQueueWorkflowState now exposes canSendNow when no run is active and the thread is not archived or deleted. resumeThreadQueue accepts an optional run ID and dispatches queued-run.start when present, or queue.resume otherwise.
Server handling of targeted starts
apps/server/src/orchestration-v2/Orchestrator.ts, apps/server/src/orchestration-v2/SteeringCompletion.integration.test.ts, apps/server/src/orchestration-v2/testkit/OrchestratorScenario.ts
The orchestrator validates targeted starts, selects the requested queued run, and carries its ID through promotion, replay, and failure handling. Integration tests cover restart recovery, duplicate starts, and rejection while a provider turn is running.
Mobile and web send controls
apps/mobile/src/features/threads/ThreadQueueControl.tsx, apps/mobile/src/features/threads/threadQueueControlPresentation.ts, apps/mobile/src/features/threads/threadQueueControlPresentation.test.ts, apps/web/src/components/chat/QueuedRunsControl.tsx, apps/web/src/components/settings/KeybindingsSettings.logic.ts
Mobile and web controls allow immediate sending when available and retain steer promotion when applicable. Mobile row controls use canSend and test busy and editing states. The keybinding label no longer says “as Steer”.

Priority: ➖ Normal

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

Change: Bug fix

Sequence Diagram(s)

mermaid
1sequenceDiagram
2 participant QueuedRunsControl
3 participant resumeThreadQueue
4 participant Orchestrator
5 participant startNextQueuedRun
6 QueuedRunsControl->>resumeThreadQueue: Send selected queued message
7 resumeThreadQueue->>Orchestrator: Dispatch queued-run.start with runId
8 Orchestrator->>startNextQueuedRun: Promote the selected queued run

Suggested reviewers: juliusmarminge

Merge Risk: ⚪ Minimal · up to 7b48b

The selected-message send path has no identified issue requiring a fix before merge; normal checks remain appropriate.

Pre-merge checks: Passed 4
Check nameStatusExplanation
Title checkPassedThe title clearly and concisely describes the main change: sending a selected held queue message when a thread is stopped.
Description checkPassedThe description covers the problem, implementation, scope rationale, verification results, lint warnings, and unperformed browser or device checks. It is mostly complete and aligned with the template.
Linked Issues checkPassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes checkPassedCheck skipped because no linked issues were found for this pull request.
✨ 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

Comment @coderabbitai help to get the list of available commands.