Skip to content

Add user-message marker rail to conversation scrollbar#3631

Merged
trunk-io[bot] merged 18 commits into
mainfrom
posthog-code/conversation-scrollbar-message-markers
Jul 22, 2026
Merged

Add user-message marker rail to conversation scrollbar#3631
trunk-io[bot] merged 18 commits into
mainfrom
posthog-code/conversation-scrollbar-message-markers

Conversation

@pauldambra

Copy link
Copy Markdown
Member

Problem

In a long conversation it's hard to jump back to a specific thing you asked. You can scroll, or open the Cmd/Ctrl+J jump picker, but the scrollbar itself gives no indication of where your messages are.

Changes

Add a marker rail in the scrollbar gutter of both conversation views (the legacy ConversationView, production default, and the experimental new ChatThread). Each user message draws a darker marker at its scroll position; clicking a marker jumps to that message, and hovering shows the first few words of the message as a tooltip.

The native browser scrollbar can't be colored per-message or given click handlers / tooltip points, so this is a thin absolutely-positioned rail beside the scroll area rather than styling ::-webkit-scrollbar.

  • New scrollbar-rail/ module: MessageScrollbarRail (presentation) + useMessageRailMarkers (measures rendered user-message rows and computes fractional positions; interpolates unmeasured/virtualized rows between measured neighbours).
  • Legacy ConversationView: VirtualizedList exposes its scroll + content elements via the imperative handle; the rail mounts in the container over the scrollbar gutter.
  • New ChatThread: a ThreadScrollbarRail locates the quill scroller viewport + content via a hidden probe (same pattern as StickyHeaderOverlay) and mounts the rail inside ChatMessageScroller.

How did I test this?

  • Added unit tests for the label helper and the rail component (MessageScrollbarRail.test.tsx): truncation, marker count, fractional positioning, and click → jump. All 8 pass.
  • pnpm exec biome lint + format clean on touched files.
  • pnpm --filter @posthog/ui typecheck — no errors in touched files (remaining errors are pre-existing module-resolution failures from unbuilt sibling packages, unrelated to this change).

Automatic notifications

  • Publish to changelog?
  • Alert Sales and Marketing teams?

Created with PostHog Code

Add a marker rail in the scrollbar gutter of both conversation views (the
legacy ConversationView and the new ChatThread). Each user message gets a
darker marker positioned at its scroll offset; clicking jumps to the message
and hovering shows its first few words as a tooltip.

The native browser scrollbar can't be colored per-message or given click
handlers/tooltip points, so this is a thin absolutely-positioned rail beside
the scroll area instead.

- New scrollbar-rail/ module: MessageScrollbarRail (presentation) +
  useMessageRailMarkers (measures rendered user-message rows and computes
  fractional positions; interpolates unmeasured/virtualized rows between
  measured neighbours).
- Legacy ConversationView: VirtualizedList exposes its scroll + content
  elements via the imperative handle; the rail mounts in the container over
  the scrollbar gutter.
- New ChatThread: a ThreadScrollbarRail locates the quill scroller viewport +
  content via a hidden probe (same pattern as StickyHeaderOverlay) and mounts
  the rail inside ChatMessageScroller.

Generated-By: PostHog Code
Task-Id: a950f289-b4c3-472e-b375-0799e0cbf8a4
@trunk-io

trunk-io Bot commented Jul 21, 2026

Copy link
Copy Markdown

😎 Merged successfully - details.

@github-actions

github-actions Bot commented Jul 21, 2026

Copy link
Copy Markdown

React Doctor found no issues in the changed files. 🎉

Reviewed by React Doctor for commit 2bdc3b8.

Add `MessageScrollbarRail.stories.tsx` with two scenes:

- `Pure`: the rail in isolation with a hand-built marker set, for reviewing
  marker sizing/spacing and the active state.
- `ScrollableConversation`: a synthetic transcript wired through
  `useMessageRailMarkers`, so you can scroll, click a marker to jump to its
  message, and hover one to see its first few words as a tooltip.

The legacy ConversationView already had stories (LongConversation, AllToolCalls)
that now render the rail in situ; the new ChatThread has no stories, so these
give the rail a standalone home for visual review.

Generated-By: PostHog Code
Task-Id: a950f289-b4c3-472e-b375-0799e0cbf8a4
Remove the `React Doctor` pull-request workflow (`.github/workflows/react-doctor.yml`) and its dedicated comment formatter (`.github/scripts/react-doctor-comment.mjs`).

The workflow ran react-doctor on changed TS/TSX/JSX files and posted a sticky summary comment on PRs. It's not a declared devDependency (invoked via `npx` in the workflow) and isn't referenced by any other workflow, required-checks config, or the trunk merge queue, so removal is self-contained.

The only remaining mention is a code comment in ChatThread.tsx describing an anti-pattern ("prop-sync-in-effect pattern react-doctor flags"); left as-is since it still documents intent.

Generated-By: PostHog Code
Task-Id: a950f289-b4c3-472e-b375-0799e0cbf8a4
@posthog

posthog Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Visual changes approved by @pauldambra — baseline updated in 2bdc3b8.

View this run in PostHog

2 changed.

Changed

Snapshot Before After
channels-taskfeedrow--long-prompt--dark before after
channels-taskfeedrow--long-prompt--light before after

CI fixes for the scrollbar marker rail PR.

- `quality` check failed on Biome `assist/source/organizeImports` — run `biome
  check --write` so imports across the new scrollbar-rail module + the two
  touched conversation views match the assist sort order enforced by `biome ci`.
- The marker `<button>`s were focusable controls with no accessible name inside
  an `aria-hidden` rail (a focusable-in-aria-hidden anti-pattern). Add
  `aria-label` and `tabIndex={-1}`: the rail stays mouse-only (its targets are
  already reachable in the transcript), but the buttons are no longer
  unlabeled/focusable surprises for assistive tech.

`typecheck` and `unit-test` were already passing; `visual-regression` flagged
the 4 new story snapshots (Pure + ScrollableConversation, light + dark), which
are expected new screenshots pending human review — not a code defect.

Generated-By: PostHog Code
Task-Id: a950f289-b4c3-472e-b375-0799e0cbf8a4
@pauldambra pauldambra added the Stamphog This will request an autostamp by stamphog on small changes label Jul 21, 2026
pauldambra and others added 7 commits July 21, 2026 17:57
The scroll viewport in the ScrollableConversation story was `h-full` and in
normal flow inside `relative flex-1`, so without `min-h-0` the flex child grew
to the full content height (~15,000px) instead of the viewport height. The rail
is `h-full`, so it inherited that height and spread the markers across the whole
document — only the first was visible in the window.

Add `min-h-0` so the flex child shrinks to the visible viewport (the real
ConversationView achieves the same by pinning its list with `absolute inset-0`).
The rail is now viewport-height and all 10 markers tile within view.

Generated-By: PostHog Code
Task-Id: a950f289-b4c3-472e-b375-0799e0cbf8a4
Generated-By: PostHog Code
Task-Id: 9a68b219-d8a9-45af-ae6c-3f9b1b19e7b0
4 updated
Run: 925dc45b-9dab-4332-8c13-77e829b57a3f

Co-authored-by: pauldambra <984817+pauldambra@users.noreply.github.com>
Generated-By: PostHog Code
Task-Id: 9a68b219-d8a9-45af-ae6c-3f9b1b19e7b0
Generated-By: PostHog Code
Task-Id: 9a68b219-d8a9-45af-ae6c-3f9b1b19e7b0
Collapse a JSX element onto one line so `biome ci` passes formatting.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4 updated
Run: 5c72beed-851f-4266-9d48-8750405a5f9c

Co-authored-by: pauldambra <984817+pauldambra@users.noreply.github.com>
@pauldambra
pauldambra marked this pull request as ready for review July 22, 2026 11:16
@pauldambra
pauldambra requested a review from a team July 22, 2026 11:16
@stamphog

stamphog Bot commented Jul 22, 2026

Copy link
Copy Markdown

Note

🤖 stamphog reviewed 96104caabac73ef94d46ea0b44cd14d6bb5e38a1 — verdict: REFUSED

Gates denied this PR: it deletes the React Doctor CI workflow and its script (undisclosed in the PR description, which only discusses a scrollbar-rail UI feature) and is classified as too large/cross-cutting for auto-approval; there are also unresolved reviewer concerns about marker overlap and performance.

  • Deletes .github/workflows/react-doctor.yml and its comment script with no replacement and no mention in the PR description — undisclosed CI/infra behavior change
  • Classified T2-never due to size/cross-cutting scope, ineligible for auto-approval
  • Unresolved Codex P1/P2 comments: overlapping marker positions for unmeasured rows, stale cached offsets after virtualization changes, and O(n) DOM scans per scroll event
Gate mechanics and policy version
Gate Result
prerequisites all clear
deny-list matches: infra_cicd
size 1084L, 10F substantive, 1173L/11F incl. docs/generated/snapshots — within ceiling
tier classified as T2-never: T2-never (1173L, 11F, cross-cutting, unknown)
stamphog 2.0.0b3 .stamphog/policy.yml @ 92db230 · reviewed head 96104ca

Updated in place — this replaces 1 earlier stamphog review(s) on this PR.

@stamphog stamphog Bot removed the Stamphog This will request an autostamp by stamphog on small changes label Jul 22, 2026

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 24ea8de6be

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/react-doctor.yml
Generated-By: PostHog Code
Task-Id: 106723a6-379c-4fdb-bde2-78568beacdfd
Generated-By: PostHog Code
Task-Id: 106723a6-379c-4fdb-bde2-78568beacdfd
@pauldambra pauldambra added the Stamphog This will request an autostamp by stamphog on small changes label Jul 22, 2026 — with PostHog
@stamphog stamphog Bot removed the Stamphog This will request an autostamp by stamphog on small changes label Jul 22, 2026
pauldambra and others added 2 commits July 22, 2026 12:27
Generated-By: PostHog Code
Task-Id: 106723a6-379c-4fdb-bde2-78568beacdfd
Address qa/codex P2: measure() ran one querySelector per user message on
every scroll event, which in long threads is hundreds/thousands of
synchronous DOM lookups per frame. Collect rendered rows with a single
querySelectorAll pass indexed by id, and coalesce observer/scroll-driven
measures to at most one per animation frame.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@pauldambra pauldambra added the Stamphog This will request an autostamp by stamphog on small changes label Jul 22, 2026
github-actions[bot]
github-actions Bot previously approved these changes Jul 22, 2026

@github-actions github-actions 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.

Contained, additive UI feature (scrollbar marker rail) with no touch on risky territory; the flagged CI-workflow-deletion concern isn't present in the current diff (already resolved), and the P1 marker-spacing and DOM-scan-per-scroll issues were verifiably fixed in this diff. The one remaining unresolved comment is a cosmetic edge case (stale marker position for off-screen virtualized rows after unrelated layout shifts) that doesn't affect the actual jump-to-message functionality.

  • Author wrote 0% of the modified lines and has 15 merged PRs in these paths (familiarity MODERATE).
  • Unresolved Codex P2 comment on useMessageRailMarkers.ts: cached offsets for off-screen/virtualized rows aren't invalidated when layout shifts elsewhere (e.g. tool-group expand/collapse), so a marker's visual position can go stale until its row re-renders — non-blocking since clicking still jumps to the correct message by id, just worth a follow-up fix.
Gate mechanics and policy version
Gate Result
prerequisites all clear
deny-list no deny categories matched
size 849L, 8F substantive, 938L/9F incl. docs/generated/snapshots — within ceiling
tier T1-agent / T1d-complex (938L, 9F, two-areas, unknown)
stamphog 2.0.0b3 .stamphog/policy.yml @ 92db230 · reviewed head 8d82637

Generated-By: PostHog Code
Task-Id: 106723a6-379c-4fdb-bde2-78568beacdfd
@stamphog
stamphog Bot dismissed github-actions[bot]’s stale review July 22, 2026 11:49

New commits pushed (delta classified non_trivial_delta) — stamphog approval dismissed; re-review running automatically.

github-actions[bot]
github-actions Bot previously approved these changes Jul 22, 2026

@github-actions github-actions 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.

Self-contained UI feature (scrollbar message-marker rail) with no risky-territory surface touched in the current diff; Codex's prior performance/correctness findings and the CI-workflow-deletion concern are all visibly fixed or absent from the current head.

  • Author wrote 0% of the modified lines and has 15 merged PRs in these paths (familiarity MODERATE).
Gate mechanics and policy version
Gate Result
prerequisites all clear
deny-list no deny categories matched
size 859L, 8F substantive, 948L/9F incl. docs/generated/snapshots — within ceiling
tier T1-agent / T1d-complex (948L, 9F, two-areas, unknown)
stamphog 2.0.0b3 .stamphog/policy.yml @ 92db230 · reviewed head ce8554a

pauldambra commented Jul 22, 2026

Copy link
Copy Markdown
Member Author

Merge activity

  • Jul 22, 2:52 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Jul 22, 3:12 PM UTC: Graphite couldn't merge this PR because it failed for an unknown reason (GitHub is reporting that this PR is not mergeable, despite passing required status checks defined by your branch protection rules. Please check your rulesets for additional blocking criteria. Graphite Merge Queue does not currently support rulesets. Please contact Graphite support for further assistance.).

@pauldambra

Copy link
Copy Markdown
Member Author

/trunk merge

Generated-By: PostHog Code
Task-Id: 9a68b219-d8a9-45af-ae6c-3f9b1b19e7b0
@stamphog
stamphog Bot dismissed github-actions[bot]’s stale review July 22, 2026 19:59

New commits pushed (delta classified non_trivial_delta) — stamphog approval dismissed; re-review running automatically.

github-actions[bot]
github-actions Bot previously approved these changes Jul 22, 2026

@github-actions github-actions 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.

Additive, contained frontend feature (scrollbar marker rail) with no touch to risky territory (no data models, APIs, auth, billing, deps, or CI files in the current diff); the Codex P1/P2 findings from an earlier commit (one-sided estimate spacing, stale cached offsets, per-scroll DOM scans, and the workflow-file deletion) are all resolved and verifiably fixed in the current diff, plus a human approval and unit tests.

  • Author wrote 0% of the modified lines and has 15 merged PRs in these paths (familiarity MODERATE).
Gate mechanics and policy version
Gate Result
prerequisites all clear
deny-list no deny categories matched
size 866L, 8F substantive, 955L/9F incl. docs/generated/snapshots — within ceiling
tier T1-agent / T1d-complex (955L, 9F, two-areas, unknown)
stamphog 2.0.0b3 .stamphog/policy.yml @ aebec27 · reviewed head e54289c

2 updated
Run: b53b6164-a29a-4b6c-997e-d464d1a1d695

Co-authored-by: pauldambra <984817+pauldambra@users.noreply.github.com>
@stamphog
stamphog Bot dismissed github-actions[bot]’s stale review July 22, 2026 21:12

New commits pushed (delta classified non_trivial_delta) — stamphog approval dismissed; re-review running automatically.

@github-actions github-actions 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.

Self-contained UI feature (scrollbar marker rail) with no touch to auth, billing, data models, APIs, or CI/build config in the current diff; the earlier Codex-flagged issues (one-sided estimate distance, stale offset invalidation, per-scroll DOM scanning, and the CI workflow deletion) are all visibly fixed in the current diff and marked resolved, and unit tests were added for the new logic.

  • Author wrote 0% of the modified lines and has 15 merged PRs in these paths (familiarity MODERATE).
Gate mechanics and policy version
Gate Result
prerequisites all clear
deny-list no deny categories matched
size 870L, 8F substantive, 959L/9F incl. docs/generated/snapshots — within ceiling
tier T1-agent / T1d-complex (959L, 9F, two-areas, unknown)
stamphog 2.0.0b3 .stamphog/policy.yml @ 5599f91 · reviewed head 2bdc3b8

@trunk-io
trunk-io Bot merged commit e7d8d13 into main Jul 22, 2026
32 checks passed
@trunk-io
trunk-io Bot deleted the posthog-code/conversation-scrollbar-message-markers branch July 22, 2026 21:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Stamphog This will request an autostamp by stamphog on small changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants