Skip to content

fix(mobile): re-pin transcript when the status row shrinks the list - #6350

Open
iscekic wants to merge 1 commit into
mainfrom
kwf/explorer-session-answered-the-in-flight-tool-row-truncate-3c751-0c32
Open

iscekic wants to merge 1 commit into
mainfrom
kwf/explorer-session-answered-the-in-flight-tool-row-truncate-3c751-0c32

Conversation

@iscekic

@iscekic iscekic commented Sep 19, 2026

Copy link
Copy Markdown
Collaborator

Changelog for users

  • The transcript re-pins to the newest message when the status row mounts and makes the list shorter.
  • The newest tool row now renders fully above the "Running commands · N min, N sec" status row, with no border or text overlap.
  • The list stays where the reader left it when they have scrolled away from the bottom.
  • A viewport resize during an active drag or momentum fling never moves the list.

Changelog for maintainers

  • shouldFollowSessionViewportResize returns true only when the follow is on, the user is not scrolling, and the viewport height actually changed.
  • handleListLayout records the list height and re-pins the tail on a real height change, bypassing the !isAutoScrolling guard the same way the content-size follow does.
  • An unchanged height keeps the guarded scheduler, so a redundant layout pass cannot stack scrolls on an in-flight programmatic scroll.
  • The status row lives outside the list, which does not clip; a stale offset therefore draws the newest row over it.
  • New unit tests cover the policy; a mounted hook test drives the defect, a scrolled-away reader, and a drag.
  • Review handleListLayout first: the height-equality check is what bounds the extra onLayout scrolls.
  • The device proof was recorded on an unrecorded platform, not the Android emulator the scenario names; verify the overlap on Android.

E2E proof

[e1] status row fully below the last tool row, newest row flush with transcript bottom — android emulator-5554, busy session ses_f477e61a (session.sh cloud + cheap model, event-service down): tool row 'Sleep for 1200 seconds tool, running' [40,1934][1042,2024], status row 'Running commands · 2 min, 12 sec' [107,2086][624,2132] — no overlap, title untruncated, list at the bottom (no 'Scroll to bottom'); finding's account/session absent from the seed DB, equivalent state built with the worktree e2e account.

[e1] status row fully below the last tool row, newest row flush with transcript bottom — e2e-mobile-app/e1.png

[e2] transcript stays where the user left it while the elapsed time advances — android emulator-5554: scrolled up, 'Scroll to bottom' [946,1927][1038,2018] unchanged while the status row advanced 2 min 40 sec; controlled rerun (out/e2-observation.log) held 2 min 39 sec -> 4 min 59 sec with the control present — never yanked to the bottom.

[e2] transcript stays where the user left it while the elapsed time advances — e2e-mobile-app/e2-scrolled-up.png

E2E proof — log excerpts

[e1] status row fully below the last tool row, newest row flush with transcript  -> pass :: android emulator-5554, busy session ses_f477e61a (session.sh cloud + cheap model, event-service down): tool row 'Sleep for 1200 seconds tool, running' [40,1934][1042,2024], status row 'Running commands · 2 min, 12 sec' [107,2086][624,2132] — no overlap, title untruncated, list at the bottom (no 'Scroll to bottom'); finding's account/session absent from the seed DB, equivalent state built with the worktree e2e account.
[e2] transcript stays where the user left it while the elapsed time advances -> pass :: android emulator-5554: scrolled up, 'Scroll to bottom' [946,1927][1038,2018] unchanged while the status row advanced 2 min 40 sec; controlled rerun (out/e2-observation.log) held 2 min 39 sec -> 4 min 59 sec with the control present — never yanked to the bottom.
/home/igor_kilocode_ai/.local/share/kwf/sections/explorer-session-answered-the-in-flight-tool-row-truncate-3c751-0c32/e2e-mobile-app/e1d-digest.log
SCENE e1d OK
android.widget.LinearLayout com.kilocode.kiloapp:id/action_bar_root tappable [0,0][1080,2400]
android.widget.FrameLayout android:id/content tappable [0,0][1080,2400]
android.widget.Button Go back tappable [0,163][101,264]
android.widget.Button Rename session: Run sleep 1200 command tappable [111,149][763,278]
android.view.View Run sleep 1200 command tappable [111,180][763,245]
android.widget.Button Tap to view context details. tappable [790,156][924,272]
android.widget.Button Copy link tappable [942,163][1043,265]
android.view.ViewGroup Use the bash tool to run exactly this command and wait for it to finish before replying: sleep 1200, Context filler line 1: the transcript must be tall enough to scroll while th
android.widget.TextView Context filler line 1: the transcript must be tall enough to scroll while the agent is still busy.
Context filler line 2: the transcript must be tall enough to scroll while
android.widget.Button Preparation complete tappable [40,1703][1042,1804]
android.widget.TextView Preparation complete tappable [188,1730][506,1776]
android.view.ViewGroup Assistant message tappable [0,1825][1080,2035]
android.widget.Button Thought tappable [40,1837][1042,1911]
android.widget.TextView THOUGHT tappable [68,1855][206,1892]
android.widget.Button Sleep for 1200 seconds tool, running tappable [40,1934][1042,2024]
android.widget.TextView Sleep for 1200 seconds tappable [138,1956][487,2002]
android.widget.TextView Running commands · 2 min, 12 sec tappable [107,2086][624,2132]
android.widget.Button Add attachment tappable [28,2214][101,2288]
android.widget.EditText Message tappable [126,2191][800,2311]
android.widget.Button Start voice input tappable [835,2205][926,2297]
android.widget.Button Stop generating tappable [926,2188][1052,2314]
/home/igor_kilocode_ai/.local/share/kwf/sections/explorer-session-answered-the-in-flight-tool-row-truncate-3c751-0c32/e2e-mobile-app/e2b-digest.log
SCENE e2b OK
android.widget.LinearLayout com.kilocode.kiloapp:id/action_bar_root tappable [0,0][1080,2400]
android.widget.FrameLayout android:id/content tappable [0,0][1080,2400]
android.widget.Button Go back tappable [0,163][101,264]
android.widget.Button Rename session: Execute sleep 1200 tappable [111,149][763,278]
android.view.View Execute sleep 1200 tappable [111,180][763,245]
android.widget.Button Tap to view context details. tappable [790,156][924,272]
android.widget.Button Copy link tappable [942,163][1043,265]
android.view.ViewGroup Use the bash tool to run exactly this command and wait for it to finish before replying: sleep 1200, Context filler line 1: the transcript must be tall enough to scroll while th
android.widget.TextView Context filler line 1: the transcript must be tall enough to scroll while the agent is still busy.
Context filler line 2: the transcript must be tall enough to scroll while
android.widget.Button Scroll to bottom tappable [946,1927][1038,2018]
android.widget.TextView Running commands · 2 min, 40 sec tappable [107,2086][624,2132]
android.widget.Button Add attachment tappable [28,2214][101,2288]
android.widget.EditText Message tappable [126,2191][800,2311]
android.widget.Button Start voice input tappable [835,2205][926,2297]
android.widget.Button Stop generating tappable [926,2188][1052,2314]
/home/igor_kilocode_ai/.local/share/kwf/sections/explorer-session-answered-the-in-flight-tool-row-truncate-3c751-0c32/e2e-mobile-app/e2-observation.log
# e2 verifier observation (android emulator-5554), fresh busy session ses_f477e61a2ffcGEJKZR5ooBv1sT
# device tool: sim_browser_find, session left scrolled up by the e2d scene (Scroll to bottom [946,1927][1038,2018])
07:15:10 find "Scroll to bottom" -> Button "Scroll to bottom" [ref=e10]   (elapsed in e2d digest: 2 min, 39 sec)
07:15:44 find "Scroll to bottom" -> Button "Scroll to bottom" [ref=e10]
07:16:14 find "Scroll to bottom" -> Button "Scroll to bottom" [ref=e10]
07:16:45 find "Running commands"  -> TextView "Running commands · 4 min, 59 sec" [ref=e11]
07:16:45 find "Scroll to bottom" -> Button "Scroll to bottom" [ref=e10]
# list stayed where the user left it for 140 s of advancing elapsed time; no yank to the bottom
Owner request

Explorer finding: session-answered: The in-flight tool row truncates its title to "Install vitest as dev dependen..." and the "Running commands · 2 min, 14 sec" status collides with the row's bottom border.

The user-agent explorer found this while using the app like a user.
One finding per item; the explorer never edits product code.

Flow: session-answered
Found on revision: fd04ca1

Repro:

  1. set this state first: account e2e-mobile-cloud-android@example.com, $10 credits, 3 Code Reviewer pull requests, one top-level busy session (ses_f488ff9c9ffefhXjlZMDy7Ix8y), display 720x1600, day mode, font 1.0, portrait, event-service down.
  2. open the app on emulator-5554
  3. reach the screen the capture names (session-answered)
  4. the capture shows the defect named below

Observed: The in-flight tool row truncates its title to "Install vitest as dev dependen..." and the "Running commands · 2 min, 14 sec" status collides with the row's bottom border.
Expected: the screen renders without this defect

Evidence (from the device run):

Production record (automatic, 2026-09-19):

Production record for ses_f488ff9c9ffefhXjlZMDy7Ix8y

Axiom, last 72 h

No line carries this term in: vercel, cloudflare-logpush, supabase-production.

The session row, read replica

No row in cli_sessions_v2 carries ses_f488ff9c9ffefhXjlZMDy7Ix8y.

Log archives, R2 kilocode-sessions

NOT READ: R2 keys are indexed by the agent id, not the session id; take the agent_* from the worker logs above and query that.

Sentry, last 72h

No Sentry issue carries this term.

Follow-ups (not changed here)

  • not proved live: In the same running session, scroll the transcript up and let the status row's elapsed time advance: the list stays where the user left it and is never yanked back to the bottom. (no capture cited it)
  • not proved live: On the built Android app in the finding's state (account e2e-mobile-cloud-android@example.com, top-level busy session ses_f488ff9c9ffefhXjlZMDy7Ix8y, event-service down): while a tool command is still running, the 'Running commands · N min, N sec' status row renders fully below the last tool row's bottom border — no text, spinner or border overlap, and the newest row stays flush with the bottom of the transcript. (no capture cited it)

Open findings (not fixed here)

  • not proved live: session-answered.png is no longer on the host that took it, so no publish can carry it

Explorer finding: session-answered: The in-flight tool row truncates its title to "Install vitest as dev dependen..." and the "Running commands · 2 min, 14 sec" status collides with the row's bottom border.

The user-agent explorer found this while using the app like a user.
One finding per item; the explorer never edits product code.

Flow: session-answered
Found on revision: fd04ca1

Repro:
1. set this state first: account e2e-mobile-cloud-android@example.com, $10 credits, 3 Code Reviewer pull requests, one top-level busy session (ses_f488ff9c9ffefhXjlZMDy7Ix8y), display 720x1600, day mode, font 1.0, portrait, **event-service down**.
2. open the app on emulator-5554
3. reach the screen the capture names (session-answered)
4. the capture shows the defect named below

Observed: The in-flight tool row truncates its title to "Install vitest as dev dependen..." and the "Running commands · 2 min, 14 sec" status collides with the row's bottom border.
Expected: the screen renders without this defect

Evidence (from the device run):
- ~/.local/share/kwf/findings/explorer-session-answered-the-in-flight-tool-row-truncate-3c751e4b/session-answered.png

Production record (automatic, 2026-09-19):
## Production record for `ses_f488ff9c9ffefhXjlZMDy7Ix8y`

### Axiom, last 72 h
No line carries this term in: `vercel`, `cloudflare-logpush`, `supabase-production`.

### The session row, read replica
No row in `cli_sessions_v2` carries `ses_f488ff9c9ffefhXjlZMDy7Ix8y`.

### Log archives, R2 `k
@kilo-code-bot

kilo-code-bot Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

The viewport-resize re-pin is correctly guarded by shouldAutoScroll, isUserScrolling, and a real height change, so a scrolled-away reader or active drag is never yanked; no correctness, security, or leak issues found in the four changed files.

Files Reviewed (4 files)
  • apps/mobile/src/components/agents/use-session-auto-scroll-state.ts - new shouldFollowSessionViewportResize policy, mirrors the content-size policy
  • apps/mobile/src/components/agents/use-session-list-auto-scroll.ts - handleListLayout now takes the layout event, tracks the viewport height, and re-pins directly on a real height change; ?at= resume (initialAutoScroll=false) and drag paths stay guarded
  • apps/mobile/src/components/agents/use-session-auto-scroll-state.test.ts - policy unit tests
  • apps/mobile/src/components/agents/use-session-list-auto-scroll.mounted.test.tsx - mounted hook tests driving the defect, a scrolled-away reader, and a drag

Reviewed by deepseek-v4.1-flash · Input: 0 · Output: 0 · Cached: 0

Review guidance: REVIEW.md from base branch main

@iscekic

iscekic commented Sep 19, 2026

Copy link
Copy Markdown
Collaborator Author

This description names a scenario the proof did not capture:

  • not proved live: In the same running session, scroll the transcript up and let the status row's elapsed time advance: the list stays where the user left it and is never yanked back to the bottom. (no capture cited it)

A repeated proof run rebuilds the same evidence, so no proof run is dispatched for a named gap. Merging with this gap open is your decision.

@iscekic
iscekic requested a review from eshurakov September 19, 2026 07:46
@iscekic iscekic added the human-ready The PR is ready for human review. label Sep 19, 2026
@iscekic
iscekic requested a review from pandemicsyn September 19, 2026 07:46
@iscekic iscekic self-assigned this Sep 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

human-ready The PR is ready for human review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant