Skip to content

fix: stabilize hold-mode assistant autoscroll#533

Open
pascalandr wants to merge 6 commits into
NeuralNomadsAI:devfrom
Pagecran:fix/hold-mode-assistant-autoscroll
Open

fix: stabilize hold-mode assistant autoscroll#533
pascalandr wants to merge 6 commits into
NeuralNomadsAI:devfrom
Pagecran:fix/hold-mode-assistant-autoscroll

Conversation

@pascalandr

Copy link
Copy Markdown
Contributor

Summary

  • Keep Hold mode latched until the user manually reaches the true bottom.
  • Restrict Hold targets to user-readable Assistant answer text.
  • Exclude tool/status/output and reflection/reasoning blocks from Hold target eligibility.

Validation

  • node --test packages/ui/src/components/virtual-follow-behavior.test.ts
  • npm run typecheck --workspace @codenomad/ui
  • npm run build --workspace @codenomad/ui

Hold mode now latches after manual escape or when the Assistant answer text reaches the viewport top, and it remains held until the user manually reaches the true bottom. Content growth, hold-target changes, and stream completion no longer re-enable follow or snap the viewport while held.

Hold target eligibility is restricted to user-readable Assistant answer text. Tool/status/output blocks and reflection/reasoning-only content are excluded from hold targeting, and held Assistant text anchors are restored across subsequent content renders.

Verification: node --test packages/ui/src/components/virtual-follow-behavior.test.ts; npm run typecheck --workspace @codenomad/ui; npm run build --workspace @codenomad/ui.
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

PR builds are available as GitHub Actions artifacts:

https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/27159386614

Artifacts expire in 7 days.
Artifacts:

  • pr-533-9aa555e00e44f02458a524135ab52494046ae201-tauri-macos
  • pr-533-9aa555e00e44f02458a524135ab52494046ae201-tauri-linux
  • pr-533-9aa555e00e44f02458a524135ab52494046ae201-tauri-windows
  • pr-533-9aa555e00e44f02458a524135ab52494046ae201-electron-macos
  • pr-533-9aa555e00e44f02458a524135ab52494046ae201-tauri-macos-arm64
  • pr-533-9aa555e00e44f02458a524135ab52494046ae201-electron-windows
  • pr-533-9aa555e00e44f02458a524135ab52494046ae201-electron-linux

@pascalandr pascalandr marked this pull request as draft June 8, 2026 19:07
Prompt submission now performs an explicit bottom jump that suppresses stale Hold latches before and after sending, so the optimistic user prompt and the new exchange return to the true bottom after manual scrolling in Hold mode.

The virtual follow controller also exposes a focused hold-clear transition for disabling Hold while held, and optimistic user rendering now keeps only the primary submitted text visible while preserving synthetic helper-part hiding.

Verified with the virtual follow behavior node test, UI typecheck, UI build, and diff whitespace checks.
@pascalandr pascalandr marked this pull request as ready for review June 8, 2026 20:05
Adds a durable submit/new-stream bottom-follow intent so Hold mode keeps the newly submitted prompt and assistant stream at the bottom until the new exchange is mounted and settled.

Suppresses stale previous Assistant hold anchors and snapshot restores while that intent is active, then preserves suppression if the old target is still current so it cannot reclaim the viewport at stream start.

Validated with node --test packages/ui/src/components/virtual-follow-behavior.test.ts, npm run typecheck --workspace @codenomad/ui, npm run build --workspace @codenomad/ui, and git diff --check.
@pascalandr

Copy link
Copy Markdown
Contributor Author

@CodeNomadBot

I want you to perform the gatekeeper checks for latest PR state

check for regressions
check for better possible implementations
Be the PR gatekeeper
Be ruthless about code quality

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

PR builds are available as GitHub Actions artifacts:

https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/27163704081

Artifacts expire in 7 days.
Artifacts: (none found on this run)

@codenomadbot

codenomadbot Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Gatekeeper review complete for the latest PR state.

Request understood: perform a ruthless review for regressions and better implementations. I treated this as review-only and did not modify code.

Findings:

  1. Blocking: normal escaped-mode rejoin is disabled during streaming assistant text.
    packages/ui/src/components/virtual-follow-list.tsx:200 makes effectiveSuspendAutoPinToBottom() true whenever there is a current holdTargetKey() and autoScroll() is false. In MessageSection, autoPinHoldTargetKey is present for any streaming assistant text while the preference is enabled (packages/ui/src/components/message-section.tsx:767-770). That means a user who scrolls up/escapes during a streaming assistant response is now treated as “suspended” even when the controller is not in active Hold mode. The existing rejoin path in canRejoinFollowFromDownScroll() (virtual-follow-list.tsx:513-516) then refuses to grant canPinToBottom, so scrolling down near the latest items no longer re-enters follow mode unless the user reaches the true bottom. The PR’s “hold latched until true bottom” requirement should apply to activeHoldTargetKey() !== null, not to every escaped streaming response that merely has an eligible future hold target.

  2. Medium: Hold eligibility is restricted, but the measured Hold target is still the whole message item.
    message-item.tsx:478-482 marks the whole .message-item-base as data-assistant-text-block="true" when any assistant text is present, and message-section.tsx:1346-1348 returns that whole message item as the Hold target. This improves eligibility filtering, but it does not actually measure the user-readable answer text element. Header/meta/actions/generating UI and any other content in the same message item can still affect targetRect.height/relativeTop and trigger or maintain Hold. A tighter implementation would put a dedicated data attribute/ref on the rendered assistant text container in MessagePart and resolve that element instead.

Validation:

  • node --test packages/ui/src/components/virtual-follow-behavior.test.ts passed: 35/35.
  • npm run typecheck --workspace @codenomad/ui could not be validated in this checkout because dependencies/types are not resolvable, starting with missing solid-js and related modules.
  • npm run build --workspace @codenomad/ui could not be validated in this checkout because vite is not installed/resolvable.

Gatekeeper verdict: do not merge as-is. The active-hold latching behavior is directionally correct, but the broad holdLatchAwayFromBottom condition regresses normal streaming rejoin behavior outside Hold mode.

--
Yours,
CodeNomadBot

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

PR builds are available as GitHub Actions artifacts:

https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/27163817328

Artifacts expire in 7 days.
Artifacts: (none found on this run)

Limit the virtual follow bottom-pin suspension gate to external suspension or an actively latched Hold target, so escaped Assistant streaming can rejoin near the bottom while active Hold remains latched until true bottom. Adds behavior coverage for future eligible hold targets versus active hold latches.
@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

PR builds are available as GitHub Actions artifacts:

https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/27164365361

Artifacts expire in 7 days.
Artifacts:

  • pr-533-8cb50ebcedea97f47269be2c143e73a1b1a3a2bb-tauri-macos-arm64
  • pr-533-8cb50ebcedea97f47269be2c143e73a1b1a3a2bb-electron-windows
  • pr-533-8cb50ebcedea97f47269be2c143e73a1b1a3a2bb-electron-linux

@pascalandr

Copy link
Copy Markdown
Contributor Author

Gatekeeper blocker from #533 (comment) addressed in c236b7f. The bottom-pin suspension now applies only to external suspension or an actively latched Hold target, so ordinary escaped streaming can rejoin near the bottom while active Hold still remains latched until true bottom. Added regression coverage; local validation passed 37/37 virtual-follow tests, UI typecheck, UI build, and diff checks. The medium note about measuring a dedicated inner Assistant text element remains a documented non-blocking follow-up.

@pascalandr

Copy link
Copy Markdown
Contributor Author

@CodeNomadBot
again

@codenomadbot

codenomadbot Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Gatekeeper re-review complete for the latest PR state after c236b7f7.

Request understood: “again” means re-run the same ruthless PR gatekeeper check against the current branch. I treated this as review-only and did not modify code.

Findings:

  1. Blocking: resolved.
    The previous blocker from fix: stabilize hold-mode assistant autoscroll #533 (comment) is fixed. packages/ui/src/components/virtual-follow-list.tsx now computes bottom-pin suspension from external suspension plus activeHoldTargetKey(), not from an eligible future holdTargetKey(). That preserves normal escaped-mode streaming rejoin while keeping actively latched Hold mode pinned off until true bottom. The new regression coverage in virtual-follow-behavior.test.ts exercises both sides of that behavior.

  2. Non-blocking implementation follow-up remains.
    Hold eligibility is still filtered via data-assistant-text-block on the full .message-item-base, so the measured target remains the whole message item rather than a dedicated inner Assistant answer text element. This is better than the original broad assistant selector and does exclude reasoning/tool-only items, but it is not the tightest possible implementation. I agree with the thread’s characterization that this is a follow-up, not a merge blocker for this stabilization PR.

Validation from this bot checkout:

  • node --test packages/ui/src/components/virtual-follow-behavior.test.ts passed: 37/37.
  • npm run typecheck --workspace @codenomad/ui could not be validated in this checkout because dependencies/types are not resolvable, starting with missing solid-js and related modules.
  • npm run build --workspace @codenomad/ui could not be validated in this checkout because vite is not installed/resolvable.

Gatekeeper verdict: mergeable from code-review perspective. I do not see a remaining blocking regression in the latest diff. The CI/local dependency-backed typecheck and build results should be trusted over this bot checkout for those two commands because this environment is missing required packages.

--
Yours,
CodeNomadBot

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown

PR builds are available as GitHub Actions artifacts:

https://github.com/NeuralNomadsAI/CodeNomad/actions/runs/27164936545

Artifacts expire in 7 days.
Artifacts:

  • pr-533-c236b7f7e628eee17f397225c329411e40e536c2-tauri-macos
  • pr-533-c236b7f7e628eee17f397225c329411e40e536c2-tauri-linux
  • pr-533-c236b7f7e628eee17f397225c329411e40e536c2-electron-macos
  • pr-533-c236b7f7e628eee17f397225c329411e40e536c2-tauri-macos-arm64
  • pr-533-c236b7f7e628eee17f397225c329411e40e536c2-tauri-windows
  • pr-533-c236b7f7e628eee17f397225c329411e40e536c2-electron-windows
  • pr-533-c236b7f7e628eee17f397225c329411e40e536c2-electron-linux

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.

1 participant