Repository navigation
fix(mobile): settle the new session branch row and explain an unreachable repository - #8729
Conversation
…on's repository A prepare request that names no integration skips the repository preflight, so a repository the connected installation cannot reach fails later as an opaque error. Resolve the owning connection for the caller's scope and forward its id: an explicit id still wins, and a repository no connection names stays unqualified, which is the previous behaviour.
…able repository The branch row now renders from one resolved state, so loading and a message can never share the screen, and a request that outlives a 15 second bound becomes a retry instead of an endless skeleton. Each state also gets its own native view, so the accessibility tree cannot keep the loading description on the row that replaced it. When the server refuses the selected repository, the form shows the actionable repository guidance instead of the generic service line.
|
bot: Local-stack verification on the Android emulator with an owned fake account and seeded GitHub connection fixtures (one repository under the connected account, one whose owner differs).
|
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Executive SummaryThe incremental commit Assumptions: Files Reviewed (5 files)
Previous Review Summaries (3 snapshots, latest commit cb8222d)Current summary above is authoritative. Previous snapshots are kept for context only. Previous review (commit cb8222d)Status: No Issues Found | Recommendation: Merge Executive SummaryThe incremental change ( Assumptions: Files Reviewed (1 file)
Previous review (commit 0e6cde8)Status: No Issues Found | Recommendation: Merge Executive SummaryThe incremental changes ( Assumptions: Files Reviewed (4 files)
Previous review (commit fb18f92)Status: 3 Issues Found | Recommendation: Address before merge Executive SummaryThe branch-row settle bound renders its Retry non-pressable exactly when a request is stalled, so the escape hatch it adds cannot be used; two hardening gaps accompany it in the bound reset and the new integration resolution. Assumptions: Overview
Issue Details (click to expand)WARNING
SUGGESTION
Files Reviewed (12 files)
Reviewed by deepseek-flash-latest · Input: 57.8K · Output: 5.4K · Cached: 606K Review guidance: REVIEW.md from base branch |
…ry to the repository The settle bound reported a running request as retry progress, which disabled the retry control exactly when the stuck request needed replacing; a refetch cancels the in-flight request, so the control stays enabled and only a retry after a real failure reports progress. The expiry now records the repository and scope it was armed for, so a selection change starts loading again with no stale expiry frame. The GitHub connection lookup also treats a read failure as no connection, which is the behaviour its documentation promises.
…nch-start-states # Conflicts: # apps/mobile/src/components/agents/cloud-prepare-error-display.ts
|
bot: Re-ran the affected flow on the merged head on the Android emulator, local dev stack, owned fake account with seeded GitHub connection fixtures.
|
|
bot: Re-ran the affected flow on the current head on the Android emulator, against the local dev stack with an owned fake account and seeded GitHub connection fixtures (one repository under the connection's account, one whose owner differs).
|
|
bot: Android emulator run at this head against the local dev stack. The branch row under a selected repository holds one settled state: with the branch request still in flight past the settle bound the row shows the retry row alone, and no loading description is present in the same hierarchy. The composer reports a repository the installation cannot serve with the actionable provider-access guidance instead of the generic service line. |










Evidence
Evidence: demonstrated — on the local dev stack with an owned fake account on the Android emulator: with the selected repository's branch request held open so the server could not answer it, the branch row showed a single loading node and then, past the settle bound, a single retry row with no loading node anywhere in the hierarchy; pressing Retry issued a fresh branch request against the backend; Start session on a repository the connected installation does not own returned the runtime's classified
integration_mismatchand the composer showed the actionable repository guidance; Start session on the installation's own repository created the session and opened its detail.What changed
Branch row: one settled state, and loading is bounded (
apps/mobile)resolveBranchSectionStateis a pure resolver over the branch query's flags and returns a single discriminant:bitbucket-organizations-only,loading,unavailable,retryable,empty, orlist.RepositoryBranchSelectorrenders from that value only, so loading and a message cannot both be rendered.useRepositoryBranchesgives a pending request a 15 s bound. Past it the row reports a retryable failure with an enabled Retry while the query keeps running: a refetch cancels the stuck request, so the control works exactly when it is needed. A late answer still replaces the row, and the expiry is tied to the repository and scope it was armed for, so a new selection starts loading immediately.Start session: classify an unreachable repository (
apps/web,apps/mobile)prepareSessionhandlers (personal and organization) resolve the GitHub connection that owns the selected repository for the caller's scope (resolveGitHubIntegrationIdForRepository) and forward its id when the client did not send one. An explicitly supplied id still wins, and a repository no connected installation names stays unqualified — the previous behaviour — rather than refusing a request the runtime can still serve.integration_mismatch,no_installation_found,repository_not_installed).cloudPrepareFailureMessagemaps exactly those refusals to the existing localizedagentChat.newSession.branchUnavailableguidance, so the form says what to fix instead of the generic service line. No cloud-agent runtime code changed.End-to-end verification
Run on this VM at this head: local dev stack (web app, Cloud Agent worker, git-token service, session ingest, Metro) and the Android emulator
omp36, signed in to an owned fake account. The GitHub connection fixture is one active personal installation whose cached repository inventory names both a repository its account owns and one owned by another account; the stack holds no GitHub App credentials, so provider calls are exercised unmodified and fail at the provider.GitHub repository authorization failed (integration_mismatch); the router returnedBAD_REQUEST, no session row was created, and the composer showed "Failed to create session" with the actionable repository guidance instead of the generic service line. The same result reproduced twice, once per repository change.integration_mismatchonly when a prepare request names the integration expected to serve the repository, and the mobile body never sends one; the refusal therefore demonstrates that the new server-side resolution ran and forwarded the connection it found.Local-stack limits, stated plainly:
Checks run on this VM:
pnpm --filter kilo-app exec tsc --noEmit(clean),pnpm --filter kilo-app exec oxlintover changed files (clean), mobile vitest pure suites (branch state, repo hook, prepare error display) and the mounted branch-selector suite (all passing),pnpm --filter web exec tsc --noEmit(clean), web jest forcloud-agent-next-routerandorganization-cloud-agent-next-router(298 passing, including new cases for a resolved, an explicit, and an absent connection id).Production prerequisites
None.
Proxy answers
The owner's proxy gave these answers in the owner's place.
Answer: Web resolves the integration, forwards the id
Confidence: 0.65 — fixes the missing integration identity at its cause, uses the runtime's existing classified preflight without changing runtime code, and avoids an extra provider call on every create.
Answer: Settle bound ~15s, query keeps running
Confidence: 0.60 — a stuck end state is not acceptable and loading must never look permanent; the bound is a safety net, not the only fix.
Answer: Pure resolver + single discriminant
Confidence: 0.75 — fix the class: a single discriminant makes the two-node state unrepresentable.
Answer: Reuse branchUnavailable key
Confidence: 0.55 — the brief asks for the specific actionable message the branch section uses, without an 86-catalog translation pass.
Answer: Forward nothing, keep current behaviour
Confidence: 0.65 — refusing would break public-repo and token paths that work today; classify only the real provider refusal.
Answer: Retryable error with Retry
Confidence: 0.65 — the row must never look stuck, and a late success can still replace the row.