Skip to content

fix: honor weak upward timeline scroll intent#630

Merged
Astro-Han merged 2 commits into
devfrom
codex/i595-scroll-reading-fix
May 15, 2026
Merged

fix: honor weak upward timeline scroll intent#630
Astro-Han merged 2 commits into
devfrom
codex/i595-scroll-reading-fix

Conversation

@Astro-Han
Copy link
Copy Markdown
Owner

@Astro-Han Astro-Han commented May 15, 2026

Summary

  • Treat non-nested upward wheel/touch intent as user history-reading intent regardless of weak/strong gesture classification.
  • Add user_upward_navigation diagnostics so weak upward reading no longer logs as weak_scroll_observed or strong_upward_navigation.
  • Guard scheduled restore_latest recovery so a stale RAF cannot pull the viewport back after the controller has moved out of following_latest.
  • Add controller unit coverage and a focused E2E for small wheel deltas after submit.

Why

#595 RCA showed real upward wheel input staying in following_latest because it was classified as weak. The later near-top sample then hit submit_restore_latest_after_top_reset, and the recovery path restored latest/bottom.

This is the Phase 1 fix only: it addresses the current wheel/touch RCA path without doing the full three-owner consolidation.

Related Issue

Related to #595. This PR does not close the full consolidation issue because createAutoScroll and bottomFollowLock are still deferred Phase 2 work.

Human Review Status

Pending. A human should make the final merge decision after reviewing the final diff and verification evidence.

Review Focus

  • Whether upward wheel/touch should leave latest for all non-nested gestures.
  • Whether the stale restore_latest mode guard is the right minimal protection.
  • Whether leaving the legacy scroll owners in place is acceptable for this Phase 1 boundary.

Risk Notes

  • Diagnostic reason changed for upward wheel/touch from strong_upward_navigation / weak_scroll_observed to user_upward_navigation.
  • This intentionally does not remove bottomFollowLock or createAutoScroll; those remain [Task] Consolidate session timeline scroll owners into single state machine #595 Phase 2 scope.
  • Existing keeps long timeline stable across worktree exit follow-up E2E still fails in this worktree after a single-test rerun at the pre-existing long-session render-count checkpoint: expected at least 80 rendered messages after entering a worktree, received 10. The new weak-wheel E2E and the earlier diagnostics/scrollbar cases passed.

How To Verify

Install deps: bun install --frozen-lockfile -> ok
TDD red check: controller focused test failed before implementation on user_upward_navigation / weak upward assertions -> expected red
Focused controller test: bun test --preload ./happydom.ts ./src/pages/session/session-timeline-scroll-controller.test.ts -> 23 pass, 0 fail
Typecheck: bun run typecheck -> exit 0
Focused E2E: bun run test:e2e:local -- e2e/session/session-renderer-diagnostics.spec.ts -g "honors weak upward wheel after submit" -> 1 passed
Diagnostics E2E file: bun run test:e2e:local -- e2e/session/session-renderer-diagnostics.spec.ts -> 3 passed, 1 failed in existing worktree-exit long-session case
Existing failing E2E rerun: bun run test:e2e:local -- e2e/session/session-renderer-diagnostics.spec.ts -g "keeps long timeline stable across worktree exit follow-up" -> same failure, expected >= 80 rendered messages, received 10
Diff check: git diff --check -> ok

Screenshots or Recordings

Not applicable. This is a scroll behavior/controller fix with E2E coverage, not a visual styling change.

Checklist

  • Human review status is stated above as pending, approved, or not required
  • I linked the related issue, or stated why there is no issue
  • This PR has type, primary area, and priority labels, or I requested maintainer labeling
  • I described the review focus and any meaningful risks
  • I listed the relevant verification steps and the key result for each
  • I did not introduce unrelated refactors, dependencies, generated files, or file changes beyond the stated scope
  • I manually checked visible UI or copy changes when needed, with screenshots or recordings
  • I considered macOS and Windows impact for platform, packaging, updater, signing, paths, shell, or permissions changes
  • I called out docs, release notes, dependencies, permissions, credentials, deletion behavior, generated content, or local file changes when relevant
  • I reviewed the final diff for unrelated changes and suspicious dependency changes
  • I am targeting dev, and my PR title and commit messages use Conventional Commits in English

Summary by CodeRabbit

  • Bug Fixes

    • Improved timeline scroll handling so weak upward gestures after submitting no longer force an unwanted "jump to latest"; the timeline better preserves reading position and only restores latest when appropriate.
  • Tests

    • Added and updated end-to-end and unit tests covering upward scroll gestures, intent classification, and recovery/restore behavior.

Review Change Stack

@github-actions github-actions Bot added the app Application behavior and product flows label May 15, 2026
@Astro-Han Astro-Han added bug Something isn't working ui Design system and user interface P2 Medium priority labels May 15, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 15, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 1307f3fe-055b-470e-9e76-c541453f8891

📥 Commits

Reviewing files that changed from the base of the PR and between 5b81c46 and 6ccd169.

📒 Files selected for processing (2)
  • packages/app/src/pages/session/session-timeline-scroll-controller.test.ts
  • packages/app/src/pages/session/session-timeline-scroll-controller.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/app/src/pages/session/session-timeline-scroll-controller.ts

📝 Walkthrough

Walkthrough

Reclassifies upward scrolls to user_upward_navigation, treats any non-nested upward wheel/touch as explicit, adds a guard to only restore latest when the controller is following_latest, and validates behavior with updated unit tests and an E2E that reproduces the post-submit weak-wheel scenario.

Changes

Timeline scroll behavior after submit

Layer / File(s) Summary
Scroll type definition and controller logic
packages/app/src/pages/session/session-timeline-scroll-controller.ts
Replaces strong_upward_navigation with user_upward_navigation, treats ArrowUp as explicit keyboard top intent, and treats any non-nested upward wheel/touch as explicit. Updates intent handler to map non-keyboard upward navigation to user_upward_navigation.
Restore-latest recovery guard
packages/app/src/pages/session/use-session-timeline-interaction.ts
Adds a guard so restore_latest recovery only resumes latest when the scroll controller mode is following_latest.
Unit tests for scroll gesture classification and recovery
packages/app/src/pages/session/session-timeline-scroll-controller.test.ts
Updates expectations to user_upward_navigation; adds tests for weak upward wheel leaving latest, nested weak upward wheel preserving latest, weak upward touch leaving latest, ArrowUp navigation to history, and a regression test for weak upward wheel after submit preserving reading anchor and preventing restore_latest.
E2E test for post-submit wheel scroll behavior
packages/app/e2e/session/session-renderer-diagnostics.spec.ts
Adds wheelTimelineBy helper and an E2E test that submits a prompt, performs repeated upward wheel gestures, asserts timeline movement and diagnostics (wheel_scroll / user_upward_navigation), and confirms the restore-latest-after-top-reset path is not accepted; then verifies Jump to latest behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Possibly related PRs

Suggested labels

P1, ui

Poem

🐰 I nudged the wheel, a gentle shove,
After submit it rose above.
Now tiny scrolls are read with care,
No sudden jump to latest there,
The timeline listens — soft as love. 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: fixing behavior to honor weak upward timeline scroll intent rather than ignoring it.
Description check ✅ Passed The PR description covers all required template sections: summary, why, related issue, human review status, review focus, risk notes, verification steps, and checklist. All sections are substantive and complete.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/i595-scroll-reading-fix

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Suggested priority: P2 (includes user-path files (packages/app/src/pages/session/session-timeline-scroll-controller.test.ts, packages/app/src/pages/session/session-timeline-scroll-controller.ts, packages/app/src/pages/session/use-session-timeline-interaction.ts)).

P1/P0 are reserved for maintainer confirmation. Please relabel manually if this is a release blocker, security issue, data-loss risk, or updater/runtime failure.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request updates the session timeline scroll controller to ensure that all upward navigation intents, including weak wheel and touch scrolls, transition the UI into reading history mode. This prevents the view from automatically snapping back to the latest message after a user has manually scrolled up. The changes include new E2E and unit tests, as well as a guard in the interaction hook. Feedback from the review suggests adding ArrowUp to the explicit top intent logic for consistency and removing the now-redundant strong_upward_navigation diagnostic reason.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 15, 2026

Perf delta summary

Comparator: pass

Profile / Scenario interaction median interaction worst long task max tbt frame gap p95 frame gap max jank count cls status
default / homepage-cold 40 -> 32 (-8) 56 -> 56 (0) 69 -> 61 (-8) 19 -> 11 (-8) 16.8 -> 16.8 (0) 166.7 -> 166.6 (-0.1) 4 -> 3 (-1) 0 -> 0 (0) pass
default / long-session-input-lag 56 -> 48 (-8) 64 -> 64 (0) 0 -> 0 (0) 0 -> 0 (0) 16.8 -> 16.8 (0) 16.8 -> 16.8 (0) 0 -> 0 (0) 0 -> 0 (0) pass
default / session-streaming-long 40 -> 48 (+8) 72 -> 56 (-16) 0 -> 0 (0) 0 -> 0 (0) 16.8 -> 16.8 (0) 33.4 -> 33.4 (0) 0 -> 0 (0) 0 -> 0 (0) pass
default / tool-call-expand 16 -> 16 (0) 24 -> 24 (0) 0 -> 0 (0) 0 -> 0 (0) 16.7 -> 16.7 (0) 16.7 -> 16.7 (0) 0 -> 0 (0) 0 -> 0 (0) pass
default / tool-default-open-heavy-bash 24 -> 32 (+8) 32 -> 32 (0) 64 -> 65 (+1) 14 -> 15 (+1) 50 -> 50 (0) 99.9 -> 100 (+0.1) 3 -> 3 (0) 0 -> 0 (0) pass
default / terminal-side-panel-open 48 -> 48 (0) 56 -> 48 (-8) 0 -> 0 (0) 0 -> 0 (0) 16.8 -> 16.8 (0) 33.3 -> 16.8 (-16.5) 0 -> 0 (0) 0 -> 0 (0) pass
default / session-scroll-reading 24 -> 24 (0) 24 -> 32 (+8) 0 -> 0 (0) 0 -> 0 (0) 16.7 -> 16.7 (0) 16.7 -> 16.7 (0) 0 -> 0 (0) 0.505 -> 0.505 (0) warn: cls
low-end / session-timeline-recompute 120 -> 120 (0) 120 -> 128 (+8) 105 -> 108 (+3) 146 -> 154 (+8) 83.4 -> 83.4 (0) 166.5 -> 166.7 (+0.2) 3 -> 4 (+1) 0.081 -> 0.081 (0) pass

@github-actions github-actions Bot removed the ui Design system and user interface label May 15, 2026
@Astro-Han
Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 15, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@Astro-Han Astro-Han merged commit 10ae5fb into dev May 15, 2026
32 of 41 checks passed
@Astro-Han Astro-Han deleted the codex/i595-scroll-reading-fix branch May 15, 2026 08:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app Application behavior and product flows bug Something isn't working P2 Medium priority

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant