Skip to content

fix(app): a chat that shrinks to fit mid-turn keeps its top rows drawn - #193

Merged
pumfleet merged 2 commits into
mainfrom
i-was-running-a
Oct 27, 2026
Merged

pumfleet merged 2 commits into
mainfrom
i-was-running-a

Conversation

@pumfleet

@pumfleet pumfleet commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Mid-turn, a chat could go blank at the top: the prompt, the Working fold and the first steps were missing, with empty space where they belonged.

Cause. The chat draws only the rows near the view, and it learns where the view is from the browser's scroll events. When the agent's long reply folded into Working (a tool call and a newer reply arrived after it), the chat got short enough to fit and the view moved back to the top. WebKit, which runs the Mac app, does that without firing a scroll event. So the virtualizer kept drawing for the old, lower position, and nothing scrolled after that to correct it. I confirmed this by replaying the real session's record through the box's transcript reader: the blank band in the screenshot is exactly the prompt, the fold and the first locations.go edit.

Fix (app/src/components/conversation/chat-list.tsx). Whenever the list changes height, it compares the virtualizer's offset with the real scrollTop. If they differ, it updates the virtualizer with a scroll event.

Testing

  • New browser test in app/e2e/draft.spec.ts that replays the turn's shape: five edits, then a reply taller than the screen, then a command and a short reply that fold it away. It drops the browser's own (trusted) scroll events, as WebKit does. Without the fix it fails 4 times in 4; with it, the whole spec passes 24 times in 24 (6 tests × 4). chat-long.spec.ts passes 5 out of 5.
  • The test needs to add edits and commands to the demo's record, so the demo's test hook (window.__berthDraft, mock-only) has record beside land.
  • WebKit itself wasn't run: Playwright's WebKit needs system libraries on this box. The Mac app is worth a look on the next long turn.
  • Gate: go vet and go test -race, cargo check, the app checks and build, npx tsc -p e2e, and the docs build all pass, apart from one Go flake. internal/leadline/api TestDetach fails 3 times in 10 with -race. This branch changes no Go code, so the same flake is on main. The package passes on a rerun.

Review

  • Round 1 (Codex review --base origin/main): no actionable findings.
  • cubic on the first push raised two, both fixed:
    • P2: the synthetic scroll event also reached the chat's own scroll handler, which could unpin a chat you touched a moment before. The handler now ignores untrusted scroll events.
    • P3: the mock hook's Omit<TranscriptItem, "id"> flattened the union. It's now distributive (Unsaved<T>).
  • Round 2 (Codex, on the fixes): no actionable findings.

🤖 Generated with Claude Code

View guided diff Turn on auto-fix

When a long reply folded into its turn's steps and the chat got short
enough to fit, WebKit moved the view up without a scroll event. The
virtualized list kept drawing rows for where the view had been, leaving
the prompt and the first steps undrawn with blank space in their place.

The list now checks where the view really is whenever its height
changes, and tells the virtualizer when they differ. The demo's test
hook can record any step (an edit, a command), and a browser test
replays the turn with the browser's own scroll events dropped, as
WebKit does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
berth Ready Ready Preview Oct 27, 2026 5:14pm UTC
berth-docs Ready Ready Preview Oct 27, 2026 5:14pm UTC

Request Review

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 4 files

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread app/src/lib/mock-conversation.ts Resolved
- The chat's own scroll handler ignores the list's synthetic scroll
  event, so telling the virtualizer where the view is can't unpin a chat
  the person touched a moment before.
- The demo's record hook takes any kind of item without its id, typed
  per kind instead of the union's common fields.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@pumfleet
pumfleet merged commit d42be90 into main Oct 27, 2026
9 checks passed
@pumfleet
pumfleet deleted the i-was-running-a branch October 27, 2026 17:33
@linear-code

linear-code Bot commented Oct 27, 2026

Copy link
Copy Markdown

ENG-6964

@pumfleet pumfleet mentioned this pull request Oct 27, 2026

This branch was successfully deployed

2 active deployments
Preview – berth-docs — 0dad1717 Deployed Oct 27, 2026 by vercel[bot]
Preview – berth — 0dad1717 Deployed Oct 27, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

run-ci Run CI on this pull request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant