spec: prevent overshoot scrolling code diff to top (#9808)#10228
spec: prevent overshoot scrolling code diff to top (#9808)#10228lonexreb wants to merge 5 commits intowarpdotdev:masterfrom
Conversation
There was a problem hiding this comment.
Overview
This spec defines a gesture-window clamp for nested scroll containers to prevent in-progress overscroll from moving the parent blocklist.
Concerns
- The behavior contract does not define ownership after a new gesture starts at an inner-scroll boundary, so implementers could bubble only the first delta and then consume the rest of the same gesture.
- The scope expands from code diff to all blocklist-embedded scroll containers, but acceptance criteria, implementation pointers, and tests remain diff-only.
- The scrollbar click acceptance criterion should identify which scrollbar target bypasses the gesture clamp.
Verdict
Found: 0 critical, 2 important, 1 suggestions
Request changes
Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).
Powered by Oz
| scroll-event-stream timing: events within ≤200ms of each other | ||
| belong to the same gesture (matches macOS/Windows trackpad | ||
| inertia conventions). | ||
| - B3. After a 200ms gap, the next scroll arriving at the diff |
There was a problem hiding this comment.
| - B4. Same behavior at top AND bottom edges. | ||
| - B5. Click-to-jump (clicking the scrollbar) bypasses this rule | ||
| — that's a discrete event, not part of a gesture. | ||
| - B6. The new behavior applies to **all** scroll containers |
There was a problem hiding this comment.
| top remains visible. | ||
| - A2. Stop scrolling for >200ms, scroll up again — blocklist | ||
| scrolls normally. | ||
| - A3. Click the scrollbar above the diff to jump up — works as |
There was a problem hiding this comment.
💡 [SUGGESTION] Clarify whether this means the inner diff scrollbar, the parent blocklist scrollbar, or both, because the bypass behavior depends on which scrollable receives the click.
Co-Authored-By: Warp <agent@warp.dev>
|
/oz-review |
|
I'm re-reviewing this spec-only pull request in response to a review request. You can view the conversation on Warp. I completed the review and no human review was requested for this pull request. Comment Powered by Oz |
There was a problem hiding this comment.
Overview
This spec defines gesture ownership for wheel/trackpad scrolling inside embedded code-diff containers, including boundary clamping, the 200ms gesture window, acceptance criteria, and tests.
Concerns
- The proposed V1 scope conflicts with the PR description: the description says the behavior applies to all blocklist-embedded scroll containers, while the spec limits the behavior to code-diff containers and excludes other embedded containers. Resolve the scope before implementation so reviewers know which surfaces must be changed and tested.
Verdict
Found: 0 critical, 1 important, 0 suggestions
Request changes
Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).
Powered by Oz
| Clicking or dragging the parent blocklist scrollbar affects only | ||
| the parent blocklist scroll position. Neither scrollbar click | ||
| changes gesture ownership for later wheel/trackpad events. | ||
| - B6. V1 applies only to code-diff scroll containers embedded in |
There was a problem hiding this comment.
|
Round-1 fixes for oz-for-oss review: (1) added Gesture Ownership at Boundaries subsection — boundary-state at gesture start is sole binding decision point; no first-delta bubble then consume; (2) reconciled V1 scope to ALL blocklist-embedded scrollable containers (diff, tree, table, log) with enumerated component identifiers and acceptance/tests covering ≥2 container types; (3) defined scrollbar bypass precisely via |
|
/oz-review |
|
I'm re-reviewing this spec-only pull request in response to a review request. You can view the conversation on Warp. I completed the review and no human review was requested for this pull request. Comment Powered by Oz |
There was a problem hiding this comment.
Overview
This spec defines a gesture-ownership model to keep in-progress wheel/trackpad scrolling inside blocklist-embedded scroll containers until a 200ms idle gap, with scrollbar pointer actions bypassing the clamp.
Concerns
- The V1 scope says all blocklist-embedded scrollable containers are covered, but the behavior and validation only define vertical top/bottom scrolling and representative two-container coverage.
- The scrollbar bypass contract relies on ARIA roles and CSS pseudo-elements, which do not match Warp's custom-rendered scrollbar hit-testing model.
- The implementation pointers promise concrete identifiers but still leave implementers to discover the actual component wrappers.
Verdict
Found: 0 critical, 2 important, 1 suggestions
Request changes
Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).
Powered by Oz
|
|
||
| ## Scope (V1) | ||
|
|
||
| V1 applies to ALL blocklist-embedded scrollable containers, not |
There was a problem hiding this comment.
| - Wheel/trackpad input that happens to occur over the scrollbar | ||
| area still respects the gesture-window contract above; only | ||
| actual click/drag pointer input bypasses. | ||
| - B5a. **"Scrollbar target" defined.** A scrollbar target is any |
There was a problem hiding this comment.
|
|
||
| - A "blocklist-embedded scrollable container" is any descendant | ||
| scroll container of the blocklist whose root element matches | ||
| one of the following identifiers (extend this list as |
There was a problem hiding this comment.
💡 [SUGGESTION] Replace the placeholder discovery guidance with the actual component or wrapper names for each in-scope container; otherwise different implementers can opt in different subsets despite the all-containers scope.
|
Round-2 fixes: (1) generalized clamp to both vertical AND horizontal axes — per-axis boundary check, axis-lock for diagonal gestures (>=70% threshold then first-boundary-collision tiebreaker for ambiguous diagonals); (2) replaced ARIA/CSS-pseudo scrollbar contract with Warp's actual |
|
/oz-review |
|
I'm re-reviewing this spec-only pull request in response to a review request. You can view the conversation on Warp. I completed the review and no human review was requested for this pull request. Comment Powered by Oz |
There was a problem hiding this comment.
Overview
This spec defines gesture ownership for blocklist-embedded scroll containers and includes acceptance criteria, implementation pointers, and a test plan for wheel/trackpad and scrollbar behavior.
Concerns
- Ambiguous diagonal gestures can still resolve ownership after a mid-gesture boundary collision, which conflicts with the binding rule that ownership is decided only at gesture start.
- The 200ms gesture boundary is described inconsistently as <=200ms, >=200ms, and >200ms across the behavior contract, acceptance criteria, and implementation notes.
- Some implementation pointers need correction before implementation: standalone diff scope is inconsistent with blocklist-only scope, the scrollbar hit-test API is referenced as existing but is not present in the current shared scrollbar module, and the suggested owner enum cannot represent mixed per-axis ownership.
Verdict
Found: 0 critical, 5 important, 0 suggestions
Request changes
Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).
Powered by Oz
| first boundary collision**: the first axis whose boundary the | ||
| inner container is already at decides ownership for that axis; | ||
| if neither is at a boundary, the gesture is provisionally | ||
| inner-owned on both axes and the lock resolves to whichever |
There was a problem hiding this comment.
|
|
||
| - B-OWN. **Boundary state at gesture start is the sole binding | ||
| decision point.** When a new wheel/trackpad gesture starts (the | ||
| first event after ≥200ms of input idleness), ownership is |
There was a problem hiding this comment.
| | Container type | File path | Component identifier | | ||
| | ----------------- | ------------------------------------------------------------- | ------------------------------------------------------------ | | ||
| | Code diff (inline action) | `app/src/ai/blocklist/inline_action/code_diff_view.rs` | The diff view's outer scrollable wrapper (constructed via the shared scrollable element from `warpui_core`) | | ||
| | Code diff (standalone) | `app/src/code/diff_viewer.rs` | `diff_viewer` scrollable region | |
There was a problem hiding this comment.
Code diff (standalone) conflicts with the stated blocklist-embedded-only scope and the out-of-scope exclusion for top-level app panels; either limit this row to embedded/inline display modes or explain why the standalone full-pane diff is included in V1.
|
|
||
| The 200ms gesture-window state is implementable as | ||
| `last_scroll_time: Option<Instant>` plus a current gesture | ||
| owner (`InnerVertical`, `InnerHorizontal`, `Parent`, or `None`) |
There was a problem hiding this comment.
Parent/InnerVertical/InnerHorizontal value.
| `last_scroll_time` is treated as a new gesture and re-evaluates | ||
| ownership from boundary state per B-OWN. | ||
|
|
||
| Scrollbar pointer hit-testing resolves via the |
There was a problem hiding this comment.
ScrollbarTarget hit-test API as the routing mechanism, but the current shared_scrollbar.rs exposes geometry helpers without that API; state that implementation must add this API or point to the existing hit-test path to avoid an unimplementable pointer.
|
Round-3 review fixes (commit e8be75e):
|
|
/oz-review |
Spec for #9808. Clamp in-progress scroll gestures to the diff container; only new gestures (after a 200ms settling window) bubble up to the parent blocklist. Applies to all blocklist-embedded scroll containers, not just diff.
Closes (spec-only) #9808.