fix(word-addin): settle the submitted turn on one 80px pin line and defend it against pane resizes

↗ view on GitHub · Amal · 2026-08-11 · 078a5d5b

WHY THIS MATTERS
When you send a message in the assistant pane, the transcript scrolls so your
turn "pins" near the top while the answer streams in below it. Users reported
the pinned turn drifting to different heights per turn and sliding when the
response's activity strip changed size.

WHAT IS A PIN LINE (and what was wrong)
The pin is built from two cooperating pieces:
  1. a scroll target - where the turn should sit (`element.offsetTop - N`), and
  2. a reserved spacer under the turn (min-height on the assistant row) that
     guarantees the scroll range can actually reach that position.
The old code targeted N=24px but sized the spacer against the container's
80px top padding, so the maximum scroll only reached `offsetTop - 80`. The
turn's resting position became a function of the answer's height:
`max(24, 80 - (answerHeight - spacer))` - short answers rested at 80, long
ones climbed to 24, and any shrink slid the turn back down. The web assistant
avoids this by keeping the target and the container padding on the same line;
the add-in had copied the constant but not the invariant.

HOW IT WORKS NOW
- `PIN_TOP_OFFSET = 80` - one constant, documented as "must equal the
  container's pt-20" - is used by the live pin scroll, the restored-history
  scroll, and `measureSpacerPx`. With both pieces on the same line, the
  minimum scroll range lands exactly on the pin position for every answer
  height, so post-completion shrinking can never clamp the turn away.
- Two ResizeObserver watchdogs (container box + active assistant row)
  re-assert the anchored position when the pane or the streaming row resizes,
  and restore the user's own position (clamped to the new range) once the
  user has scrolled away. Scroll "ownership" is tracked in refs
  (`anchorActiveRef`, `desiredScrollTopRef`): the app owns the anchor until
  wheel/touch/pointer/keyboard input hands it to the user.
- `UserMessage` clamps long prompts from the first painted frame so the
  spacer measurement and the painted layout can never disagree.

VERIFICATION TOOLING
- e2e/chat-layout.spec.ts gains completion-transition and bottom-arrow specs.
- playwright.webkit.temp.config.ts runs the same suite under WebKit - the
  engine the Office task pane actually uses (WKWebView) - where Chromium-only
  runs cannot observe engine scroll adjustments.
- docs/word-addin-chat-scroll-report.md records the full investigation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Repository open-legal-products/mike
Author Amal <mamalanand3@gmail.com>
Authored
Committed
Parents 8b3cd9ab
Stats 6 files changed , +1067 , -153
Part of Bring the Word add-in chat experience in line with the web app

Capture this commit into my fork

Download a Markdown prompt that tells Claude how to port this exact commit into your working tree. Run it via claude -p < capture-commit-078a5d5b.md from inside the repo you want the change in.

⬇ Download capture-commit-078a5d5b.md