Skip to content

fix(ci): make HttpApi exerciser and Bun setup resilient to flakes - #13094

Draft
kirillk wants to merge 5 commits into
mainfrom
fix/ci-flaky-tests-and-bun-retry
Draft

fix(ci): make HttpApi exerciser and Bun setup resilient to flakes#13094
kirillk wants to merge 5 commits into
mainfrom
fix/ci-flaky-tests-and-bun-retry

Conversation

@kirillk

@kirillk kirillk commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

What

Resilience fixes that eliminate the most frequent transient CI failures on main. All three are the same root pattern — a network download or a single flaky scenario with no retry fails the whole gate:

  1. HttpApi exerciser scenario retry — the exerciser had no retry, so one flaky scenario failed the whole required test (linux) gate. Added --retries (default 2 extra attempts) in test/server/httpapi-exercise/. Retried passes are reported as flaky=N in the summary and tagged [attempt N] per line so flakes stay visible. A genuine regression still fails every attempt.
  2. Bun download retry.github/actions/setup-bun now retries the oven-sh/setup-bun download once (continue-on-error + a gated retry step), mirroring the existing Setup Node retry.
  3. Kilo CLI download retry (JetBrains)KiloCliDownloader fetched release metadata and the archive with single OkHttp calls; a dropped connection failed the whole jetbrains typecheck/build. Now retries transient network errors (up to 3 attempts, short backoff). HTTP status errors (404, rate limit) still fail immediately.

Why

Investigation of recent push runs on main showed the test workflow failing ~32% of the time, from transient classes:

  • HttpApi exerciser (4/8 test failures): always the identical scenario v2.session.permission.create (pass=314 fail=1). Cross-scenario state occasionally outlives the async reset between scenarios, flipping the created permission's effect away from "ask".
  • typecheck: socket hang up while downloading the Bun release.
  • typecheck-jetbrains (seen on this PR's own CI): java.net.SocketException: Unexpected end of file downloading the pinned Kilo CLI release. Confirmed transient — passed on re-run.

Retry is the contained, correct fix for all three: transient flakes recover on a second attempt, real breakage keeps failing.

Tests

  • New test/server/httpapi-exercise-retry.test.ts covers the exerciser retry decision logic (first-try pass, recover-after-one-failure with attempts=2, exhaust-all-attempts fail).
  • New KiloCliDownloaderTest."retries a dropped download and succeeds" uses MockWebServer with DISCONNECT_DURING_RESPONSE_BODY to prove the download recovers after a mid-transfer drop (13/13 downloader tests pass).
  • bun run typecheck, prettier, check-opencode-annotations.ts --worktree, and ./gradlew :backend:test --tests KiloCliDownloaderTest all pass. Ran the exerciser locally: permission scenarios green, flaky=0.

Not in scope (follow-up)

The remaining test failures are Windows unit-test flakes on the 4-vCPU runners — timeouts on a different test each run (KiloSnapshotTrack, config overlay routes, HttpApi Server.listen) plus a grep-signal-controls layer-init fetch() socket drop. These are real-time / harness-network races that need careful, individual rewrites (per the repo's "wait on a readiness signal, not wall-clock" guidance) and are intentionally left out of this PR to keep it low-risk. The unit runner already retries failed files once.

The `test` workflow was the dominant cause of red main (~32% of recent
push runs). Two transient failure classes accounted for most of it:

- The HttpApi exerciser has no retry, so a single flaky scenario (always
  `v2.session.permission.create`, `pass=314 fail=1`) failed the whole
  required gate. Cross-scenario state occasionally survives the async
  reset between scenarios, flipping the created permission's effect away
  from "ask".
- `typecheck` failed with `socket hang up` while `oven-sh/setup-bun`
  downloaded the Bun release — a pure network flake with no retry.

Add scenario-level retry to the exerciser (default 2 extra attempts,
`--retries`), report retried passes as `flaky=N` so they stay visible,
and retry the Bun download once, mirroring the existing Setup Node retry.
A genuine regression still fails every attempt.
@kilo-code-bot

kilo-code-bot Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: 1 Issue Found | Recommendation: Address before merge

Overview

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

SUGGESTION

File Line Issue
packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloCliDownloader.kt 280 Download progress percent resets to 0 on a retry — read/last re-initialize per attempt, so ConnectionState.Downloading briefly regresses after a mid-transfer flake (cosmetic)

Fix these issues in Kilo Cloud

Files Reviewed (1 file, incremental)
  • packages/kilo-jetbrains/build-tasks/src/main/kotlin/GenerateOpenApiSpecTask.kt (incremental: NETWORK_ATTEMPTS 4 → 5 and updated comment; backoff math in comment verified accurate — no new issues; previous suggestion on KiloCliDownloader.kt verified still present and remains open)
Previous Review Summaries (4 snapshots, latest commit cb86d1e)

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

Previous review (commit cb86d1e)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

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

SUGGESTION

File Line Issue
packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloCliDownloader.kt 280 Download progress percent resets to 0 on a retry — read/last re-initialize per attempt, so ConnectionState.Downloading briefly regresses after a mid-transfer flake (cosmetic)

Fix these issues in Kilo Cloud

Files Reviewed (1 file, incremental)
  • packages/kilo-jetbrains/build-tasks/src/main/kotlin/GenerateOpenApiSpecTask.kt (incremental: withRetry backoff for release metadata + archive download — no new issues; previous suggestion on KiloCliDownloader.kt remains open)

Previous review (commit 7f476c1)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

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

SUGGESTION

File Line Issue
packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloCliDownloader.kt 280 Download progress percent resets to 0 on a retry — read/last re-initialize per attempt, so ConnectionState.Downloading briefly regresses after a mid-transfer flake (cosmetic)

Fix these issues in Kilo Cloud

Files Reviewed (3 files)
  • .github/actions/setup-bun/action.yml (incremental: backoff + third attempt — no new issues)
  • packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloCliDownloader.kt - 1 issue
  • packages/kilo-jetbrains/backend/src/test/kotlin/ai/kilocode/backend/cli/KiloCliDownloaderTest.kt

Previous review (commit 71f36f2)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

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

SUGGESTION

File Line Issue
packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloCliDownloader.kt 280 Download progress percent resets to 0 on a retry — read/last re-initialize per attempt, so ConnectionState.Downloading briefly regresses after a mid-transfer flake (cosmetic)

Fix these issues in Kilo Cloud

Files Reviewed (2 files)
  • packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloCliDownloader.kt - 1 issue
  • packages/kilo-jetbrains/backend/src/test/kotlin/ai/kilocode/backend/cli/KiloCliDownloaderTest.kt

Previous review (commit 945fb7d)

Status: No Issues Found | Recommendation: Merge

lgtm — the retry logic is correct (Effects are safely re-run, each attempt gets a fresh Effect.scoped so per-attempt resources are released before the next attempt), --retries parsing validates input, the flaky/attempt reporting stays noise-free for first-try passes, the new test exercises the real retry implementation deterministically without mocks, and the continue-on-error + outcome == 'failure' Bun retry follows the correct GitHub Actions pattern. No memory-leak concerns introduced.

Files Reviewed (6 files)
  • .github/actions/setup-bun/action.yml
  • packages/opencode/test/server/httpapi-exercise-retry.test.ts
  • packages/opencode/test/server/httpapi-exercise/report.ts
  • packages/opencode/test/server/httpapi-exercise/routing.ts
  • packages/opencode/test/server/httpapi-exercise/runner.ts
  • packages/opencode/test/server/httpapi-exercise/types.ts

Reviewed by kimi-k3 · Input: 51.8K · Output: 3.1K · Cached: 231.9K

Review guidance: REVIEW.md from base branch main

The pinned CLI download in `generateOpenApiSpec` / connect-time resolve
used a single OkHttp call with no retry, so a transient network drop
(`java.net.SocketException: Unexpected end of file from server`) failed
the whole jetbrains typecheck/build. Retry the metadata fetch and the
archive download up to 3 times with a short backoff. HTTP status errors
(404, rate limit) still fail immediately without retry.
val url = url(version, platform, ext)
log.info("Downloading Kilo CLI $version for $platform from $url")
val request = Request.Builder().url(url).build()
retryNetwork("Downloading Kilo CLI $version for $platform") {

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.

SUGGESTION: Download progress resets to 0 on a retry

read and last are re-initialized on every retried attempt (they live inside the block passed to retryNetwork), so after a mid-transfer drop the reported percent jumps back down (e.g. 40% → 1%) before climbing again — consumers of ConnectionState.Downloading(percent, ...) in KiloBackendConnectionService will briefly see the progress bar regress. Consider hoisting the progress tracking outside the retry, or reporting a monotonic max across attempts, so the bar doesn't move backwards during a flake retry. Purely cosmetic; fine to leave as-is if you prefer.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

A single immediate retry did not cover GitHub release CDN blips that last
tens of seconds (observed: back-to-back "socket hang up" and HTTP 503
within ~20s). Attempt the Bun download up to three times with 15s/30s
backoff between tries; only the final attempt fails the job.
The build-time downloader (used by typecheck/build) threw immediately on
a dropped connection or transient 5xx (observed in CI: HTTP 503 from the
GitHub release CDN), failing the whole jetbrains typecheck. Retry both
the metadata fetch and the archive download on IOExceptions and 5xx with
a backoff (4 attempts). Permanent errors (404, rate limit, digest
mismatch) still fail immediately.

This complements the runtime KiloCliDownloader retry; the build task has
no cached fallback, so it also retries transient 5xx (the runtime path
intentionally fails fast on 5xx and reuses its cached CLI).
@kirillk
kirillk marked this pull request as draft August 13, 2026 00:04
t7tran pushed a commit to t7tran/kilocode that referenced this pull request Aug 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant