Skip to content

fix(mobile): keep the session body painted when measurement or entrance stalls - #6459

Merged
iscekic merged 1 commit into
mainfrom
kwf/explorer-session-idle-the-session-content-area-is-complet-14721-f358
Sep 21, 2026
Merged

iscekic merged 1 commit into
mainfrom
kwf/explorer-session-idle-the-session-content-area-is-complet-14721-f358

Conversation

@iscekic

@iscekic iscekic commented Sep 21, 2026

Copy link
Copy Markdown
Collaborator

Changelog for users

  • A session's content area now shows its transcript, empty message, status, or error card instead of staying blank while the header already reports loaded token usage.
  • If the screen's layout measurement never arrives, the body reveals its content after a short delay instead of staying invisible.
  • The loaded transcript no longer depends on an entrance animation to become visible.
  • Empty, status, and error bodies stay centered while the measurement is pending.

Changelog for maintainers

  • CenteredState now bounds the hidden-until-measured state: content appears after STATE_SURFACE_FALLBACK_MS (400 ms) even when the native surface frame never lands.
  • A real measurement still wins: once the layout resolves, the fallback resets and the measured placement replaces the centered placeholder.
  • The transcript branch renders in a plain View; the Animated.View with FadeIn.duration(200) is gone because FadeIn starts at opacity: 0 and could leave the body blank when the entrance never ran.
  • The skeleton's exiting crossfade still carries the skeleton-to-transcript swap, so the transcript needs no entrance animation.
  • Review hint: the in-window contract is unchanged — content stays opacity-0 and accessibility-hidden until the 400 ms bound elapses.
  • Unit tests assert the transcript wrapper has no entering prop and cover the timer reveal, the measured-wins path, and the hidden-until-window behavior.
  • No new dependencies, configuration, migrations, or copy keys.

E2E proof

[e1] Explorer finding: session-idle — session content area blank under a populated header — e2e-mobile-app/e1-after-retry.png (capture not retained)

[e1] Explorer finding: session-idle — session content area blank under a populated header — e2e-mobile-app/e1-open.png

[e1] Explorer finding: session-idle — session content area blank under a populated header — prior/e1-after-retry.png

[e1] Explorer finding: session-idle — session content area blank under a populated header — prior/e1-open.png

<redacted>
/home/igor_kilocode_ai/.local/share/kwf/sections/kwf-fix-proof-3bb953f-901c/e2e-mobile-app/e1-scene.log
SCENE e1 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,98][101,199]
android.widget.Button Rename session: Greeting tappable [111,84][595,213]
android.view.View Greeting tappable [111,115][595,180]
android.widget.Button Context 10,940 of 1,310,720 tokens, 1% used, cost 0.39 cents. Tap to view context details. tappable [622,91][925,206]
android.widget.TextView 1% tappable [744,130][781,167]
android.widget.TextView $0.0039 tappable [790,130][894,167]
android.widget.Button Copy link tappable [943,98][1044,199]
android.widget.TextView 5:12 AM tappable [476,1713][604,1752]
android.view.ViewGroup say hello, User message tappable [0,1771][1080,1909]
android.widget.TextView say hello tappable [847,1808][1011,1871]
android.widget.Button Preparation complete tappable [40,1930][1042,2031]
android.widget.TextView Preparation complete tappable [188,1957][506,2003]
android.view.ViewGroup Hello, Assistant message tappable [0,2052][1080,2143]
android.widget.TextView Hello tappable [37,2066][1045,2129]
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 Send message [926,2188][1052,2314]
## Follow-ups (not changed here) - not proved live: Loaded idle session paints its body: the session screen (composer placeholder visible) shows a defined body state - a transcript row such as the seeded 'say hello' prompt, or the empty-state copy 'No messages yet' / 'Send a message below to get started.' - instead of the finding's blank area. platform:both(native surface geometry differs per OS and is the measurement under test). (no capture cited it) - not proved live: Seeded idle session paints its transcript row instead of a blank body (the finding's state): with the session open and its metadata and messages loaded, the body shows the seeded prompt row 'say hello'; the finding's blank body (header pill showing tokens, no skeleton, no empty-state text) fails this scenario. Platform: the request's (Android). (no capture cited it) - not proved live: ux-check: Cold-open/relaunch a populated session: within one second the body shows either the message skeleton or the transcript; it never sits as empty space under a populated header. (no capture cited it) - not proved live: ux-check: Observe the skeleton-to-transcript swap: the transcript does not jump or reflow; the skeleton fades out over the transcript. (no capture cited it) - not proved live: ux-check: Open a populated session (header shows a non-zero context/token pill): the transcript messages are visible and the content area is never fully blank once the header is shown. (no capture cited it) - not proved live: ux-check: Open a session whose body is a data state (no renderable messages / connecting / terminal error): the empty, status, or error content is visible within ~1 second, not blank, and the a11y-hidden flag is off. (no capture cited it)

Open findings (not fixed here)

  • ulator-5554
    mobile-device: signed-in app data restored on emulator-5604
    mobile-device: signed-in app data frozen on emulator-5554 (67549696 bytes)
    mobile-device: signed-in app data frozen on emulator-5554 (67557888 bytes)
    mobile-device: shard1 judged by jev
    proof-audit: vision pass returned no JSON
  • not proved live: session-idle.png is no longer on the host that took it, so no publish can carry it
  • the '## E2E proof' section carries no log excerpt, so nothing shows the change was driven end to end

…ce stalls

Explorer finding: session-idle: The session content area is completely blank even though the header already shows 17.2K tokens used, with no spinner, skeleton or empty-state text to indicate that it is loading.

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-idle
Found on revision: f2181ae

Repro:
1. set this state first: credits 20; uimode day; reviews 4; battery 65 discharging; density 300; relaunch; rotate landscape; rotate portrait; the device in light mode
2. open the app on emulator-5602
3. reach session-idle
4. the capture shows the defect named below

Observed: The session content area is completely blank even though the header already shows 17.2K tokens used, with no spinner, skeleton or empty-state text to indicate that it is loading.
Expected: the screen renders without this defect

Evidence (from the device run):
- ~/.local/share/kwf/findings/explorer-session-idle-the-session-content-area-is-complet-147214a1/session-idle.png
@iscekic
iscekic marked this pull request as draft September 21, 2026 04:14
@iscekic
iscekic marked this pull request as ready for review September 21, 2026 04:30
@kilo-code-bot

kilo-code-bot Bot commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

The mobile session-body fix is a small, focused change: the transcript wrapper drops its FadeIn entrance so it paints without an animation, and CenteredState bounds its hidden-until-measured window with a 400 ms timer that is cleared on cleanup and reset when a real measurement lands. No correctness, security, or leak issues were found in the changed lines.

Notes

  • apps/mobile/src/components/centered-state.tsx — the fallback setTimeout is cleaned up in the effect return and the effect re-runs on ready changes, so no timer leaks or stale callbacks; the reset on ready correctly lets a real measurement replace the centered placeholder.
  • apps/mobile/src/components/agents/session-detail-content.tsxAnimated/FadeIn/FadeOut/LinearTransition remain used elsewhere in the file, so removing the transcript Animated.View introduces no unused imports.
  • The pending-state contentContainerStyle uses justifyContent: 'center' on a flexGrow: 1 container, which only applies when content is shorter than the viewport, so tall content is not clipped.
Files Reviewed (4 files)
  • apps/mobile/src/components/agents/session-detail-content.test.ts
  • apps/mobile/src/components/agents/session-detail-content.tsx
  • apps/mobile/src/components/centered-state.mounted.test.tsx
  • apps/mobile/src/components/centered-state.tsx

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

Review guidance: REVIEW.md from base branch main

@iscekic

iscekic commented Sep 21, 2026

Copy link
Copy Markdown
Collaborator Author

This description names a scenario the proof did not capture:

  • not proved live: Loaded idle session paints its body: the session screen (composer placeholder visible) shows a defined body state - a transcript row such as the seeded 'say hello' prompt, or the empty-state copy 'No messages yet' / 'Send a message below to get started.' - instead of the finding's blank area. platform:both(native surface geometry differs per OS and is the measurement under test). (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 added the human-ready The PR is ready for human review. label Sep 21, 2026
@iscekic iscekic self-assigned this Sep 21, 2026

@eshurakov eshurakov 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.

Approved after a shallow triage pass. No blocking findings.

@iscekic
iscekic merged commit 531b87f into main Sep 21, 2026
29 checks passed
@iscekic
iscekic deleted the kwf/explorer-session-idle-the-session-content-area-is-complet-14721-f358 branch September 21, 2026 16:45
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.

2 participants