fix(app): keep send scroll anchored to bottom#312
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📜 Recent review details🧰 Additional context used📓 Path-based instructions (2)packages/app/**/*.{ts,tsx,js,jsx}📄 CodeRabbit inference engine (packages/app/AGENTS.md)
Files:
packages/app/e2e/**/*.spec.ts📄 CodeRabbit inference engine (packages/app/e2e/AGENTS.md)
Files:
🧠 Learnings (38)📓 Common learnings📚 Learning: 2026-04-20T14:36:04.113ZApplied to files:
📚 Learning: 2026-04-20T14:36:04.113ZApplied to files:
📚 Learning: 2026-04-20T14:36:04.113ZApplied to files:
📚 Learning: 2026-04-20T14:36:04.113ZApplied to files:
📚 Learning: 2026-04-24T05:48:39.493ZApplied to files:
📚 Learning: 2026-04-23T07:23:23.849ZApplied to files:
📚 Learning: 2026-04-20T14:36:04.113ZApplied to files:
📚 Learning: 2026-04-20T14:36:04.113ZApplied to files:
📚 Learning: 2026-04-20T14:36:04.113ZApplied to files:
📚 Learning: 2026-04-20T14:36:04.113ZApplied to files:
📚 Learning: 2026-04-28T18:53:46.234ZApplied to files:
📚 Learning: 2026-04-28T11:24:35.312ZApplied to files:
📚 Learning: 2026-04-24T03:51:54.050ZApplied to files:
📚 Learning: 2026-04-28T04:56:21.338ZApplied to files:
📚 Learning: 2026-04-28T04:38:21.935ZApplied to files:
📚 Learning: 2026-04-28T05:36:25.456ZApplied to files:
📚 Learning: 2026-04-24T05:48:36.205ZApplied to files:
📚 Learning: 2026-04-20T14:36:04.113ZApplied to files:
📚 Learning: 2026-04-28T04:38:11.771ZApplied to files:
📚 Learning: 2026-04-27T12:59:49.844ZApplied to files:
📚 Learning: 2026-04-22T08:49:47.800ZApplied to files:
📚 Learning: 2026-04-27T10:33:12.228ZApplied to files:
📚 Learning: 2026-04-27T11:19:24.963ZApplied to files:
📚 Learning: 2026-04-28T04:56:18.533ZApplied to files:
📚 Learning: 2026-04-27T08:27:43.672ZApplied to files:
📚 Learning: 2026-04-28T05:36:24.561ZApplied to files:
📚 Learning: 2026-04-20T14:36:04.113ZApplied to files:
📚 Learning: 2026-04-27T11:18:47.332ZApplied to files:
📚 Learning: 2026-04-24T00:02:50.599ZApplied to files:
📚 Learning: 2026-04-28T04:38:11.727ZApplied to files:
📚 Learning: 2026-04-26T16:34:57.130ZApplied to files:
📚 Learning: 2026-04-24T05:39:58.329ZApplied to files:
📚 Learning: 2026-04-23T15:26:07.250ZApplied to files:
📚 Learning: 2026-04-28T06:47:20.342ZApplied to files:
📚 Learning: 2026-04-20T14:36:04.113ZApplied to files:
📚 Learning: 2026-04-20T14:36:04.113ZApplied to files:
📚 Learning: 2026-04-23T15:25:27.182ZApplied to files:
🔇 Additional comments (5)
📝 WalkthroughWalkthroughAdds an E2E timeline scroll probe and tests, a unit test for auto-scroll behavior, and updates auto-scroll logic to apply overflow-anchor immediately when forcing scroll after user scroll state is cleared. Changes
Sequence Diagram(s)sequenceDiagram
participant E2E as E2E Runner
participant Page as Browser Page
participant Probe as TimelineProbe (in-page)
participant Timeline as TimelineViewport
E2E->>Page: Navigate to message hash
E2E->>Page: Install TimelineProbe (creates Probe, starts RAF sampling)
E2E->>Page: Send prompt (triggers new content)
Probe-->>Page: Samples scroll geometry + performance.now() + URL
Page->>Probe: Request stop() after assertion window
Probe-->>E2E: Return collected samples
E2E->>E2E: Filter samples after send time, assert no upward jump
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Review rate limit: 2/3 reviews remaining, refill in 20 minutes. Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces a mechanism to manage overflow anchoring in the auto-scroll hook to prevent unwanted scroll jumps, accompanied by a new E2E test to verify this behavior. The review identified a potential TypeError when spreading the global window object and highlighted the need for proper cleanup of global state to ensure test isolation, providing a specific code suggestion to address the former.
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
|
@coderabbitai full review |
✅ Actions performedFull review triggered. |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/app/e2e/session/session-scroll-position.spec.ts`:
- Around line 58-59: The test currently finds the viewport via a fragile class
selector using list?.closest(".scroll-view__viewport"); change this to use a
stable test-facing selector such as a data attribute or ARIA role (e.g.
list?.closest('[data-component="scroll-viewport"]') or using a role lookup) and
update the other occurrence at the later block (lines referenced 91-93) to the
same data-component/data-action or role-based selector; ensure you update any
test setup or fixture that provides the viewport to include the chosen data
attribute so the selector resolves reliably.
- Around line 281-299: The test can falsely pass when no probe samples were
captured; after calling stopTimelineScrollProbe(page) and before computing
topJumps, assert that samples contains captured data (e.g.,
expect(samples.length).toBeGreaterThan(0)) and/or filter samples to only those
taken after the sendVisiblePrompt call (use a timestamp or correlate to the
probe's sample metadata) to ensure the predicate runs against relevant post-send
samples; then compute topJumps from that guarded/filtered samples array and
assert expect(topJumps).toEqual([]). Use the existing symbols
installTimelineScrollProbe, sendVisiblePrompt, stopTimelineScrollProbe, samples,
and topJumps to locate where to add the guard and filtering.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 708ee3eb-8115-4d68-abf9-43fca1fd17c5
📒 Files selected for processing (3)
packages/app/e2e/session/session-scroll-position.spec.tspackages/app/src/pages/session/session-auto-scroll.test.tspackages/ui/src/hooks/create-auto-scroll.tsx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
packages/app/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (packages/app/AGENTS.md)
Always prefer
createStoreover multiplecreateSignalcalls in SolidJS
Files:
packages/app/src/pages/session/session-auto-scroll.test.tspackages/app/e2e/session/session-scroll-position.spec.ts
packages/app/e2e/**/*.spec.ts
📄 CodeRabbit inference engine (packages/app/e2e/AGENTS.md)
packages/app/e2e/**/*.spec.ts: Import test utilities from../fixturesinstead of@playwright/test
Test files should be named with the patternfeature-name.spec.ts
Use lowercase, descriptive test names (e.g., 'sidebar can be toggled')
Use camelCase for variable names in tests
Use SCREAMING_SNAKE_CASE for constants in tests
Use fixture-managed cleanup withwithSession(sdk, title, callback)for temporary sessions instead of callingsdk.session.delete(...)directly
Prefer theprojectfixture for tests that need a dedicated project with LLM mocking
Usedata-component,data-action, or semantic roles for selectors instead of CSS class names or IDs
UsemodKeyfrom utils for cross-platform keyboard shortcuts (Meta on Mac, Control on Linux/Windows)
In terminal tests, type through the browser usingrunTerminal()andwaitTerminalReady()instead of writing to the PTY through the SDK
Never use wall-clock waits likepage.waitForTimeout(...)to make a test pass
Wait on observable state withexpect(...),expect.poll(...), or existing helpers instead of assuming work is finished after an action
Use locator assertions liketoBeVisible(),toHaveCount(0), andtoHaveAttribute(...)for normal UI state verification
Useexpect.poll(...)for probing mock or backend state rather than transient DOM visibility
Prefer fluent helpers and drivers when they make intent obvious and reduce locator-heavy noise in tests
Use direct locators when the interaction is simple and a helper would not add clarity
When validating routing, assert against canonical or resolved workspace slugs using shared helpers from../actionsto account for Windows canonicalization
Test one feature per test file
Callproject.trackSession(sessionID, directory?)andproject.trackDirectory(directory)for any resources created outside the fixture so teardown can clean them up
Files:
packages/app/e2e/session/session-scroll-position.spec.ts
🧠 Learnings (21)
📓 Common learnings
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 208
File: packages/app/src/components/prompt-input.tsx:1569-1611
Timestamp: 2026-04-24T05:39:58.329Z
Learning: In Astro-Han/pawwork `packages/app/src/components/prompt-input.tsx`, after the composer unification in PR `#208` (fixed in commit 5d810aa):
- `SendButton.disabled` does NOT gate on `store.mode !== "normal"`. Shell mode has a fully visible, clickable orange submit button that calls `handleSubmit` directly (same path as the Enter key in `handleKeyDown`). Do NOT suggest re-adding the mode gate.
- `SendButton` does NOT use the `buttons()` spring opacity animation (`style={buttons()}`). It is always fully visible regardless of mode.
- `WorkspaceChip` is gated on `props.homeMode && store.mode === "normal"` so it hides in shell mode (preventing it from appearing isolated/bright while neighboring controls fade).
- The left-side chip group (`aria-hidden={store.mode !== "normal"}`) covers attach/model/variant/workspace controls only; `SendButton` remains in a separate right-side sibling div.
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 270
File: packages/opencode/src/patch/index.ts:337-346
Timestamp: 2026-04-28T04:38:05.946Z
Learning: In Astro-Han/pawwork (`packages/opencode/src/patch/index.ts`), the BOM-transition surfacing gap — where `Bom.split` strips BOM before building `unified_diff`/`new_content` but `Bom.join` later re-attaches BOM on disk write, meaning BOM changes are not reflected in the diff payload — is intentionally deferred. PR `#270` is an upstream-sync graft; fixing the issue here would mix refactor + bugfix intents and drift the diff from the upstream baseline needed for clean future grafts. A dedicated follow-up PR (or upstream report) will address this. Do NOT re-flag the missing BOM-change surfacing in `ApplyPatchFileUpdate`/`ApplyPatchFileChange` as a blocking issue in PR `#270` or in future sync PRs that carry the same upstream baseline.
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 287
File: packages/opencode/src/tool/agent.ts:89-102
Timestamp: 2026-04-28T13:10:01.345Z
Learning: In `packages/opencode/src/tool/agent.ts` (Astro-Han/pawwork, PR `#287`), `makeReadLastCompletedAssistantText` intentionally scans the full child session message history (no `limit`) to find the latest completed assistant text part for `partial_result` on cancellation. Cancellation is a rare path so the extra read cost is acceptable; tool-heavy children can push the last stable assistant text far back. Do NOT suggest re-adding a fixed small limit (e.g., `limit: 5`) to this function.
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 264
File: packages/opencode/src/session/prompt.ts:108-169
Timestamp: 2026-04-27T10:33:12.228Z
Learning: In Astro-Han/pawwork (`packages/opencode/src/session/prompt.ts` and `packages/opencode/src/session/processor.ts`, PR `#264`), the loop-gate race condition between `buildLoopContext()` and `recordSyntheticBlock`/`recordSyntheticStop` is intentionally handled via idempotence guards (re-check sigKey presence / `hasStopped` inside the record helpers) rather than a full per-parent `Effect.Mutex`. Threading a `Map<MessageID, Mutex>` through the processor was considered too large a surface change for this edge case; the residual TOCTOU window only produces extra synthetic parts with no behavioral drift on the "turn ends" contract. A code comment documents the trade-off and points to a full-mutex follow-up if the race is observed in practice. Do NOT re-flag the absence of a per-parent mutex as a blocking issue in future reviews.
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 193
File: packages/app/src/pages/layout/sidebar-items.tsx:102-107
Timestamp: 2026-04-23T15:26:07.250Z
Learning: In Astro-Han/pawwork (`packages/app/src/pages/layout/sidebar-items.tsx`), the `indicator()` function in `SessionRow` intentionally renders `props.leadingSlot` (the pin button) only as a fallback when no status indicator (running/permission/error/unseen) is active. When a higher-priority status wins the slot, the pin button is removed from the DOM — this is a deliberate design choice for the merged leading slot (`#150`). The keyboard unpin path is preserved via: (1) focusing the row anchor triggers `group-focus-within` which reveals the dots menu trigger, then Tab → Enter → "Unpin Session"; (2) the context menu (right-click / Shift+F10) exposes "Unpin Session". The "always render + CSS overlay" approach was considered but rejected due to z-index/pointer-events complexity; residual `...` slot behavior is tracked in `#192`. Do NOT flag the absence of the pin button from the DOM when a status is active as an accessibility regression.
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 270
File: packages/opencode/src/tool/agent.ts:23-27
Timestamp: 2026-04-28T04:38:11.771Z
Learning: In Astro-Han/pawwork (`packages/opencode/src/tool/agent.ts`), the `subagent_session_id` field in the `Parameters` schema accepts any `Schema.String` rather than a branded `SessionID`. This is inherited upstream behavior (adopted in PR `#270`, an upstream-sync graft of upstream PR `#23244`). The fix — validating `subagent_session_id` as a `SessionID` brand up front so malformed/typo'd IDs fail explicitly rather than silently forking a new subagent session — is intentionally deferred to a follow-up PR or upstream report. Do NOT re-flag this as a blocking issue in PR `#270` or in future upstream-sync PRs that carry the same schema; flag it only in a PawWork-authored PR that touches `agent.ts` parameter validation.
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 270
File: packages/opencode/src/tool/lsp.ts:23-32
Timestamp: 2026-04-28T07:28:14.317Z
Learning: In `packages/opencode/src/tool/lsp.ts` (Astro-Han/pawwork, PR `#270`), the `Parameters` schema requires `line` and `character` for all operations, including `workspaceSymbol` and `documentSymbol` which never use coordinates. This matches the upstream `dev:packages/opencode/src/tool/lsp.ts:23-32` baseline exactly — both fields are declared as required `Schema.Number` with `>= 1` checks. The fix (per-operation schema split, or making `line`/`character` optional with handler-side presence validation for operations that need them like `goToDefinition`/`findReferences`) is deferred to a follow-up PR or upstream report to avoid mixing refactor + bug-fix intents and drifting the diff from the upstream baseline. Do NOT re-flag the required coordinates on `workspaceSymbol`/`documentSymbol` in upstream-sync PRs; flag it only in a PawWork-authored PR that directly touches `lsp.ts` parameter validation.
📚 Learning: 2026-04-28T11:24:35.312Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 287
File: packages/opencode/test/session/subagent-lifecycle-integration.test.ts:41-47
Timestamp: 2026-04-28T11:24:35.312Z
Learning: In `packages/opencode/test/session/subagent-lifecycle-integration.test.ts` (Astro-Han/pawwork, PR `#287`), the test suite intentionally uses a manual `run` helper (`Effect.runPromise(program.pipe(Effect.provide(Layer.mergeAll(SubagentRun.defaultLayer, Session.defaultLayer)), Effect.orDie))`) and raw `bun:test` test cases rather than the `testEffect(...)` harness. All 27 lifecycle tests pass with this pattern. Migration to `testEffect` + `it.live(...)` is deferred to a dedicated test-harness sweep PR to avoid fixture drift before merge. Do NOT re-flag the manual `Effect.runPromise` runner in this file as needing harness migration until that sweep PR lands.
Applied to files:
packages/app/src/pages/session/session-auto-scroll.test.tspackages/app/e2e/session/session-scroll-position.spec.ts
📚 Learning: 2026-04-28T18:53:46.234Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 308
File: packages/opencode/test/server/global-session-list.test.ts:224-259
Timestamp: 2026-04-28T18:53:46.234Z
Learning: In `packages/opencode/test/server/global-session-list.test.ts` (Astro-Han/pawwork), all `it.live(...)` test bodies intentionally use `Effect.promise(async () => { ... })` rather than `Effect.gen(function* () { ... })`. This is the established local convention for the route/pagination tests in this file (e.g., "supports cursor pagination", "session route orders by creation time", "session routes omit undefined optional fields"). Do NOT flag individual `it.live` cases in this file as needing conversion to `Effect.gen`; any harness-style migration would need to cover the entire file.
Applied to files:
packages/app/src/pages/session/session-auto-scroll.test.tspackages/app/e2e/session/session-scroll-position.spec.ts
📚 Learning: 2026-04-24T03:51:56.211Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 206
File: packages/app/e2e/prompt/prompt-footer-focus.spec.ts:131-143
Timestamp: 2026-04-24T03:51:56.211Z
Learning: In Astro-Han/pawwork E2E tests (packages/app/e2e/fixtures.ts), `project.prompt(text)` internally calls `trackSession(next.sessionID, active.directory)` after the prompt submission is observed and the active session is resolved. Tests that obtain a `sessionID` from `project.prompt()` do NOT need to call `project.trackSession(sessionID)` manually — it is already registered for teardown. Calling it again would be duplicate ownership.
Applied to files:
packages/app/src/pages/session/session-auto-scroll.test.ts
📚 Learning: 2026-04-20T14:36:04.113Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.113Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Use locator assertions like `toBeVisible()`, `toHaveCount(0)`, and `toHaveAttribute(...)` for normal UI state verification
Applied to files:
packages/app/src/pages/session/session-auto-scroll.test.tspackages/app/e2e/session/session-scroll-position.spec.ts
📚 Learning: 2026-04-27T11:19:24.963Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 271
File: packages/opencode/test/tool/websearch-auth.test.ts:0-0
Timestamp: 2026-04-27T11:19:24.963Z
Learning: In `packages/opencode/test/tool/websearch-auth.test.ts` (Astro-Han/pawwork), the tests intentionally use a small local `runWith` runner with raw `bun:test` and `Effect.runPromise` rather than the `testEffect` harness. Each test case injects a custom in-memory `Auth.Service` layer; switching to `testEffect` would be style-only churn without changing risk coverage. Do not flag these tests as needing harness migration.
Applied to files:
packages/app/src/pages/session/session-auto-scroll.test.ts
📚 Learning: 2026-04-23T07:23:23.849Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 180
File: packages/app/src/components/session/session-new-view.tsx:13-18
Timestamp: 2026-04-23T07:23:23.849Z
Learning: In pawwork (Astro-Han/pawwork), prefer using `createStore` instead of multiple `createSignal` calls only when the signals represent **coupled** object state that is updated together (i.e., there is at least one shared batch-update site where the state is changed in the same transaction). If the state fields are **independent** and are mutated by separate handlers (e.g., one handler updates only `selectedSkill` while another updates only `mode`), keep them as individual `createSignal` calls—using `createStore` for truly independent fields adds boilerplate without behavioral benefit.
Applied to files:
packages/app/src/pages/session/session-auto-scroll.test.tspackages/app/e2e/session/session-scroll-position.spec.ts
📚 Learning: 2026-04-23T15:10:21.635Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 191
File: packages/app/src/components/session/pawwork-skill-meta.ts:38-39
Timestamp: 2026-04-23T15:10:21.635Z
Learning: This repo configures Tailwind v4 with `--color-*: initial`, which effectively breaks standard Tailwind palette utilities (e.g., `text-violet-500` can resolve to no CSS variable and render as a no-op/black). For brand/accent colors that are not backed by semantic design tokens, use inline styles with the exact hex value (e.g., `style={{ color: '#8B5FBF' }}` / `homeIconStyle: { color: '#8B5FBF' }`) and add a short comment explaining that Tailwind palette utilities won’t work due to the `--color-*: initial` setup. Do not suggest replacing these inline hex colors with Tailwind palette classes anywhere in this repo.
Applied to files:
packages/app/src/pages/session/session-auto-scroll.test.ts
📚 Learning: 2026-04-20T14:36:04.113Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.113Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Use `expect.poll(...)` for probing mock or backend state rather than transient DOM visibility
Applied to files:
packages/app/e2e/session/session-scroll-position.spec.ts
📚 Learning: 2026-04-20T14:36:04.113Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.113Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Import test utilities from `../fixtures` instead of `playwright/test`
Applied to files:
packages/app/e2e/session/session-scroll-position.spec.ts
📚 Learning: 2026-04-24T03:51:54.050Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 206
File: packages/app/e2e/prompt/prompt-footer-focus.spec.ts:131-143
Timestamp: 2026-04-24T03:51:54.050Z
Learning: In Astro-Han/pawwork E2E tests under packages/app/e2e, do not manually call `project.trackSession(sessionID)` when you obtain a `sessionID` via `project.prompt(text)`. The `project.prompt()` implementation already registers `trackSession(next.sessionID, active.directory)` automatically after the prompt submission is observed and the active session is resolved, so calling `project.trackSession(sessionID)` again will create duplicate session ownership/teardown handling.
Applied to files:
packages/app/e2e/session/session-scroll-position.spec.ts
📚 Learning: 2026-04-20T14:36:04.113Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.113Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Call `project.trackSession(sessionID, directory?)` and `project.trackDirectory(directory)` for any resources created outside the fixture so teardown can clean them up
Applied to files:
packages/app/e2e/session/session-scroll-position.spec.ts
📚 Learning: 2026-04-20T14:36:04.113Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.113Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : In terminal tests, type through the browser using `runTerminal()` and `waitTerminalReady()` instead of writing to the PTY through the SDK
Applied to files:
packages/app/e2e/session/session-scroll-position.spec.ts
📚 Learning: 2026-04-20T14:36:04.113Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.113Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Never use wall-clock waits like `page.waitForTimeout(...)` to make a test pass
Applied to files:
packages/app/e2e/session/session-scroll-position.spec.ts
📚 Learning: 2026-04-20T14:36:04.113Z
Learnt from: CR
Repo: Astro-Han/pawwork PR: 0
File: packages/app/e2e/AGENTS.md:0-0
Timestamp: 2026-04-20T14:36:04.113Z
Learning: Applies to packages/app/e2e/**/*.spec.ts : Prefer fluent helpers and drivers when they make intent obvious and reduce locator-heavy noise in tests
Applied to files:
packages/app/e2e/session/session-scroll-position.spec.ts
📚 Learning: 2026-04-28T04:56:21.338Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 270
File: packages/opencode/test/tool/tool-define.test.ts:2-9
Timestamp: 2026-04-28T04:56:21.338Z
Learning: In `packages/opencode/test/tool/tool-define.test.ts` (Astro-Han/pawwork, PR `#270`), the test suite intentionally uses a `ManagedRuntime.make(Layer.mergeAll(Truncate.defaultLayer, Agent.defaultLayer))` wrapper and raw `bun:test` `test(...)` cases rather than the `testEffect(...)` harness. This code was adopted wholesale from upstream via the graft strategy (per `project_upstream_strategy.md`). Migrating to `testEffect` is deferred to a follow-up PR so as not to mix refactor + harness-migration intents and to avoid drifting the diff from the upstream baseline needed for clean future grafts. Do NOT re-flag the `ManagedRuntime.make` usage in this file as needing harness migration until that follow-up lands.
Applied to files:
packages/app/e2e/session/session-scroll-position.spec.ts
📚 Learning: 2026-04-28T04:38:21.935Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 270
File: packages/opencode/test/file/ripgrep.test.ts:9-10
Timestamp: 2026-04-28T04:38:21.935Z
Learning: In `packages/opencode/test/file/ripgrep.test.ts` (Astro-Han/pawwork, PR `#270`), the tests intentionally use a local `run` helper (`effect.pipe(Effect.provide(Ripgrep.defaultLayer), Effect.runPromise)`) rather than the `testEffect(...)` harness. This file was adopted from upstream wholesale as part of an upstream-sync graft; migrating to `testEffect` + `it.live(...)` was deferred to a separate follow-up PR to avoid mixing refactor and harness-migration intents within the sync. Do NOT re-flag the local `run` wrapper as needing harness migration until that follow-up lands.
Applied to files:
packages/app/e2e/session/session-scroll-position.spec.ts
📚 Learning: 2026-04-28T05:36:25.456Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 270
File: packages/opencode/test/tool/grep.test.ts:16-22
Timestamp: 2026-04-28T05:36:25.456Z
Learning: In `packages/opencode/test/tool/grep.test.ts` (Astro-Han/pawwork, PR `#270`), the test suite intentionally uses a manual `ManagedRuntime.make(Layer.mergeAll(...))` setup and raw `bun:test` test cases rather than the `testEffect(...)` harness. The migration to `testEffect` + `it.live(...)` + `provideTmpdirInstance(...)` is a whole-file rewrite deferred to a dedicated sweep PR that will migrate all tool tests still on the manual ManagedRuntime pattern together. Do NOT re-flag the ManagedRuntime setup in this file as needing harness migration until that sweep PR lands.
Applied to files:
packages/app/e2e/session/session-scroll-position.spec.ts
📚 Learning: 2026-04-24T00:02:50.599Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 203
File: packages/app/e2e/sidebar/sidebar-session-links.spec.ts:34-55
Timestamp: 2026-04-24T00:02:50.599Z
Learning: For Astro-Han/pawwork E2E tests under packages/app/e2e/**/*.spec.ts, do not call project.trackDirectory() or project.trackSession() before project.open() has run. The project fixture throws until open() initializes internal state. Use this ordering pattern: (1) call project.trackSession(sessionID) inside the beforeGoto callback (where state is already available), (2) call project.trackDirectory(directory) and any cross-workspace tracking like project.trackSession(id, directory) immediately after project.open() returns, and (3) if you create any resources before open() that cannot yet be tracked via the fixture, ensure you clean them up explicitly in finally blocks (e.g., cleanupSession / cleanupTestProject).
Applied to files:
packages/app/e2e/session/session-scroll-position.spec.ts
📚 Learning: 2026-04-23T15:25:27.182Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 193
File: packages/app/e2e/sidebar/sidebar-leading-slot.spec.ts:5-55
Timestamp: 2026-04-23T15:25:27.182Z
Learning: In Astro-Han/pawwork E2E tests (e.g., *.spec.ts under packages/app/e2e), reaching a real "running" session state is not achievable with the bare `sdk` fixture. Use the `project` fixture (to bootstrap the model) and orchestrate the transition with `llm.wait(1)`; even if you set `agent: "build"` and a `system` prompt via `sdk.session.promptAsync`, the current test infrastructure does not trigger an actual LLM call, so it won’t simulate "running" cheaply. Review any attempt to mock/force "running" using only `sdk` as likely ineffective unless it also uses `project` + `llm.wait(1)`.
Applied to files:
packages/app/e2e/session/session-scroll-position.spec.ts
📚 Learning: 2026-04-24T05:48:36.205Z
Learnt from: Astro-Han
Repo: Astro-Han/pawwork PR: 208
File: packages/app/e2e/app/composer-parity.spec.ts:0-0
Timestamp: 2026-04-24T05:48:36.205Z
Learning: In E2E parity tests, prefer using the existing `[data-action]` coverage when asserting UI parity. For elements whose trigger props set `data-action` (e.g., `data-action="prompt-model"` and `data-action="prompt-model-variant"` on prompt input chip triggers), you generally do not need to add separate assertions driven by `[data-component]` for parity. Avoid duplicating component-specific queries when the `[data-action]` selector sweep already includes the elements; any extra unioning of selectors should be treated as optional belt-and-suspenders rather than required.
Applied to files:
packages/app/e2e/session/session-scroll-position.spec.ts
🔇 Additional comments (5)
packages/ui/src/hooks/create-auto-scroll.tsx (2)
37-52:overflow-anchormode handling is clean and deterministic.Good refactor: mode branching is explicit and dynamic mode maps directly to
userScrolledstate.
100-103: Force-scroll ordering fix looks correct.Clearing
userScrolledand immediately syncingoverflowAnchorbefore the forced bottom move addresses the race this PR targets.packages/app/src/pages/session/session-auto-scroll.test.ts (1)
5-45: Great focused regression coverage for force-scroll anchor ordering.The test captures
overflowAnchorat the exactscrollTopwrite point, which is the critical timing contract for this bug.packages/app/e2e/session/session-scroll-position.spec.ts (2)
18-20:TimelineScrollSampleextension is appropriate.Including
urlin sampled state is useful for correlating hash transitions with scroll behavior.
117-128: Probe shutdown helper is solid.
stopTimelineScrollProbecleanly enforces installation and returns collected samples through a single stop path.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
Summary
overflow-anchorupdates before forced bottom scrolls.Why
When the session composer forces the timeline back to the latest turn after sending, dynamic overflow anchoring could still be in the user-scrolled
autostate at the exact momentscrollTopis set to the bottom. That leaves a browser-level window where DOM changes can anchor the viewport back toward the previous position, which matches the reported "send jumps to top" behavior.This PR updates the auto-scroll helper so forced bottom scrolls synchronously disable overflow anchoring before changing
scrollTop.Related Issue
No dedicated issue for the send-scroll bug yet. The related session-switch flicker is tracked separately in #311 and intentionally not fixed here.
How To Verify
bun test --preload ./happydom.ts ./src/pages/session/session-auto-scroll.test.ts bun test:e2e -- session/session-scroll-position.spec.ts session/session-send-stability.spec.ts bun typecheckAlso ran
bun testinpackages/ui; it still fails two existing diff text assertions inapply-patch-file.test.tsandsession-diff.test.ts, unrelated to this scroll change.Screenshots or Recordings
Not attached. This is a scroll-position timing fix covered by unit and E2E tests.
Checklist
dev, and my PR title and commit messages use Conventional Commits in EnglishSummary by CodeRabbit
Bug Fixes
Tests