Skip to content

fix(cloud-agent): report unavailable GitHub installations in repository lists - #8590

Merged
iscekic merged 4 commits into
mainfrom
drain/report-unavailable-github-installations
Oct 22, 2026
Merged

iscekic merged 4 commits into
mainfrom
drain/report-unavailable-github-installations

Conversation

@iscekic

@iscekic iscekic commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator

What changed

fetchAllGitHubRepositoriesForOrganization used to drop every installation that was not healthy before aggregating. A suspended, disconnected or reauthorization-needed connection therefore read as integrationInstalled: false with "No GitHub integration found for this organization", and a partly readable set read as an unqualified success.

  • apps/web/src/lib/cloud-agent/github-integration-helpers.ts: every stored installation is now classified as one of three outcomes — readable, unavailable (with a reason), or failed. Zero readable installations returns the single-path message plus unavailableReason; a partly readable set returns the reachable repositories plus partial: true; an all-failed read stays an error so the caller retries. A rejected read beside an unusable installation also sets partial, so the reason and the retry control are shown together rather than the reason alone. An installation without a platform_installation_id counts as unavailable (not_configured) instead of an empty success. fetchGitHubRepositoriesForUser carries the same reason.
  • apps/web/src/routers/cloud-agent-next-router.ts and organizations/organization-cloud-agent-next-router.ts publish unavailableReason and partial in the output schema; the code-review routers return the result object directly, so their existing errorMessage banner now names the real reason.
  • Web: cloud-agent-next/github-repository-status.ts maps a result to notices. NewSessionPanel keeps the composer for an installation that exists but cannot list, and shows the reason with a link to the GitHub connection settings; a genuinely absent installation still gets the connect screen. The settings RepositoryPicker shows the same notices.
  • Mobile: resolveProviderStatus gains an unavailable state and RepositoryGroup carries a notice. The GitHub group renders a reconnect card (with the open action and refresh) and a partial-list notice above the reachable rows. Copy lives in repository-provider-copy.ts; the provider card actions moved into repository-card-actions.tsx so the section stays under its size limit.
  • Copy: three new English keys, translated into all 87 locale catalogs.

Verification (this VM)

  • apps/web: jest over src/lib/cloud-agent, src/lib/integrations/personal-github-installation-selection.test.ts, src/components/cloud-agent-next/github-repository-status.test.ts, src/routers/cloud-agent-next-router.test.ts, src/routers/organizations — 46 suites, 1259 tests passed. New cases: suspended-only organization, auth-invalid organization, suspended sibling with a readable installation, installation without a platform installation id, unconfigured sibling.
  • apps/web typecheck clean (tsgo --noEmit); root oxlint over the changed files clean; oxfmt --check clean.
  • apps/mobile: vitest run src/components/agents src/lib/use-new-session-repos.test.ts src/lib/new-session-submit.test.ts src/i18n — 296 files, 6668 tests passed. check:i18n, check:plurals, pnpm --filter kilo-app lint, format:check and typecheck clean.
  • Web, real dev stack with two owned fake organizations: a suspended-only organization shows "GitHub integration is suspended · Review the GitHub connection" in the composer with the repository picker reporting "No repositories found"; a healthy + suspended organization shows "Some GitHub installations could not be loaded" and lists the reachable rows. Attached comments carry the captures.
  • Android emulator, same two organizations: the new-session screen shows the reconnect card for the suspended-only organization, the partial-list notice for the mixed one, and the picker still lists the reachable repositories.

Unproven

  • The GitHub provider itself was faked at the database: no real installation was suspended or reauthorized, so the reason mapping is exercised by the seeded rows and the unit tests, not by GitHub webhooks.
  • The personal (non-organization) reconnect notice renders from the same helper but was not driven through the UI in this run.

Proxy answers

The owner's proxy gave these answers in the owner's place.

  1. Question: Web takeover: When an organization has a GitHub installation row that is unusable and no other provider is usable, NewSessionPanel currently replaces the composer with the connect screen. What should it do?
    Answer: Composer + inline reconnect notice (Recommended)
    Confidence: 0.60
  2. Question: Reason field scope: should fetchGitHubRepositoriesForUser also populate the new unavailableReason, or only the organization path?
    Answer: Both paths (Recommended)
    Confidence: 0.80
  3. Question: Mobile copy: how should the reconnect state and the partial-list line be handled?
    Answer: Three new English keys, translated to all 87 locales (Recommended)
    Confidence: 0.85
  4. Question: Settings picker: should the second web repository picker also show the GitHub unavailable/partial state?
    Answer: Both pickers
    Confidence: 0.70

…ry lists

The organization repository helper filtered unhealthy installations before
aggregating, so a suspended or reauthorization-needed connection was reported
as "No GitHub integration found". Inside the aggregator, an installation
without a platform installation id resolved to an empty success and rejected
per-installation reads were dropped, so a short list was indistinguishable from
a complete one.

- github-integration-helpers: keep every stored installation and classify it
  (repositories, unavailable with a reason, or failed). Zero usable
  installations returns the reason and the single-path message; a partly
  readable set returns the reachable repositories with `partial: true`; an
  all-failed read stays an error. The personal path carries the same reason.
- cloud-agent routers publish `unavailableReason` and `partial`.
- Web: a shared GitHub notice helper feeds the new-session panel and the
  settings repository picker; an installation that exists but cannot list keeps
  the composer and names the reconnect step instead of the connect screen.
- Mobile: the GitHub provider gains an `unavailable` status with a reconnect
  card and a partial-list notice, with new copy in every locale catalog.
@iscekic iscekic added drain Work item from the findings drain janitor:features-workflows Janitor finding family: features-workflows labels Oct 22, 2026
@iscekic

iscekic commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator Author

bot: Verified on the local dev stack with two owned fake organizations.

Organization whose only GitHub connection cannot list repositories now keeps the composer and names the reconnect step instead of showing the connect screen:

  • the repository row reports the reason with a link to the connection settings
  • opening the picker shows "No repositories found" plus the refresh action

Organization with one reachable and one unusable connection lists the reachable repositories and says the list is incomplete.

Android emulator, same two organizations: the new-session screen renders the reconnect card for the first organization and the partial-list notice for the second, with the picker still listing the reachable repositories.

Settings dialog surface (second web picker) could not be exercised here: that dialog reports "Could not load Cloud Agent settings" against the local stack, so its state mapping is covered by the unit test only.

Web composer showing the GitHub reconnect reason and settings link
Web repository picker empty with the refresh action
Web composer showing the incomplete-list notice
Web repository picker listing the reachable repositories

@iscekic

iscekic commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator Author

bot: Android emulator, new-session screen, same two owned fake organizations.

  • Organization whose only GitHub connection cannot list repositories: the repository section renders the reconnect card with the open action and the refresh control, and no connect prompt.
  • Organization with one reachable and one unusable connection: the section renders the incomplete-list notice above the reachable rows, and the picker still lists those repositories.

Android new-session screen showing the GitHub reconnect card
Android new-session screen showing the incomplete-list notice
Android repository picker listing the reachable repositories

@kilo-code-bot

kilo-code-bot Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Executive Summary

The incremental commits resolve the prior unreachable pending_approval finding by removing that classification end to end, and the new settings-picker retry correctly performs a forced provider read before updating the cached query. No new issues found in the changed lines.

Assumptions: [INFERENCE] the deployed schema includes the platform_integrations_github_connection_role_check constraint declared in this repo, which keeps pending rows out of every GitHub repository lookup (all of them filter on github_connection_role = 'workflow'); the 87 locale catalogs were not re-reviewed language by language because the incremental diff does not touch them.

Files Reviewed (7 files)
  • apps/web/src/lib/cloud-agent/github-integration-helpers.ts
  • apps/web/src/lib/cloud-agent/github-integration-helpers.test.ts
  • apps/web/src/routers/cloud-agent-next-router.ts
  • apps/web/src/routers/organizations/organization-cloud-agent-next-router.ts
  • apps/web/src/components/cloud-agent-next/github-repository-status.ts
  • apps/web/src/components/cloud-agent-next/settings/RepositoryPicker.tsx
  • apps/mobile/src/components/agents/new-session-repository-state.ts
Previous Review Summaries (2 snapshots, latest commit f3727da)

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

Previous review (commit f3727da)

Status: 1 Issue Found | Recommendation: Address before merge

Executive Summary

The incremental commit keeps the retry affordance for a failed sibling read, but the new pending_approval classification is unreachable because the GitHub repository lookups filter on github_connection_role, which pending rows never carry.

Assumptions: [INFERENCE] the deployed schema includes the platform_integrations_github_connection_role_check constraint declared in this repo; the 87 locale catalogs were not re-reviewed language by language. If pending rows were made reachable, the mobile unavailable card has no pending-specific copy and would still say "GitHub needs to be reconnected".

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
apps/web/src/lib/cloud-agent/github-integration-helpers.ts 135 The pending_approval branch is filtered out before it runs: getIntegrationsByOrganization/getIntegrationForOwner require github_connection_role workflow/agent_only, while pending rows are inserted with a null role (the check constraint forbids a role without an installation id). The added unit test mocks that lookup, so it cannot catch this; pending installations still read as "No GitHub integration found".
Files Reviewed (6 files)
  • apps/web/src/lib/cloud-agent/github-integration-helpers.ts - 1 issue
  • apps/web/src/lib/cloud-agent/github-integration-helpers.test.ts - 0 issues
  • apps/web/src/routers/cloud-agent-next-router.ts - 0 issues
  • apps/web/src/routers/organizations/organization-cloud-agent-next-router.ts - 0 issues
  • apps/web/src/components/cloud-agent-next/github-repository-status.ts - 0 issues
  • apps/mobile/src/components/agents/new-session-repository-state.ts - 0 issues

Previous review (commit 6a9a879)

Status: 2 Issues Found | Recommendation: Address before merge

Executive Summary

The new unavailable/partial classification in github-integration-helpers.ts mislabels pending GitHub approval rows as reconnect states and hides a transient installation failure behind an unavailable sibling.

Assumptions: [INFERENCE] a pending installation row can outlive an unapproved request (the row is only completed by the installation webhook). The 87 locale additions were checked for key coverage and English copy, not reviewed language by language.

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
apps/web/src/lib/cloud-agent/github-integration-helpers.ts 132 pending installations fall through to not_configured, so an awaiting-approval connection is shown as "needs to be reconnected" / "not properly configured" and forces partial: true beside a healthy installation.
apps/web/src/lib/cloud-agent/github-integration-helpers.ts 361 When every installation is unreadable, a failed outcome is discarded as soon as any unavailable outcome exists, so a transient provider failure is reported as a terminal reconnect state and the caller never retries.
Files Reviewed (104 files)
  • apps/web/src/lib/cloud-agent/github-integration-helpers.ts - 2 issues
  • apps/web/src/lib/cloud-agent/github-integration-helpers.test.ts - 0 issues
  • apps/web/src/lib/integrations/personal-github-installation-selection.test.ts - 0 issues
  • apps/web/src/components/cloud-agent-next/NewSessionPanel.tsx - 0 issues
  • apps/web/src/components/cloud-agent-next/github-repository-status.ts - 0 issues
  • apps/web/src/components/cloud-agent-next/github-repository-status.test.ts - 0 issues
  • apps/web/src/components/cloud-agent-next/settings/RepositoryPicker.tsx - 0 issues
  • apps/web/src/routers/cloud-agent-next-router.ts - 0 issues
  • apps/web/src/routers/organizations/organization-cloud-agent-next-router.ts - 0 issues
  • apps/mobile/src/lib/use-new-session-repos.ts - 0 issues
  • apps/mobile/src/components/agents/new-session-repository-state.ts - 0 issues
  • apps/mobile/src/components/agents/new-session-repository-state.test.ts - 0 issues
  • apps/mobile/src/components/agents/new-session-repository-section.tsx - 0 issues
  • apps/mobile/src/components/agents/new-session-repository-section.test.ts - 0 issues
  • apps/mobile/src/components/agents/new-session-repository-section.test-helpers.ts - 0 issues
  • apps/mobile/src/components/agents/repository-card-actions.tsx - 0 issues
  • apps/mobile/src/components/agents/repository-provider-copy.ts - 0 issues
  • 87 apps/mobile/src/i18n/locales/*.json catalogs - 0 issues

Fix these issues in Kilo Cloud


Reviewed by deepseek-flash-latest · Input: 123.2K · Output: 8.9K · Cached: 766.1K

Review guidance: REVIEW.md from base branch main

- A rejected per-installation read next to an unusable installation now marks
  the result partial, so the pickers keep the retry control instead of showing
  only the unusable reason.
- A pending installation reports its own reason and message ("awaiting
  approval") instead of the generic not-configured wording.
The settings repository picker asked the cached query to refetch, which answers
from the stored snapshot. The partial-list retry now runs the same force-refresh
path the new-session picker uses.
Repository listings only read rows whose GitHub connection role is set, and the
role constraint requires a platform installation id, so an installation that is
still waiting for approval never reaches this classification. The generic
not-configured reason covers a stored row that cannot answer.
@iscekic iscekic added the merge:bot Bot-owned review; merge when ready once readiness passes and a review approves. label Oct 22, 2026
@iscekic
iscekic enabled auto-merge October 22, 2026 14:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

drain Work item from the findings drain janitor:features-workflows Janitor finding family: features-workflows merge:bot Bot-owned review; merge when ready once readiness passes and a review approves.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants