paperclip/server/src
Dotta bf95a7eae2
fix(ui): stabilize active-run steering queue (#12834)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - The issue detail page shows a live agent run and accepts follow-up
instructions.
> - A follow-up must stay in a stable queue until the user sends,
reorders, or removes it.
> - Native runners can receive a steering event in the active run.
> - Legacy runners must interrupt the active run and start a follow-up
run.
> - The current UI moved comments between the queue and the transcript
and could show duplicate text or ambiguous chronology.
> - This pull request makes the queue projection durable, keeps each
message in one clear place, and labels when queued input was actually
steered or delivered.
> - The benefit is predictable steering with stable ordering, no
duplicate messages, and visible causal timing.

## Linked Issues or Issue Description

Refs #11374.
Refs #12591.

**What happened?**

During an active run, a new follow-up could first appear as a transcript
bubble and then move into the steering queue. After a steer or remove
action, it could appear again. Progress text could also repeat the final
response text. Once consumed, a queued bubble displayed only its
original submission time even though it moved to its later causal slot,
and a native run split by steering looked like two unrelated runs.

**Expected behavior**

An active-run follow-up must appear in the queue immediately. A native
steer must move it once into the active run. A legacy interrupt must
move it once into the follow-up run. A removed item must stay removed.
Progress text that is identical to the final response must appear once.
Consumed follow-ups must show both queue and steer/delivery times, and
post-steer native segments must identify themselves as continuations of
the same run.

**Steps to reproduce**

1. Start a long-running task.
2. Send two or more follow-up messages while the agent is active.
3. Reorder the messages and remove one message.
4. Send the first queued message as steering.
5. Observe the queue and transcript during and after both runs.

**Paperclip version or commit**

The problem reproduced on commit `da1e40302`.

**Deployment mode**

Local development with the embedded database.

## What Changed

- Project queued comments into the steering well for native and legacy
live runners.
- Send native steering to the active run and use interrupt-and-follow-up
for legacy runners.
- Keep optimistic queue order stable across refreshes and roll back
failed actions.
- Remove discarded comments from the transcript cache and keep them
removed when the queue becomes empty.
- Collapse only the final progress occurrence matching the durable
response, including across steered transcript segments.
- Show `Queued … · Steered …` for same-run input and `Queued … ·
Delivered …` for successor-run input at their causal positions.
- Label settled and live post-steer segments `Continued after steering`
and time them from the steer boundary.
- Add regression tests for queue display, steering, fallback interrupt,
reorder, remove, rollback, duplicate text, causal timestamps, and
live/settled continuation headers.

## Verification

- Ran the final focused steering/chronology UI suite with 233 passing
tests.
- Ran the activity-service regression suite with 5 passing tests.
- Ran the broader queue-focused UI suite with 298 passing tests before
the final chronology refinement.
- Ran `pnpm -r typecheck` successfully.
- Ran `pnpm build` successfully.
- Ran `pnpm check:token-gates` successfully.
- Tested native steering in a real browser with a 90-second baseline
wait and a three-second steering correction.
- Confirmed that the old final response did not appear before the
steered response.
- Tested three queued messages in a real browser.
- Confirmed that reorder changed delivery order and that the removed
message was never sent or shown again.
- Tested a legacy runner in a real browser.
- Confirmed that it used the interrupt fallback and showed the follow-up
once.
- Reloaded a saved mixed-steer/successor-run thread and confirmed the
causal timestamps and continuation header render in the correct
positions.
- The complete macOS suite reaches five unrelated platform assertions in
workspace-runtime tests. Two compare `/var` with `/private/var`. Three
require Linux `/proc` listener data. GitHub Actions provides the
authoritative Linux run.

## Risks

- Low risk. The change is limited to issue-chat queue projection and
transcript presentation.
- The server run-history API adds only a read-only `contextIssueId`
projection; the database schema does not change.
- Optimistic actions restore the prior UI state when a request fails.

## Model Used

- OpenAI Codex with GPT-5, extended reasoning, browser automation, shell
tools, and code execution.

## 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

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-04 12:54:00 -05:00
..
__tests__ fix(ui): stabilize active-run steering queue (#12834) 2026-09-04 12:54:00 -05:00
adapters fix(security): harden privileged server boundaries (#12776) 2026-09-03 14:15:32 -05:00
auth feat(runner): add Codex-native application integration (#12591) 2026-08-31 14:38:38 -05:00
built-ins/agents Remove cheap model profiles (#12683) 2026-09-01 14:57:38 -05:00
http fix(server): raise company import zip upload limit to 1 GB and make it operator-configurable (#11184) 2026-08-10 12:47:03 -07:00
lib perf(server): reduce issue detail request overhead (#10414) 2026-08-11 14:39:23 -04:00
middleware fix(server): honor proxy trust for forwarded host (#12832) 2026-09-04 10:02:28 -05:00
onboarding-assets fix: reliably show plans in the Plan pane and restore sticky plan confirmation CTAs (#10930) 2026-08-05 19:32:07 -07:00
realtime feat(runner): add remote execution substrate (#12638) 2026-09-01 01:29:06 -05:00
routes feat(telemetry): add the agent.task_run event and emit it at every terminal run transition (#12809) 2026-09-04 08:21:32 -07:00
secrets
…
services fix(ui): stabilize active-run steering queue (#12834) 2026-09-04 12:54:00 -05:00
storage
…
types
…
vendor/paperclip-runner feat(runner): add remote execution substrate (#12638) 2026-09-01 01:29:06 -05:00
agent-auth-jwt.ts fix(server): align agent run JWT default TTL with documented 48h default (#10176) 2026-08-12 16:44:20 -07:00
app.ts fix(runner): stabilize local paid E2E recovery (#12836) 2026-09-04 11:16:20 -05:00
attachment-types.ts Remove the company brand color and per-company attachment limit (#12291) 2026-08-27 12:11:05 -07:00
board-claim.ts
…
build-commit.ts
…
build-version.ts
…
config-file.ts fix(config): preserve extensions and guard invalid repairs (#11005) 2026-08-07 00:41:19 -05:00
config.ts feat(apps): improve gateway and workspace connection UX (#12340) 2026-08-29 12:08:32 -05:00
db-errors.ts fix(issues): make DELETE /api/issues/:id succeed for issues with dependents (#11331) 2026-08-13 12:02:15 -07:00
dev-native-runner-status.ts feat(runner): integrate Codex native execution (#12616) 2026-08-31 22:51:17 -05:00
dev-runner-worktree.ts feat(workspaces): sign the workspace login handoff and gate readiness (#11671) 2026-08-19 02:37:02 -05:00
dev-server-status.ts
…
dev-watch-ignore.ts fix(server): ignore sibling worktrees in dev watch (#11074) 2026-08-07 18:30:16 -07:00
embedded-postgres-supervisor.ts fix(workspaces): recover degraded runtime databases (#11651) 2026-08-18 17:40:54 -05:00
errors.ts feat(artifacts): bridge Markdown work products into the document review surface (#11822) 2026-08-20 17:28:01 -07:00
first-admin-claim.ts
…
home-paths.ts feat(server): thread plural referenced-project workspaces through run prep (#10448) 2026-07-29 14:27:05 -07:00
index.ts fix(server): stop paging Sentry for supervised boot races in managed cloud (#12772) 2026-09-03 10:02:42 -07:00
instrumentation.test.ts fix(server): export manual OpenTelemetry spans (#10565) 2026-07-31 12:47:57 -07:00
instrumentation.ts fix(observability): pin the Sentry browser SDK and gate the optional Sentry server peer on the exact version (#12270) 2026-08-27 07:20:03 -07:00
log-redaction.ts
…
paths.ts
…
peer-version-check.ts fix(observability): pin the Sentry browser SDK and gate the optional Sentry server peer on the exact version (#12270) 2026-08-27 07:20:03 -07:00
redaction.ts fix(runner): repair paid provider startup paths (#12769) 2026-09-04 07:58:44 -05:00
runtime-api.ts
…
runtime-tools-token.test.ts feat(connections): add self-serve intent runtime (#12345) 2026-08-29 12:08:34 -05:00
runtime-tools-token.ts feat(connections): add self-serve intent runtime (#12345) 2026-08-29 12:08:34 -05:00
sentry-dsn.ts feat(server): split the Sentry DSN into front-end and backend variables (#12678) 2026-09-01 11:02:04 -07:00
sentry.ts feat(server): split the Sentry DSN into front-end and backend variables (#12678) 2026-09-01 11:02:04 -07:00
server-info.ts
…
shutdown.test.ts feat(observability): add opt-in Sentry error monitoring for the server and the browser (#12190) 2026-08-26 11:15:45 -07:00
shutdown.ts feat(observability): add opt-in Sentry error monitoring for the server and the browser (#12190) 2026-08-26 11:15:45 -07:00
startup-banner.ts fix(security): route paperclipai CLI guidance through safe npx form (CWE-78) (#11400) 2026-08-14 22:11:16 -07:00
startup-refusals.ts fix(server): stop paging Sentry for supervised boot races in managed cloud (#12772) 2026-09-03 10:02:42 -07:00
static-index-html.ts
…
static-ui-cache.ts fix(ui): keep the installed service worker fresh on parked tabs (#12198) 2026-08-25 16:12:02 -07:00
telemetry.ts
…
ui-branding.ts
…
url-utils.test.ts fix(runtime): only rewrite base-URL port for loopback hosts (#10258) 2026-08-13 09:47:13 -07:00
url-utils.ts fix(runtime): only rewrite base-URL port for loopback hosts (#10258) 2026-08-13 09:47:13 -07:00
version.ts
…
vite-html-renderer.ts fix(runner): stabilize local paid E2E recovery (#12836) 2026-09-04 11:16:20 -05:00
worktree-config.ts feat(apps): consolidate connector management (#12684) 2026-09-01 14:55:35 -05:00
worktree-seed-manifest.ts feat(workspaces): sign the workspace login handoff and gate readiness (#11671) 2026-08-19 02:37:02 -05:00