Skip to content

fix(ios): chat snaps back to bottom when scrolling to top via status-bar tap#100502

Merged
steipete merged 2 commits into
mainfrom
claude/jolly-bartik-bef18e
Jul 6, 2026
Merged

fix(ios): chat snaps back to bottom when scrolling to top via status-bar tap#100502
steipete merged 2 commits into
mainfrom
claude/jolly-bartik-bef18e

Conversation

@steipete

@steipete steipete commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Fixes an issue where iPhone users on the Chat tab who trigger the system scroll-to-top (tapping the status-bar area at the top of the screen, right next to the gateway status pill) see the transcript start scrolling up and then immediately snap back to the bottom, making older messages unreachable through that gesture. Reported from a device where a tap at the top right of the chat screen produced "a quick scroll that immediately scrolls me back to the bottom."

Why This Change Was Made

Reader-managed chat scrolling (#98258) only releases the auto-follow target on the .interacting scroll phase, i.e. finger drags. System-driven animated scrolls — the status-bar scroll-to-top, keyboard avoidance, accessibility scroll actions — report .animating, so followTarget stayed .latest and the next timeline tick (streaming delta or message refresh) re-issued a scroll to the bottom sentinel, cancelling the system scroll mid-flight. The view's own one-shot positioning always runs in a nil-animation transaction and therefore never reports .animating, so any .animating phase is reader/system-driven and now releases the follow target. This matches Android, whose ChatReaderScrollController already releases the follow for any scroll it did not apply itself (isScrollInProgress gated by isApplyingScroll); iOS was the outlier.

User Impact

Tapping the status bar to scroll to the top of the iOS chat transcript now works: the view stays where the system scroll put it, and the existing "Jump to latest" pill appears for returning to the live edge. The same shared view powers macOS web chat, which picks up the identical behavior for system-animated scrolls.

Evidence

  • New phase-policy regression tests in ChatReaderScrollStateTests prove .interacting/.animating release the follow target while .idle/.tracking/.decelerating keep it.
  • swift test --package-path apps/shared/OpenClawKit --parallel: 346 tests in 34 suites pass (rerun green on latest main after this change).
  • swiftformat --lint --config config/swiftformat clean on both changed files.
  • Structured autoreview (Codex, gpt-5.5): no accepted/actionable findings.

@openclaw-barnacle openclaw-barnacle Bot added size: XS maintainer Maintainer-authored PR labels Jul 6, 2026
@clawsweeper

clawsweeper Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 5, 2026, 9:27 PM ET / 01:27 UTC.

Summary
The PR changes shared SwiftUI chat scroll handling to release auto-follow on .animating as well as .interacting, adds phase-policy tests, and refreshes native i18n line metadata.

PR surface: Other +26. Total +26 across 3 files.

Reproducibility: Source-reproducible, but not live-reproduced here: current main does not release follow mode for .animating, while the timeline handler still scrolls to bottom when .latest remains active. A high-confidence live check would be an iOS device or simulator status-bar tap during an active transcript.

Review metrics: none identified.

Root-cause cluster
Relationship: canonical
Canonical: #100502
Summary: This PR is the narrow canonical follow-up for the iOS status-bar snap-back edge in the already-merged native reader-managed scroll model.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🌊 off-meta tidepool
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • none.

Risk before merge

  • [P1] This read-only review did not independently exercise the iOS status-bar gesture on a device or simulator, so runtime proof remains the maintainer report plus source-path and test evidence.

Maintainer options:

  1. Decide the mitigation before merge
    Land the narrow phase-policy fix after normal maintainer approval and mergeability gates, keeping the shared SwiftUI helper and focused tests.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge

  • [P1] The protected maintainer label and clean review leave a human approval/mergeability decision, not a narrow automated repair task.

Maintainer decision needed

  • Question: Should maintainers land this protected-label native chat scroll fix after the standard mergeability checks are satisfied?
  • Rationale: The PR carries the protected maintainer label and has no narrow ClawSweeper repair blocker, so cleanup automation should not close, merge, or rewrite it without human intent.
  • Likely owner: steipete — This person merged the original reader-managed scroll work and owns the current protected-label follow-up PR.
  • Options:
    • Land after standard checks (recommended): Approve or merge once GitHub reports the exact head mergeable and maintainers are comfortable with the source-plus-test proof.
    • Ask for device proof: Request an iOS simulator or device recording of the status-bar scroll-to-top path before landing if visual runtime proof is desired.
    • Pause the follow-up: Leave the PR open if maintainers want broader native chat scroll validation before changing the shared SwiftUI phase policy.

Security
Cleared: The diff only changes SwiftUI chat scroll policy, adjacent Swift tests, and generated native i18n line metadata; no security or supply-chain surface was touched.

Review details

Best possible solution:

Land the narrow phase-policy fix after normal maintainer approval and mergeability gates, keeping the shared SwiftUI helper and focused tests.

Do we have a high-confidence way to reproduce the issue?

Source-reproducible, but not live-reproduced here: current main does not release follow mode for .animating, while the timeline handler still scrolls to bottom when .latest remains active. A high-confidence live check would be an iOS device or simulator status-bar tap during an active transcript.

Is this the best way to solve the issue?

Yes, this is the best narrow fix: shared OpenClawChatView owns the SwiftUI scroll phase policy, and the Android sibling already releases follow for non-self-applied scrolling. A separate controller, config option, or channel-specific workaround would be broader than the bug requires.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against f12312d69b13.

Label changes

Label justifications:

  • P2: The PR fixes a native chat scroll regression with limited blast radius and no crash, security, or data-loss signal.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🌊 off-meta tidepool and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Not applicable: The protected maintainer label makes the external contributor proof gate not applicable; no inspectable iOS device recording was provided in the PR.
Evidence reviewed

PR surface:

Other +26. Total +26 across 3 files.

View PR surface stats
Area Files Added Removed Net
Source 0 0 0 0
Tests 0 0 0 0
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 3 32 6 +26
Total 3 32 6 +26

What I checked:

Likely related people:

  • christopheraaronhogg: Authored the merged reader-managed native chat scrolling PR that introduced the touched SwiftUI reader policy, Android sibling controller, and adjacent tests. (role: introduced behavior; confidence: high; commits: ab2761f3a59a; files: apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatView.swift, apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatReaderScrollController.kt, apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatReaderScrollStateTests.swift)
  • steipete: Merged the reader-managed scroll PR, co-authored its hardening commits, and owns this narrow native chat scroll follow-up path. (role: recent merger and adjacent owner; confidence: high; commits: ab2761f3a59a, 56318f98f750; files: apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatView.swift, apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatReaderScrollStateTests.swift, apps/.i18n/native-source.json)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (1 earlier review cycle)
  • reviewed 2026-07-06T00:36:28.018Z sha e23ca52 :: needs real behavior proof before merge. :: none

@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P2 Normal backlog priority with limited blast radius. labels Jul 6, 2026
@steipete
steipete force-pushed the claude/jolly-bartik-bef18e branch from 56318f9 to c8478dd Compare July 6, 2026 06:41
@steipete
steipete merged commit 5713f1b into main Jul 6, 2026
7 checks passed
@steipete
steipete deleted the claude/jolly-bartik-bef18e branch July 6, 2026 06:41

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

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: c8478dd2f4

ℹ️ 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".

/// avoidance). Not releasing there lets the next timeline tick yank the reader back down.
func chatReaderScrollReleasesFollow(_ phase: ScrollPhase) -> Bool {
switch phase {
case .interacting, .animating:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Badge Keep own scroll animations from clearing follow state

SwiftUI reports .animating for programmatic scrollPosition/ScrollViewReader moves, and this view uses moveScrollPosition for auto-follow, new-turn positioning, and the jump-to-latest action. When one of those reader-owned scrolls enters this branch, it is treated as user/system departure and clears followTarget, so rapid streaming updates or a jump-to-latest/new-turn scroll can stop following or show the jump pill after our own scroll rather than an actual manual departure. Gate .animating with an applying-scroll flag (as the Android controller does) instead of always releasing follow.

Useful? React with 👍 / 👎.

vincentkoc added a commit to zhangqueping/openclaw that referenced this pull request Jul 6, 2026
* origin/main: (1287 commits)
  fix(android): block loopback canvas navigation (openclaw#99874)
  fix(hooks): suppress unhandled stdout/stderr stream errors in gmail watcher (openclaw#100519)
  fix(memory-core): guard qmd mcporter JSON.parse against non-JSON stdout (openclaw#98381)
  fix(build): fall back to tsx for build TypeScript scripts (openclaw#91262)
  feat(skills): suggest saving detected reusable workflows by default (openclaw#95477) (openclaw#100692)
  docs(changelog): remove generated release-note entries
  feat(telegram): offer BotFather web app flow in setup help and docs (openclaw#100540)
  fix(ios): unify Talk and Settings row typography on one branded detail row (openclaw#100515)
  feat(gateway): add persisted crash-loop breaker and fatal-config exit contract
  refactor(macos): lock and unify PortGuardian tunnel record persistence so concurrent app instances cannot lose orphan records (openclaw#100601)
  fix: stop reconnecting on protocol mismatch (openclaw#98414)
  fix(maint): reuse recent hosted gates after rebase (openclaw#100663)
  fix(ui): reopen web terminals without stale content (openclaw#100665)
  fix(browser): diagnose empty WSL2 Chrome replies (openclaw#100590)
  fix(ios): chat snaps back to bottom when scrolling to top via status-bar tap (openclaw#100502)
  Treat already-compacted CLI compaction as no-op (openclaw#99136)
  docs(changelog): remove direct main fix entry
  fix(feishu): strip internal tool-trace banners from outbound text (openclaw#98705)
  fix(message): thread --limit through to CLI formatter and surface provider pagination hints (openclaw#99089)
  fix(voyage): close response body stream when batch output JSONL parsing throws (openclaw#98840)
  ...

# Conflicts:
#	extensions/memory-wiki/package.json
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 6, 2026
…bar tap (openclaw#100502)

* fix(ios): stop chat snapping back to bottom after system scroll-to-top

* chore(i18n): sync native inventory after chat scroll fix
giodl73-repo pushed a commit to giodl73-repo/openclaw that referenced this pull request Jul 8, 2026
…bar tap (openclaw#100502)

* fix(ios): stop chat snapping back to bottom after system scroll-to-top

* chore(i18n): sync native inventory after chat scroll fix
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maintainer Maintainer-authored PR P2 Normal backlog priority with limited blast radius. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: XS status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant