Skip to content

fix(web): stabilize conversation scrolling - #360

Merged
danyaberezun merged 9 commits into
mainfrom
ergonomic-desktop-scrolling
Sep 1, 2026
Merged

fix(web): stabilize conversation scrolling#360
danyaberezun merged 9 commits into
mainfrom
ergonomic-desktop-scrolling

Conversation

@rsolmano

@rsolmano Rinat S (rsolmano) commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fix conversation scrolling around very tall virtualized rows and multi-page questionnaires while preserving native wheel physics and canonical message-row boundaries.

The chat now starts with realistic conservative row geometry, keeps manual Latest navigation pinned while measurements settle, and lets questionnaire renderers ask the chat scroll owner to reveal each page before applying the existing focus policy.

Changes

Chat virtualization

  • Estimate projected row heights conservatively from canonical row content without splitting Markdown blocks.
  • Add bounded pixel/item overscan so nearby outliers receive authoritative measurements.
  • Cache estimates for one virtualizer mount and rebuild them when message order changes.
  • Keep manual Latest navigation at the physical latest edge through a bounded settling window, canceling on reader/controller input.

Questionnaire reveal

  • Expose a narrow, clamped element-reveal operation through ChatActions / useChatScroll.
  • Reveal the current questionnaire page in the transcript before guarded focus({ preventScroll: true }) behavior.
  • Keep one transcript scrollbar, preserve coarse-pointer focus protections, and leave follow/detached state unchanged.

Regression coverage

  • Add deterministic persisted-session fixtures for canonical tool calls/results.
  • Cover giant Markdown history with equivalent coarse/granular wheel travel.
  • Assert Latest reaches the physical latest edge in both message orders without relying on a mounted stream marker.
  • Cover tall questionnaire paging and coarse-pointer reveal-without-focus behavior.

Testing

  • bun run check:deps — passed.
  • bun run check:boundaries — passed.
  • bun run check:seams — passed.
  • bun run lint — passed with 6 pre-existing warnings.
  • bun run typecheck — 14/14 package tasks passed.
  • bun run test — 14/14 package tasks passed.
  • bun run e2e — 319 passed across 8 shards.

Screenshots

Before — page 2 remains above the viewport

Before: questionnaire page 2 hidden above the transcript viewport

After — page 2 starts inside the transcript viewport

After: questionnaire page 2 revealed at the transcript viewport

ThinkRail-Todo: 01a05794-a3cb-752b-bfd7-fba51e3e0104/t_6b68bd5e8534
ThinkRail-Todo: 01a05794-a3cb-752b-bfd7-fba51e3e0104/t_260212e91cf8
ThinkRail-Todo: 01a05794-a3cb-752b-bfd7-fba51e3e0104/t_e6fe94ef6592
ThinkRail-Todo: 01a05794-a3cb-752b-bfd7-fba51e3e0104/t_54161c153bf9

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved — ready to merge.

@danyaberezun danyaberezun left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please address these cases before merging.

Comment thread apps/web/src/chat/rowHeightEstimates.ts
Comment thread apps/web/src/chat/scrollGeometry.ts Outdated
Comment thread apps/web/src/chat/tools/AskUserQuestionCard.tsx Outdated
Comment thread apps/web/src/chat/tools/AskUserQuestionCard.tsx
Comment thread apps/web/src/chat/readingBand.ts Outdated
Comment thread apps/web/src/chat/ChatView.tsx
Resolve the import-block conflict in e2e/chat-order.spec.ts as the union of
both sides: main (#361) dropped `openChatFromHistory` when passive chat
auto-open removed its last two call sites, and this branch's
`./fixtures/chatScroll` helpers are kept for the new latest-edge assertions.

Produced by AIR Automations. Name: Resolve Merge Conflicts / Run: https://air.jetbrains.cloud/org/05cf1a7f-6ab5-713b-abd3-29d0c8a05e2d/automations/6019d7e8-25e2-42ee-9589-26da37839744?run=bd701a8c-f5c1-49c5-b411-b223a0750a83
@jetbrains-air

jetbrains-air Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Merged main into this branch to clear the conflict (merge commit, no rebase, no force-push).

Conflict: one hunk — the import block of e2e/chat-order.spec.ts.

Resolved as the union of both sides, no behavioural call made:

  • main (Restore bounded passive chat auto-open #361, bounded passive chat auto-open) dropped openChatFromHistory because it replaced this spec's two call sites with expect(tab).toHaveCount(1). That was already decided there — recorded as architecture.md Decision add "discuss first" #8, with 12 specs updated in the same PR — so main's side stands.
  • This branch's ./fixtures/chatScroll import stays: readChatScrollGeometry / readChatViewportIntersection back the new latest-edge poll assertion.

Both sides' body edits were disjoint and auto-merged intact: main's auto-open assertions and this branch's latestAnswer refactor + poll are both present. Nothing outside the conflict was touched — the merge diff against each side contains only that side's own changes.

The resolution is uniquely determined rather than chosen: keeping openChatFromHistory trips lint/correctness/noUnusedImports (verified against a scratch copy), and dropping the chatScroll import breaks its two uses.

Ran locally: check:deps, check:boundaries, check:seams, lint (0 errors, the 6 pre-existing warnings), typecheck 14/14, build 3/3, playwright --list on this spec (both tests discovered).

Not run: the browser e2e suite — this sandbox has no Chromium and the Playwright CDN is unreachable, so bun run e2e fails at browserType.launch before executing anything. Left to CI. Also pre-existing and unrelated: packages/shared freePort has 2 red tests here because Bun.serve({hostname:"localhost"}) binds only ::1 in this container while the probe dials 127.0.0.1; that package is byte-identical to main and untouched by this branch. No test was modified or weakened.

Produced by AIR Automations. Name: Resolve Merge Conflicts / Run: https://air.jetbrains.cloud/org/05cf1a7f-6ab5-713b-abd3-29d0c8a05e2d/automations/6019d7e8-25e2-42ee-9589-26da37839744?run=bd701a8c-f5c1-49c5-b411-b223a0750a83

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved — ready to merge.

@jetbrains-air

jetbrains-air Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Correction to my previous comment — this PR needs your judgement, and the merge I pushed is not ready to land.

CI has now run the browser e2e suite I could not run locally (no Chromium in that sandbox, Playwright CDN unreachable). Result on d7089b50: 1 failed, 320 passed. Lint & Typecheck, Unit Tests and Binary smoke (windows) are green, and the welcome.spec.ts failure in the same report is a retry-passing flake, not this merge.

The real failure — a semantic conflict git merged textually clean:

e2e/chat-history.spec.ts:81 › coarse wheel input crosses realistic virtual geometry
                              before a giant history row mounts
  locator.click: Test timeout of 30000ms exceeded
  waiting for getByTestId("chat-history")   at fixtures/app.ts:152 (openChatFromHistory)

That test is new in this PR — it is not in main or in the merge base, so #361 could not update it when it updated the 12 then-existing specs. It seeds exactly one session (giant hydrated history) and then calls openChatFromHistory. Under #361's restored fallback — "if nothing is placed and nothing qualifies, the single most-recent session opens as a fallback so a workspace never lands empty" — that single session now auto-opens, so nothing is left in history and the chat-history affordance never appears.

Why I stopped rather than fixed it. Every repair changes what the test exercises, so the call is yours (Rinat S (@rsolmano)) and #361's (Olga Lavrichenko (@OLavrik)):

  • rely on auto-open and drop openChatFromHistory, as Restore bounded passive chat auto-open #361 did elsewhere — but this test exists to measure geometry at first mount from a cold history open, which that path no longer covers;
  • seed a second, more-recent qualifying session so the giant one stays unplaced — keeps the cold-open path, changes the fixture's meaning;
  • make the giant session neither qualifying nor the fallback — narrowest, but pins the test to auto-open's internal rules.

I did not touch the test, and nothing was weakened to get green.

State of the branch: the merge commit d7089b50 is still here. It does clear the textual conflict — the e2e/chat-order.spec.ts import resolution described above stands and is unaffected by this failure — but the branch is red until the above is decided. I left it in place rather than reverting because rewriting a pushed branch is outside what I am allowed to do; drop or amend it as you prefer.

Produced by AIR Automations. Name: Resolve Merge Conflicts / Run: https://air.jetbrains.cloud/org/05cf1a7f-6ab5-713b-abd3-29d0c8a05e2d/automations/6019d7e8-25e2-42ee-9589-26da37839744?run=bd701a8c-f5c1-49c5-b411-b223a0750a83

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Requesting changes — please address the blocking inline findings.

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved — ready to merge.

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved — ready to merge.

@jetbrains-air jetbrains-air Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved — ready to merge.

@danyaberezun
danyaberezun added this pull request to the merge queue Sep 1, 2026
Merged via the queue into main with commit d3e75c1 Sep 1, 2026
6 checks passed
@danyaberezun
danyaberezun deleted the ergonomic-desktop-scrolling branch September 1, 2026 23:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants