You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When Desktop is following the live tail, an upward reader scroll can fail to release the tail pin if transcript geometry changes during the same scroll event. The viewport is then written back to the newest content by the next resize notification.
The visible result is a rubber-band interaction: while a response is still producing content, the reader scrolls upward to inspect earlier output, but the transcript snaps back to the bottom or requires repeated gestures before it stays away from the tail.
Expected behavior: the first effective upward scroll of the transcript releases live-tail following immediately. Later content growth must preserve the reading position until the reader explicitly returns to latest.
How to reproduce
This can be reproduced with fully synthetic content:
Seed one Turn with roughly 150–200 timeline records and more than 100 assistant/tool render blocks, followed by a few small Turns.
Open the session at the tail so earlier blocks begin with intrinsic placeholder geometry.
Keep the latest Turn streaming, or otherwise cause transcript growth.
Scroll upward into blocks that have not yet been laid out.
Observe the viewport return to the tail when block materialization and live growth deliver resize notifications.
It becomes much easier to reproduce with #4259 because content-visibility: auto changes a previously skipped block from its intrinsic fallback to its measured height as the reader approaches it. The underlying ambiguity in the scroll classifier exists on main: reader movement and geometry movement can occur before the same scroll event is handled.
Active transcript: approximately 470 stored records and 1.6 MB of inline serialized message data.
Largest Turn: 170 records and approximately 699k serialized JSON characters.
Largest Turn composition: 61 tool calls, 58 tool results, and 50 assistant records.
After the active response completed, renderer CPU returned to 0%; a native idle sample found the renderer main thread asleep. This is interaction-triggered geometry work, not a persistent background loop.
No session identifiers, titles, prompts, assistant text, tool arguments/results, user names, filesystem paths, credentials, or raw logs are included. The figures are aggregate and content-free.
Approaching a previously skipped block replaces fallback geometry with its measured height, changing the transcript scrollHeight.
createTranscriptScrollAuthority treats every scroll event whose scrollHeight or clientHeight changed as content/viewport movement and returns without setting pinned = false or notifying reader-scroll listeners.
The following ResizeObserver still sees pinned === true and calls writeToTail().
The reader is snapped back to the bottom.
The classifier is correct for growth without user input, but it has no representation for the combined case: reader movement and geometry change occurring in the same delivery window.
Test gap
The #4259 oversized-Turn test verifies that offscreen segments are skipped and that a segment can be reached with scrollIntoView. It does not exercise:
a real upward reader gesture from a pinned tail;
intrinsic-to-measured geometry changing during that gesture; or
concurrent live transcript growth.
The scroll-authority unit suite separately covers reader movement and growth, but not both before the same scroll event followed by a resize callback. This allows the performance regression test and scroll-authority tests to pass independently while their integration still snaps the viewport.
Desired outcome
An effective upward reader scroll releases the tail pin even when transcript geometry changes in the same frame/event delivery window.
Growth without reader input continues to keep a pinned transcript at the tail.
A released reader remains anchored while skipped blocks materialize and while new output arrives.
Nested scroll containers retain their current behavior: a gesture consumed by a tool output or terminal must not release the outer transcript.
Add an integration regression using synthetic oversized content, an actual upward wheel/scroll, intrinsic geometry correction, and live growth.
Prepared by OpenAI Codex under maintainer direction from a read-only, sanitized local audit. The maintainer owns the final technical decisions and submission.
What happened
When Desktop is following the live tail, an upward reader scroll can fail to release the tail pin if transcript geometry changes during the same scroll event. The viewport is then written back to the newest content by the next resize notification.
The visible result is a rubber-band interaction: while a response is still producing content, the reader scrolls upward to inspect earlier output, but the transcript snaps back to the bottom or requires repeated gestures before it stays away from the tail.
Expected behavior: the first effective upward scroll of the transcript releases live-tail following immediately. Later content growth must preserve the reading position until the reader explicitly returns to latest.
How to reproduce
This can be reproduced with fully synthetic content:
mainplus the sub-Turn render bounds from perf(desktop): bound rendering within oversized turns #4259.It becomes much easier to reproduce with #4259 because
content-visibility: autochanges a previously skipped block from its intrinsic fallback to its measured height as the reader approaches it. The underlying ambiguity in the scroll classifier exists onmain: reader movement and geometry movement can occur before the samescrollevent is handled.Environment
be3a0291b(main) with PR perf(desktop): bound rendering within oversized turns #4259 head73bb81764Sanitized evidence
Aggregate shape from one private local workspace:
No session identifiers, titles, prompts, assistant text, tool arguments/results, user names, filesystem paths, credentials, or raw logs are included. The figures are aggregate and content-free.
Source-level failure path
content-visibility: autowith intrinsic block geometry to stable timeline blocks inside an oversized Turn.scrollHeight.createTranscriptScrollAuthoritytreats everyscrollevent whosescrollHeightorclientHeightchanged as content/viewport movement and returns without settingpinned = falseor notifying reader-scroll listeners.ResizeObserverstill seespinned === trueand callswriteToTail().The classifier is correct for growth without user input, but it has no representation for the combined case: reader movement and geometry change occurring in the same delivery window.
Test gap
The #4259 oversized-Turn test verifies that offscreen segments are skipped and that a segment can be reached with
scrollIntoView. It does not exercise:The scroll-authority unit suite separately covers reader movement and growth, but not both before the same
scrollevent followed by a resize callback. This allows the performance regression test and scroll-authority tests to pass independently while their integration still snaps the viewport.Desired outcome
Related: #4256, #4259, #4099.
Prepared by OpenAI Codex under maintainer direction from a read-only, sanitized local audit. The maintainer owns the final technical decisions and submission.