Files
PaperClipAI/ui/src
DottaandClaude Opus 5.5 3e8744fa91 perf(task-chat): stop a slow run transcript from hiding the chat (#20277)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - The task chat shows saved messages, run transcripts and the composer
> - The chat hides the messages and the composer until every run
transcript loads. This prevents layout movement
> - On staging, one task's run-log read took 11–12 s. Saved messages and
the composer stayed hidden for 13.9 s after a click, and for 14.6 s
again on revisit
> - This pull request limits how long a transcript can hold the first
reveal after saved history is ready
> - The benefit is that a slow run log no longer hides the conversation,
and the layout contract stays in place

## Linked Issues or Issue Description

**Describe the bug**
When a task has a run whose transcript loads slowly, the whole chat
stays behind the loading skeleton. The composer stays hidden too. On
staging, a failed run with no saved reply needed an 11–12 s object-store
log read. The chat appeared after 13.9 s. Saved messages that loaded in
about 2 s were not visible during that time.

**Steps to reproduce**
1. Open a task whose latest run failed before it saved a reply, and
whose run log is large or slow to read.
2. Watch the chat area after the click.

**Expected behavior**
Saved messages and the composer appear when saved history is ready. Run
output must not move the messages that are already visible.

**Actual behavior**
The chat stays hidden until the run log read finishes, or until the 15 s
reveal timeout.

Refs #20276 (the measurement harness and baseline plan).

## What Changed

- `TaskChatThread` now waits at most
`INITIAL_TRANSCRIPT_REVEAL_BUDGET_MS` (600 ms) for run transcripts. The
time starts when saved history, the plan and chat metadata are ready.
The budget is one deadline. A transcript that loads early does not
restart it.
- When the budget expires, the slow runs are latched for that task, so
the decision does not change later:
- **Live runs** stop holding the reveal. Their output continues to
stream into the live tail at the bottom of the chat.
- **Settled runs in compact history** stop loading. They use the
existing fixed **More run output** control, so late output cannot insert
rows above the reader. Selecting the control loads the full history, as
it does today.
- **Settled runs in other modes** (expanded history, conversation mode,
a deep link to a comment) still wait, as before. In those modes, output
would insert rows around saved replies.
- **Live runs with a steering message or other timeline anchors** still
wait, as before. Their output before the anchor goes into the main
conversation above the anchored message.
- A live run that finishes after the reveal keeps its visible
transcript. Only runs that were already settled when the budget expired
are deferred.

## Verification

- `cd ui && npx vitest run src/components/TaskChatThread.test.tsx`. New
tests for legacy and native runs:
- A slow failed run in compact history: the chat reveals at the budget,
the transcript is no longer requested, **More run output** appears, and
expanding loads the run.
- A slow live run: the chat reveals at the budget, the transcript keeps
streaming, and the transcript stays after the run finishes.
- A slow settled run without the compact control: the chat still waits.
  - The budget does not start while saved history is pending.
- When one of two transcripts loads before the budget ends, the chat
still reveals at the first deadline.
  - A slow live run with a steering message: the chat still waits.
- A compact task with 300 slow failed runs: the chat reveals at the
budget and defers every run.
- `cd ui && npx vitest run
src/components/task-chat/transcript-reveal-budget.test.ts`. The budget
selection is one pass. A 5,000-run test counts anchor lookups and throws
above one lookup for each live run.
- Red check: with the budget timer disabled, the 6 new positive tests
fail. With the change, they pass.
- `npx vitest run src/components/TaskChatThread.test.tsx
src/components/task-chat src/pages/IssueDetail`: 64 files and 1,609
tests pass.
- `pnpm exec playwright test --config tests/e2e/playwright.config.ts
tests/e2e/task-loading-frame.spec.ts`: 7 of 7 pass. This covers a stable
loading frame on desktop and mobile, composer geometry, the reading
position, a stalled web font, and the Classic and mobile preference
paths.
- After deploy, staging is measured with the harness from #20276. The
finish condition is that a slow run-log task opens in the same time as
other tasks.

## Risks

- After a slow transcript is deferred, a settled failed run in compact
history shows its failure message and **More run output**, not its last
transcript lines. The output is one click away. The server-side log read
fix is a separate follow-up.
- A live run's output can appear in the tail after the reveal. This is
the normal streaming behaviour of the tail.
- A 600 ms budget is a trade-off. Fast transcripts still arrive in the
first frame, and slow ones no longer hide the chat.

## Model Used

- Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, used in Claude Code
with tool use (shell, browser automation, file editing).

## 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
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [ ] 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>
2026-11-09 09:06:42 -06:00
..
…