mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-09 07:10:34 +01:00
## Thinking Path
> - Paperclip is the open source app people use to manage AI agents for
work.
> - A task chat queues a message while the agent is busy. The
queued-message bar shows a Send button when no turn is running.
> - Send calls `POST /issues/:id/queued-comments/interrupt` with no
target run.
> - The issue can hold an execution run that has not started yet
(`queued`) or that waits for a retry (`scheduled_retry`). The GET
response then shows a deferred queue with no target run, so the UI shows
Send.
> - The interrupt route refused that click with 409. The UI then showed
"Couldn't send. Message is still queued."
> - This pull request saves the click as interrupt intent in that state.
The queue is delivered when the previous run stops.
> - The benefit is that the button the UI offers now works, and the
message goes next.
## Linked Issues or Issue Description
**What happened?**
Cloud onboarding test, Codex subscription path (N-06): the tester
clicked Send in the onboarding task. The UI showed "Couldn't send.
Message is still queued."
**Expected behavior**
Send is accepted. The message stays in the queue and is delivered next,
when the previous run stops.
**Steps to reproduce**
1. Have an issue whose execution run is `queued` (not started) or
`scheduled_retry`.
2. Post a message. It is deferred behind that run.
3. Click Send on the queued message.
4. The route returns 409: "This queue does not support interruption"
(paperclip_runner) or "The previous run has not stopped" (legacy
adapters).
**Paperclip version or commit**
`master` at b68f69a801.
Root cause: `GET /queued-comments` resolves the target run from running
runs only, so the UI offers Send. `POST /queued-comments/interrupt`
locks `issue.executionRunId` at any status. It accepted only a terminal
run or no run. A queued or retry-waiting run fell between those two
rules.
Relation to other fixes: #19331 (declined connection receipt) changed
which wake the queue projects. It does not touch this check, and current
`master` still fails. The sibling N-07 problem (steering a queued
message on Codex) uses the `/steer` route. This PR does not change that
route. I found no shared cause.
Evidence limits: the tester's notes are the only evidence. The staging
company that I could read uses the Claude subscription path, so I could
not see the Codex run's status at the time of the click. The reproduced
state is the only server path that gives "Couldn't send" for a Send
click with no running turn. A slow-starting or retrying Codex run gives
that state.
## What Changed
- `server/src/routes/issues.ts`: the interrupt route no longer refuses a
Send when the issue's run is `queued` or `scheduled_retry`. For
paperclip_runner queues, a run that is not running is handled like a
stopped run. The legacy "previous run has not stopped" 409 is removed.
The route saves `queuedCommentInterrupt` intent, does not cancel the
not-yet-started run, and returns the queue in the `deferred` state. The
UI already shows "Messages are still queued. They will send when the
task is ready." for that response.
- `server/src/__tests__/issue-queued-comments-routes.test.ts`: new route
test for native and legacy queues, with `queued` and `scheduled_retry`
runs. It checks that GET offers Send, that the POST is accepted without
a run cancel, that the intent is saved, and that the queue is delivered
to one successor run after the previous run stops.
## Verification
Red, on `master` (new test, before the fix):
```
pnpm vitest run server/src/__tests__/issue-queued-comments-routes.test.ts -t "accepts Send while"
× accepts Send while the previous native run is queued and delivers it once that run stops
× accepts Send while the previous native run is scheduled_retry and delivers it once that run stops
× accepts Send while the previous legacy run is queued and delivers it once that run stops
× accepts Send while the previous legacy run is scheduled_retry and delivers it once that run stops
AssertionError: {"error":"This queue does not support interruption"}: expected 409 to be 200
AssertionError: {"error":"The previous run has not stopped"}: expected 409 to be 200
Tests 4 failed | 90 skipped (94)
```
Green, after the fix (same command):
```
Test Files 1 passed (1)
Tests 4 passed | 90 skipped (94)
```
Neighbouring suites:
- `server/src/__tests__/issue-queued-comments-routes.test.ts` (complete
file): 94/94 passed.
- `server/src/__tests__/agent-conversations.test.ts`,
`server/src/services/issue-queued-comment-queue.test.ts`,
`ui/src/components/task-chat/TaskChatQueuedMessages.test.tsx`: passed.
- When I ran the two embedded-Postgres route files in one Vitest
process, every test passed. Then the queued-comment file's `afterAll`
database cleanup timed out after 30 s, which is a local resource limit.
The file passes when it runs alone.
- `pnpm --filter @paperclipai/server typecheck`: passed.
- I made no UI changes, so I did not run `pnpm check:token-gates`.
## Risks
- Low risk. Send was refused only for `queued` and `scheduled_retry`
runs. Now that click is saved and the run is not cancelled. A running
turn is unchanged: paperclip_runner still steers it, and legacy still
interrupts it.
- When a run waits for a retry, a saved Send waits for that retry to
finish. The route does not skip the retry. This matches how the queue
already works for messages without a click.
## Model Used
- Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, in Claude Code with
tool use (shell, file edits, browser for read-only staging evidence).
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>