Skip to content

fix(mobile): show an explained empty state in the PR discussion tab - #6375

Merged
iscekic merged 1 commit into
mainfrom
kwf/explorer-pr-discussion-the-discussion-tab-shows-a-large-b-a1b59-8dad
Sep 22, 2026
Merged

iscekic merged 1 commit into
mainfrom
kwf/explorer-pr-discussion-the-discussion-tab-shows-a-large-b-a1b59-8dad

Conversation

@iscekic

@iscekic iscekic commented Sep 19, 2026 •

Copy link
Copy Markdown
Collaborator

Changelog for users

  • The Discussion tab shows a titled and described empty message instead of a blank body.
  • The message appears when every loaded comment or thread is hidden or carries no comments.
  • The pinned "Comment on this pull request" bar stays available in that state.
  • A pull request whose review threads contain no comments no longer counts as having discussion content.
  • When an empty page still has more discussion to load, the Load more and Retry controls stay reachable.

Changelog for maintainers

  • apps/mobile/src/lib/pr-review/provider-pr-queries.ts:461 — accepted: GitHub normalization drops review threads with zero comments, which can leave an empty page while a next page exists; the tab now keeps pagination reachable through that state.
  • apps/mobile/src/lib/auth/passkey-client.test.ts:359 — rejected (no_change): removing the case-guard exception for lib/auth/passkey-client.ts reintroduces an existing non-display guard failure; the passkey error classification reads its error haystack case-insensitively and no authentication behavior changes.
  • apps/mobile/src/components/pr-review/pr-review-discussion-tab.tsx — the full-body empty state renders only when there is no next page, no in-flight next page, and no later-page error; otherwise the discussion list stays mounted so its empty message and pagination footer remain reachable.
  • apps/mobile/src/components/pr-review/discussion/pr-review-discussion-list.tsx — FlashList renders EmptyState as its ListEmptyComponent (placement="top"), so the blocked or muted-author filter cannot leave a blank body under the pinned Comment bar.
  • Empty copy is reused: prReview.discussion.noDiscussion / noDiscussionDescription; GitLab keeps the merge-request noun via prReview.terms.noDiscussionDescription.
  • Regression tests cover blocked and muted authors, threads with empty or fully hidden comments, zero-comment GitHub threads, and the load-more, loading, and retry footer with zero list rows.
  • Review hint: the risky seam is an empty normalized page that still has pages; the list must stay mounted so Load more and Retry remain reachable, while terminal empties keep the full-body state.

E2E proof

The new captures were collected on 2026-09-19 with temporary stub fixtures, removed after collection. They supersede the earlier moderation-fixture narrative and the previous gap where the seeded empty discussion had no live capture. The original empty-state and visible-content captures remain valid for the unaffected behavior.

[e1] Open a PR whose loaded threads contain no comments but whose next page contains discussion: confirm the empty message, Load more, and pinned Comment bar remain visible; tap Load more and confirm… — e2e-mobile-app/e1-empty-loadmore.png

[e3] Open a discussion with no comments and no remaining pages: confirm the empty message, Review files action, and pinned Comment bar remain available. — prior/e3-discussion-empty.png

[e1] pr-discussion: open the discussion of the PR that showed the blank capture (KILO-ORG/KILOCODE #14219) -> discussion empty state with the pinned Comment bar, not a blank region — e2e-mobile-app/e1.png

[e2] pr-discussion: mute or block every author of a PR's loaded comments, then open its Discussion tab -> the body shows the review-thread empty message instead of a blank region and the Comment bar stays… — e2e-mobile-app/e2.png

[e2] pr-discussion: open the Discussion tab of a PR whose comments are visible -> comment and thread rows render exactly as before, no empty state, pagination and thread expand unaffected — prior/e2-discussion-bottom.png

[e2] pr-discussion: open the Discussion tab of a PR whose comments are visible -> comment and thread rows render exactly as before, no empty state, pagination and thread expand unaffected — prior/e2-discussion-tab.png

[e2] pr-discussion: open the Discussion tab of a PR whose comments are visible -> comment and thread rows render exactly as before, no empty state, pagination and thread expand unaffected — e2-thread-expanded.png

Owner request

Explorer finding: pr-discussion: The Discussion tab shows a large blank content region with no loading indicator and no empty-state message even though the tab is labelled 5, leaving only the pinned Comment button.

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

Flow: pr-discussion
Found on revision: 59ef790

Repro:

  1. set this state first: account e2e-mobile-cloud-android@example.com signed in, $10 credits, 6 Code Reviewer pull requests, a second organization to switch to, day mode, display density 320, battery 90% charging, portrait, app cold-started via the Expo dev launcher.; the device in light mode
  2. open the app on emulator-5554
  3. reach the screen the capture names (pr-discussion)
  4. the capture shows the defect named below

Observed: The Discussion tab shows a large blank content region with no loading indicator and no empty-state message even though the tab is labelled 5, leaving only the pinned Comment button.
Expected: the screen renders without this defect

Evidence (from the device run):

E2E proof — log excerpts

[e1] While an empty normalized discussion has more pages, trigger a transient pa -> pass :: Android emulator-5554 kilo-stub/discussion-mixed#11 empty page kept pagination (e1-pagination-fail.log: 'No discussion yet', 'Load more comments'); blocked PAGESECOND left Retry on the empty body (e1-pagination-fail.log: 'Could not load more comments.', 'Retry loading more comments'; github-paged-requests.log: 'transientFailure":true'); after resume plus Retry and Load more, later comments rendered (e1-pagination-fail.log: 'Thread A comment at T+1 (inline review)') with pinned 'Comment on this pull request'; paged github-stub fixture.
/home/igor_kilocode_ai/.local/share/kwf/sections/kwf-fix-review-6d71/e2e-mobile-app/e1-pagination-fail.log
Button "Comment on this pull request"
TextView "Comment on this pull request"
# Tap Load more comments while page 2 is blocked (github-paged-requests.log):
# "after":"PAGESECOND","transientFailure":true
# State 2 — transient pagination failure; Retry remains reachable on the empty body
android.view.View "Discussion, 9" [checked]
TextView "No discussion yet"
TextView "No review threads or conversation comments on this pull request."
TextView "Could not load more comments."
Button "Retry loading more comments"
TextView "Retry"
Button "Comment on this pull request"
TextView "Comment on this pull request"
# Restore: POST /__control/resume-threads -> {"ok":true,"blockPage2":false}
# Tap Retry loading more comments, then Load more comments
# State 3 — later comments after Retry and Load more (SCENE digest)
android.view.View "Discussion, 9" [checked]
android.view.ViewGroup "Discussion thread src/alpha.ts L10 (RIGHT)"
TextView "2 comments · started 6 months ago"
TextView "Thread A comment at T+1 (inline review)"
TextView "Thread A reply at T+5 (inline review)"
android.view.ViewGroup "Discussion thread src/beta.ts L20 (RIGHT)"
Button "Comment on this pull request"
TextView "Comment on this pull request"
/home/igor_kilocode_ai/.local/share/kwf/sections/kwf-fix-review-6d71/e2e-mobile-app/github-paged-requests.log
{"t":"2026-09-19T17:34:28.446Z","method":"POST","path":"/graphql","operationName":"PrReviewThreads","after":"PAGESECOND","transientFailure":true}
{"t":"2026-09-19T17:34:28.447Z","method":"POST","path":"/__control/resume-threads","blockPage2":false}
{"t":"2026-09-19T17:34:28.449Z","method":"POST","path":"/graphql","operationName":"PrReviewThreads","variables":{"owner":"kilo-stub","name":"discussion-mixed","number":11,"first":50,"after":"PAGESECON
{"t":"2026-09-19T17:34:28.450Z","method":"POST","path":"/__control/block-threads","blockPage2":true}
{"t":"2026-09-19T17:35:41.175Z","method":"GET","path":"/repos/kilo-stub/discussion-mixed/pulls/11","owner":"kilo-stub","repo":"discussion-mixed","number":"11"}
{"t":"2026-09-19T17:35:41.177Z","method":"GET","path":"/repos/kilo-stub/discussion-mixed","owner":"kilo-stub","repo":"discussion-mixed"}
{"t":"2026-09-19T17:35:41.178Z","method":"POST","path":"/graphql","operationName":"PrReviewDecision","variables":{"owner":"kilo-stub","name":"discussion-mixed","number":11},"queryPreview":"\n  query P
{"t":"2026-09-19T17:35:42.125Z","method":"GET","path":"/repos/kilo-stub/discussion-mixed/commits/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/check-runs"}
{"t":"2026-09-19T17:35:42.126Z","method":"GET","path":"/repos/kilo-stub/discussion-mixed/commits/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/statuses"}
{"t":"2026-09-19T17:36:06.704Z","method":"POST","path":"/graphql","operationName":"PrReviewThreads","variables":{"owner":"kilo-stub","name":"discussion-mixed","number":11,"first":50,"after":null},"que
{"t":"2026-09-19T17:36:06.704Z","method":"POST","path":"/graphql","operationName":"PrReviewConversationComments","variables":{"owner":"kilo-stub","name":"discussion-mixed","number":11,"first":100,"aft

@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

Full re-review at a0c238390 after the branch was rebased (previous SHA 9b13ecde7 is no longer an ancestor of HEAD, so the incremental diff could not be isolated; the case-guard.test.ts hunk from the prior round is no longer part of this PR); the changed lines introduce no correctness, security, pagination, or memory-leak issues, and both prior kwf-audit remarks are resolved in this head (pagination kept reachable; the passkey change remains a test-only classification table with the author's no_change rationale).

Files Reviewed (8 files)
  • apps/mobile/src/components/pr-review/discussion/pr-review-discussion-list.mounted.test.tsx
  • apps/mobile/src/components/pr-review/discussion/pr-review-discussion-list.test.tsx
  • apps/mobile/src/components/pr-review/discussion/pr-review-discussion-list.tsx
  • apps/mobile/src/components/pr-review/pr-review-discussion-tab.test.tsx
  • apps/mobile/src/components/pr-review/pr-review-discussion-tab.tsx
  • apps/mobile/src/lib/auth/passkey-client.test.ts
  • apps/mobile/src/lib/pr-review/provider-pr-queries.test.ts
  • apps/mobile/src/lib/pr-review/provider-pr-queries.ts

Review Notes

  • apps/mobile/src/lib/pr-review/provider-pr-queries.ts — the GitHub arm drops zero-comment review threads via a non-mutating map/filter spread, so each page's nextCursor and conversation survive by reference: getNextPageParam/hasNextPage/fetchNextPage, the retention trim, retainConversationAcrossMounts, and the optimistic resolve/reaction reducers (which read the raw cache) are all unaffected, while isDiscussionEmpty now sees the truth. The memoization on rawPages keeps identity stable, so no extra effect runs.
  • apps/mobile/src/components/pr-review/pr-review-discussion-tab.tsx — the terminal empty body renders only when !hasNextPage && !isFetchingNextPage && !laterPageError; every negation routes to the mounted list, whose footer exposes Load more, the loading button, or Retry. When view.kind === 'empty', retainedContentError is necessarily false (it requires !isEmpty), so the list's laterPageError || retainedContentError prop stays consistent, and terminal empties keep the full-body state with its Review files action.
  • apps/mobile/src/components/pr-review/discussion/pr-review-discussion-list.tsx — EmptyState placement="top" is passed as ListEmptyComponent, so it renders only when visibleItems is empty (all rows moderation-hidden, or an empty page with pagination/error) and never nests a ScrollView inside FlashList. The new useProviderPrScope/useTranslation calls are unconditional context/memo hooks with no subscriptions, effects, timers, or module-level mutable state — no leak surface. Reused i18n keys prReview.discussion.noDiscussion/noDiscussionDescription and prReview.terms.noDiscussionDescription exist in en.json.
  • Test-only changes verified against current implementations: the passkey mixed-case table matches classifyPasskeyError's lowercased haystack (all five rows classify correctly, no production auth change); the FlashList mocks render ListEmptyComponent/ListFooterComponent faithfully; the new tab and list tests cover the zero-row load-more/loading/retry seams and the pre-existing passes GitHub pages through untouched test still holds (its fixture has no threads to filter).
Previous Review Summaries (4 snapshots)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review

Status: No Issues Found | Recommendation: Merge

Executive Summary

Full re-review at 9b13ecde7 after the branch was force-pushed (previous SHA 6b7719700 is no longer an ancestor of HEAD, so the incremental diff could not be isolated); the changed lines introduce no correctness, security, pagination, or memory-leak issues.

Files Reviewed (9 files)
  • apps/mobile/src/components/pr-review/discussion/pr-review-discussion-list.mounted.test.tsx
  • apps/mobile/src/components/pr-review/discussion/pr-review-discussion-list.test.tsx
  • apps/mobile/src/components/pr-review/discussion/pr-review-discussion-list.tsx
  • apps/mobile/src/components/pr-review/pr-review-discussion-tab.test.tsx
  • apps/mobile/src/components/pr-review/pr-review-discussion-tab.tsx
  • apps/mobile/src/lib/auth/passkey-client.test.ts
  • apps/mobile/src/lib/case-guard.test.ts
  • apps/mobile/src/lib/pr-review/provider-pr-queries.test.ts
  • apps/mobile/src/lib/pr-review/provider-pr-queries.ts

Review Notes

  • apps/mobile/src/lib/pr-review/provider-pr-queries.ts — the GitHub arm now drops zero-comment review threads by spreading each page, so nextCursor and conversation survive by reference; getNextPageParam reads the raw cache page, so hasNextPage/fetchNextPage and the optimistic resolve/reaction reducers are unaffected, and isDiscussionEmpty now sees the truth.
  • apps/mobile/src/components/pr-review/pr-review-discussion-tab.tsx — the full-body empty state is gated on !hasNextPage && !isFetchingNextPage && !laterPageError; each negation routes to a list branch that still exposes Load more, the loading button, or Retry, and retainedContentError is necessarily false when view.kind === 'empty', so the list's laterPageError || retainedContentError stays consistent.
  • apps/mobile/src/components/pr-review/discussion/pr-review-discussion-list.tsx — EmptyState placement="top" is passed as ListEmptyComponent, so it renders only when visibleItems is empty (all rows hidden, or a genuinely empty page with pagination/error) and never nests a ScrollView in FlashList. useProviderPrScope/useTranslation are called unconditionally and memoized, adding no subscriptions or module-level mutable state (no leak surface). Reused i18n keys prReview.discussion.noDiscussion/noDiscussionDescription and prReview.terms.noDiscussionDescription exist in en.json.
  • Test-only changes (FlashList empty/footer mock, passkey mixed-case classification, case-guard allowlist reason, GitHub empty-thread normalizer) assert the new behavior; the pre-existing passes GitHub pages through untouched test still passes because its page has no threads to filter.

Previous review (commit 6b77197)

Status: No Issues Found | Recommendation: Merge

Executive Summary

Full re-review at 6b7719700 after the branch was force-pushed (previous SHA 130f99b is no longer an ancestor of HEAD, so the incremental diff could not be isolated); the rebased single commit contains no new correctness, security, performance, or memory issues in its changed lines.

Review Notes

  • apps/mobile/src/lib/pr-review/provider-pr-queries.ts — the GitHub arm now drops comment-less review threads via map/filter, which leaves the cached pages untouched and preserves each page's nextCursor, so pagination and the optimistic resolve/reaction reducers are unaffected.
  • apps/mobile/src/components/pr-review/pr-review-discussion-tab.tsx — the terminal empty body is now gated on !hasNextPage && !isFetchingNextPage && !laterPageError, so an empty normalized page that still has pages falls through to the list and keeps Load more / Retry reachable; terminal empties still render the full-body state.
  • apps/mobile/src/components/pr-review/discussion/pr-review-discussion-list.tsx — EmptyState placement="top" is used as ListEmptyComponent, avoiding a nested ScrollView inside FlashList; useProviderPrScope falls back to the GitHub triple, so the GitLab merge-request copy is correct without a scope. The reused i18n keys exist in en.json and no module-level mutable state (leak surface) was added.
  • The passkey classification and case-guard allowlist additions are test-only and justified (passkey-client.ts lowercases its error haystack); they do not affect authentication behavior.
Files Reviewed (9 files)
  • apps/mobile/src/components/pr-review/pr-review-discussion-tab.tsx
  • apps/mobile/src/components/pr-review/discussion/pr-review-discussion-list.tsx
  • apps/mobile/src/lib/pr-review/provider-pr-queries.ts
  • apps/mobile/src/components/pr-review/pr-review-discussion-tab.test.tsx
  • apps/mobile/src/components/pr-review/discussion/pr-review-discussion-list.mounted.test.tsx
  • apps/mobile/src/components/pr-review/discussion/pr-review-discussion-list.test.tsx
  • apps/mobile/src/lib/pr-review/provider-pr-queries.test.ts
  • apps/mobile/src/lib/auth/passkey-client.test.ts
  • apps/mobile/src/lib/case-guard.test.ts

Previous review (commit 130f99b)

Status: No Issues Found | Recommendation: Merge

Executive Summary

Incremental review of the two test-only additions since the last review (20c9068..130f99b): a case-insensitivity classification table for classifyPasskeyError/passkeyFailureKey and a case-guard allowlist entry for lib/auth/passkey-client.ts. Both are correct, and the earlier Discussion-tab empty-state changes are unchanged.

Files Reviewed (2 files)
  • apps/mobile/src/lib/auth/passkey-client.test.ts
  • apps/mobile/src/lib/case-guard.test.ts

Previous review (commit 20c9068)

Status: No Issues Found | Recommendation: Merge

Reviewed the Discussion-tab empty-state fix: the FlashList ListEmptyComponent (moderation-hidden rows) and the GitHub normalization drop of comment-less review threads. Verified the tab/list empty checks agree, the GitLab merge-request noun is preserved, EmptyState placement="top" avoids a nested ScrollView, the i18n keys exist in en.json, and the GitHub filter does not mutate cached pages or affect pagination cursors/mutations. No memory leaks, security, or correctness issues found in the changed lines.

Files Reviewed (5 files)
  • apps/mobile/src/components/pr-review/discussion/pr-review-discussion-list.tsx
  • apps/mobile/src/components/pr-review/discussion/pr-review-discussion-list.mounted.test.tsx
  • apps/mobile/src/components/pr-review/discussion/pr-review-discussion-list.test.tsx
  • apps/mobile/src/lib/pr-review/provider-pr-queries.ts
  • apps/mobile/src/lib/pr-review/provider-pr-queries.test.ts

Reviewed by efficient · Input: 0 · Output: 0 · Cached: 0

Review guidance: REVIEW.md from base branch main

@iscekic
iscekic marked this pull request as draft September 19, 2026 15:10
@iscekic
iscekic force-pushed the kwf/explorer-pr-discussion-the-discussion-tab-shows-a-large-b-a1b59-8dad branch from 20c9068 to 130f99b Compare September 19, 2026 15:29
@iscekic
iscekic marked this pull request as ready for review September 19, 2026 15:50
@iscekic

iscekic commented Sep 19, 2026

Copy link
Copy Markdown
Collaborator Author

kilo-review — independent audit of the published diff.

Status: 2 Issues

File Line Issue
apps/mobile/src/lib/pr-review/provider-pr-queries.ts 461 Filtering zero-comment GitHub threads can hide pagination when the normalized list is empty.
apps/mobile/src/lib/auth/passkey-client.test.ts 359 The diff includes unrelated passkey and case-guard changes outside the PR discussion task.

@iscekic
iscekic marked this pull request as draft September 19, 2026 16:26
@iscekic

iscekic commented Sep 19, 2026

Copy link
Copy Markdown
Collaborator Author

bot: Accepted. Pushed 09e864f (kwf kwf-fix-review-6d71).

What changed:

  • apps/mobile/src/lib/pr-review/provider-pr-queries.ts:461 — accepted: GitHub normalization drops review threads with zero comments, which can leave an empty page while a next page exists; the tab then hid the pagination footer behind the terminal empty state.
  • apps/mobile/src/components/pr-review/pr-review-discussion-tab.tsx — the full-body empty state now renders only when there is no next page, no in-flight next page, and no later-page error; otherwise the list stays mounted so its empty message and pagination footer remain reachable.
  • apps/mobile/src/lib/auth/passkey-client.test.ts:359 — rejected (no_change): removing the case-guard exception for lib/auth/passkey-client.ts reintroduces an existing non-display guard failure; the passkey error classification reads its error haystack case-insensitively and no authentication behavior changes.
  • apps/mobile/src/components/pr-review/discussion/pr-review-discussion-list.tsx — FlashList renders EmptyState as its ListEmptyComponent, so a fully filtered list explains itself under the pinned Comment bar.
  • New regression test drives load-more, loading, and retry with zero list rows and asserts the footer and its handlers stay reachable.
  • Review hint: the risky seam is an empty normalized page that still has pages; the list must stay mounted so Load more and Retry remain reachable.

@iscekic
iscekic force-pushed the kwf/explorer-pr-discussion-the-discussion-tab-shows-a-large-b-a1b59-8dad branch from 09e864f to 6b77197 Compare September 19, 2026 18:21
@iscekic
iscekic marked this pull request as ready for review September 19, 2026 18:41
@iscekic iscekic added the human-ready The PR is ready for human review. label Sep 19, 2026
@iscekic iscekic self-assigned this Sep 19, 2026
@iscekic iscekic removed the human-ready The PR is ready for human review. label Sep 19, 2026
@iscekic
iscekic marked this pull request as draft September 19, 2026 23:16
@iscekic
iscekic force-pushed the kwf/explorer-pr-discussion-the-discussion-tab-shows-a-large-b-a1b59-8dad branch from e529041 to 9b13ecd Compare September 19, 2026 23:57
@iscekic
iscekic marked this pull request as ready for review September 20, 2026 00:12
@iscekic iscekic added the human-ready The PR is ready for human review. label Sep 20, 2026
@iscekic
iscekic force-pushed the kwf/explorer-pr-discussion-the-discussion-tab-shows-a-large-b-a1b59-8dad branch from 9b13ecd to a0c2383 Compare September 20, 2026 18:18

@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 61fe206 into main Sep 22, 2026
28 of 29 checks passed
@iscekic
iscekic deleted the kwf/explorer-pr-discussion-the-discussion-tab-shows-a-large-b-a1b59-8dad branch September 22, 2026 01:08
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