fix(mobile): confirm connectivity and expose history liveness - #5677
Conversation
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Executive SummaryIncremental test-only fixture and host-query updates look correct, with high confidence and no production-code defects. Files Reviewed (4 files)
Previous Review Summaries (4 snapshots, latest commit b3197c6)Current summary above is authoritative. Previous snapshots are kept for context only. Previous review (commit b3197c6)Status: 1 Issue Found | Recommendation: Address before merge Executive SummaryVisible session-history rows still miss live-status updates because Overview
Issue Details (click to expand)WARNING
Files Reviewed (21 files)
Fix these issues in Kilo Cloud Previous review (commit d27a89f)Status: 1 Issue Found | Recommendation: Address before merge Executive SummaryVisible session-history rows still miss live-status updates because Overview
Issue Details (click to expand)WARNING
Files Reviewed (21 files)
Fix these issues in Kilo Cloud Previous review (commit d9f0a86)Status: 1 Issue Found | Recommendation: Address before merge Executive SummaryVisible session-history rows still miss live-status updates because Overview
Issue Details (click to expand)WARNING
Files Reviewed (20 files)
Fix these issues in Kilo Cloud Previous review (commit 4353740)Status: 2 Issues Found | Recommendation: Address before merge Overview
Issue Details (click to expand)WARNING
Files Reviewed (15 files)
Reviewed by grok-4.6 · Input: 163.8K · Output: 13K · Cached: 417.3K Review guidance: REVIEW.md from base branch |
Summary
Each file lists its class, status, and added/removed line counts from the accepted statistics.
createOfflineBannerStorerequires aprobe: () => Promise<boolean>and removesshowDelayMsandOFFLINE_BANNER_SHOW_DELAY_MSin favor of a fixed five-second confirmation delay.The three-second
HEADprobe toAPI_BASE_URLaccepts every Hypertext Transfer Protocol (HTTP) response, so NetInfo alone cannot establish offline status.Failed probes confirm offline; online reports commit immediately, while unknown reports preserve state and newer events or destruction invalidate pending results.
Files
apps/mobile/src/lib/offline-banner-state.ts— Source, modified (+33/−17 lines); delays the probe without changing committed state. Initial state remains unknown withisOffline: false. False results, throws, and rejections confirm offline only for a current attempt. Each source update cancels the timer and advances the generation; destruction also prevents late commits.apps/mobile/src/lib/hooks/use-offline-banner-state.ts— Source, modified (+13/−1 lines); supplies the bounded reachability probe.withDeadlinepasses an abort signal tofetchand leaves failure handling to the store; both hooks retain one subscription.apps/mobile/src/lib/offline-banner-state.test.ts— Test, modified (+203/−179 lines); revises the connectivity-store tests.apps/mobile/src/lib/hooks/use-offline-banner-state.mounted.test.tsx— Test, modified (+137/−49 lines); revises the mounted connectivity-hook tests.apps/mobile/src/components/offline-banner.mounted.test.tsx— Test, modified (+250/−61 lines); revises the mounted banner tests.useRetrySecurityAgentSettings(scope)exposesretryandisRetryingfor existing permission, configuration, repository, and organization-role queries without creating missing entries.Each attempt cancels pending work, temporarily applies
networkMode: 'always',retry: false, andstaleTime: 0, and restores every query's options.useSecurityAgentCapability.fetchStatusexposes paused organization requests; coordinated retries finish after all requests settle, while personal capability remains independent of organization failures.Files
apps/mobile/src/lib/hooks/use-security-agent.ts— Source, modified (+57/−2 lines); adds exact-key cancellation and recovery forgetPermissionStatus,getConfig,getRepositories, and their organization counterparts. Organization recovery includesorganizations.list; personalfetchStatusisidle. It blocks duplicate attempts, preserves each query's error, restores options infinally, and retains cached organization roles during background errors.apps/mobile/src/lib/hooks/use-security-agent.test.ts— Test, modified (+27/−7 lines); revises the Security Agent hook tests.ScopeEntryScreenandSettingsOverviewScreenprioritize recovery for errors or deliberate retries; paused, uncached queries also qualify once connectivity becomes known.SettingsOverviewScreen.permissionErrordefaults to false, allowing cached settings to show recovery across enabled states and repository modes without dropping usable data.presentationstill defaults toinlineand acceptsroute; removing theSettingsOverviewPresentationalias changes the type declaration, not those choices.Files
apps/mobile/src/components/security-agent/scope-entry-screen.tsx— Source, modified (+34/−23 lines); uses pending states to distinguish unresolved queries from missing integration and retains cached permission, configuration, and capability. It forwards permission errors and explicit retry progress. The repository query remains mounted, and setup completion uses the shared retry; recovery takes precedence over skeletons.apps/mobile/src/components/security-agent/settings-overview-screen.tsx— Source, modified (+48/−40 lines); retains cached settings and expands recovery beyond disabled agents using all repositories. Known online or offline connectivity enables paused-query recovery; unavailable configuration selects the offline error, and unavailable capability selects the server error. Message priority is configuration, capability or permission, then repositories. Repository loading includes the full retry; skeletons remain the fallback, and explicit empty arrays retain the repository-selection action.apps/mobile/src/components/security-agent/scope-entry-screen.test.ts— Test, modified (+261/−192 lines); revises the scope-entry tests.apps/mobile/src/components/security-agent/settings-overview-screen.mounted.test.tsx— Test, modified (+264/−310 lines); revises the mounted settings overview tests.SettingsRecoveryStatusadds an accessible recovery row with optionalmessageand requiredisRetryingandonRetryinputs.Its outlined Retry button remains present during the whole attempt, while
AccessibleStatussuppresses the previous error message until the attempt ends.Files
apps/mobile/src/components/security-agent/settings-recovery-status.tsx— Source, added (+36/−0 lines); combines the status with a Retry button labelled throughcommon.retry. It passes null to the status during retries and connects the button's loading and press behavior to the required inputs.AgentSessionListContentProps.activeSessionIdsbecomes a requiredReadonlySet<string>, supplied throughuseAgentSessionListDatawithout another query.StoredSessionRow.livemarks matching stored rows in history and search, andmetaWhileLivekeeps their cost and relative time visible.Active identifiers refresh row rendering without adding active-only rows, creation controls, or a live tray; stored and search errors still govern content.
Files
apps/mobile/src/components/agents/use-agent-session-list-data.ts— Source, modified (+2/−0 lines); returns the existing active identifiers alongside stored and searched groups without adding active-query errors tocontentIsError.apps/mobile/src/components/agents/session-history-screen.tsx— Source, modified (+2/−0 lines); forwards the active identifiers and keeps empty states dependent on stored sessions, search, and filters.apps/mobile/src/components/agents/session-list-content.tsx— Source, modified (+5/−1 lines); checks each session identifier for liveness and enables metadata for live rows. The shared renderer depends on the active set; session keys and the sort-based list key stay unchanged.apps/mobile/src/components/agents/session-history-screen.mounted.test.tsx— Test, modified (+73/−33 lines); revises the mounted history screen tests.apps/mobile/src/components/agents/session-list-content.mounted.test.tsx— Test, added (+340/−0 lines); introduces mounted tests for session-list content.SessionRowAccessibilityLabelInputs.liveadds an optional, false-default opt-in to localized live speech immediately after the session title.StoredSessionRowopts in only for live list rows, so card labels and callers without the flag retain their previous speech.If a session needs input, that announcement wins; branch, pull request, badge, metadata, and platform speech keep their existing order.
Files
apps/mobile/src/components/agents/session-row-accessibility-label.ts— Source, modified (+7/−2 lines); adds the live opt-in and documents the existing examples as labels without it.apps/mobile/src/components/agents/session-row.tsx— Source, modified (+3/−2 lines); enables list-only live speech and clarifies the default for callers without liveness. Visual liveness and metadata forwarding remain intact.apps/mobile/src/components/agents/session-row-accessibility-label.test.ts— Test, modified (+41/−0 lines); expands the session label tests.apps/mobile/src/components/agents/session-row.mounted.test.tsx— Test, added (+269/−0 lines); introduces mounted tests for stored session rows.Tests: 10 files, with 2 additions and 8 modifications (+1,865/−831 lines):
offline-banner-state.test.ts,use-offline-banner-state.mounted.test.tsx,offline-banner.mounted.test.tsx,use-security-agent.test.ts,scope-entry-screen.test.ts,settings-overview-screen.mounted.test.tsx,session-history-screen.mounted.test.tsx,session-list-content.mounted.test.tsx,session-row-accessibility-label.test.ts,session-row.mounted.test.tsx.Generated: none (0 files).
Verification
Local end-to-end verification on an iOS simulator, 2026-09-01. Seven of nine checks passed. Two have partial coverage.
This section covers the stack's six PRs together: #5666, #5668, #5677, #5680, #5685, and #5686.
No product bug was found. No product source changed. The worktree stayed clean.
#77537band#481fd3on separate lines.Remotes and locale evidence
The installed CLI 7.5.6 reports no
kind, so every real relay lands under Terminals and the Remotes group is unreachable through it. A stand-in producer therefore attached over the real CLI WebSocket contract (/api/user/cli,instanceSchemainservices/session-ingest/src/types/user-connection-protocol.ts) and heartbeat an instance identity. Everything below the CLI process is the shipped path: the durable object,getConnectedInstances,activeSessions.listInstances, and the picker.Two
kind: 'remote'instances and onekind: 'cli'instance produced:Cloud Agent, thenREMOTESwith both remote rows, thenTERMINALSwith the terminal row.feature/remotes-verify1is 23 code points and rendered asfeature/remotes-veri…, exactly the documented 20-code-point boundary.startedAtrenderedmainalone, with no separator and no date.Started Sep 1, 2026 at 7:51 AM. German renderedGestartet 1. Sept. 2026, 07:51— day-first, German month, 24-hour clock.REMOTESbecameREMOTE-INSTANZENin German.Remotes, ci-runner-eu-west on cloud, and feature/remotes-veri… · Started Sep 1, 2026 at 7:51 AM.instance-picker-row-3c7b01,-fe6b0a, and-377bcdwere byte-identical across both locales, so the identifier does not depend on displayed facts.Run on: ci-runner-eu-west · cloud.Untested condition
The offline banner is driven only by NetInfo device connectivity.
createOfflineBannerStorecommitsonlineas soon as NetInfo reports a connection and runs its HTTP probe only to suppress a false NetInfo offline report (apps/mobile/src/lib/offline-banner-state.ts:67-88). A backend-only outage with the device still online therefore shows no banner by design. A real device-wide outage was not simulated, so that path has no runtime verdict.Setup
mobile-ux-ad6d-s6, simulator iPhone 17 Pro on iOS 26.5.xcrun simctl io <udid> screenshot./Users/igor/Projects/.scratch/local-e2e-ux/.Unrelated observation
After "Allow once" on a tool permission, repeated Back taps did not leave the chat screen; a cold restart restored navigation. Evidence:
/Users/igor/Projects/.scratch/local-e2e-ux/C-back-stuck.png. None of these six PRs touch navigation, and the symptom was not reproduced in a second round. It needs a real CLI relay executing a command to reproduce, so it is recorded here rather than diagnosed.