Skip to content

ci: split package unit jobs#125

Merged
Astro-Han merged 4 commits into
devfrom
codex/fix-i121-ci-stability
Apr 22, 2026
Merged

ci: split package unit jobs#125
Astro-Han merged 4 commits into
devfrom
codex/fix-i121-ci-stability

Conversation

@Astro-Han

@Astro-Han Astro-Han commented Apr 22, 2026

Copy link
Copy Markdown
Owner

Summary

  • split required Linux unit CI into app, opencode, and desktop package jobs
  • add a non-blocking Windows full unit-suite signal
  • add workflow contract coverage for docs-only behavior, aggregate gating, pinned actions, per-package artifacts, and Windows non-blocking status
  • stabilize the opencode unit tests from [Bug] Improve CI stability and split package unit jobs #121 and the workspace adaptor flaky surfaced by this PR CI
  • make app contract tests line-ending agnostic for the Windows signal
  • make desktop path assertions platform-native and remove real package-manager work from a config unit test
  • cap the non-blocking Windows unit signal at 15 minutes

Why

CI has been failing too often from a mix of broad unit jobs and known flaky tests. This keeps the required ci / check gate intact while making Linux unit failures easier to localize and adding Windows signal without blocking merges yet.

Related Issue

Closes #121

How To Verify

cd packages/opencode
bun test test/github/ci-workflow.test.ts
bun test --timeout 30000 test/config/seed-e2e.test.ts test/tool/edit.test.ts test/plugin/workspace-adaptor.test.ts

cd ../..
bun turbo test:ci --filter=@opencode-ai/app
bun turbo test:ci --filter=opencode
bun turbo test:ci --filter=@opencode-ai/desktop-electron
bun turbo typecheck

Screenshots or Recordings

Not applicable, CI-only change.

Checklist

  • I linked the related issue, or stated why there is no issue
  • This PR has type, scope, and priority labels, or I requested maintainer labeling
  • I listed the relevant verification steps, including tests when behavior changed
  • I manually checked visible UI or copy changes when needed, with screenshots or recordings
  • I considered macOS and Windows impact for desktop, packaging, updater, signing, paths, shell, or permissions changes
  • I called out docs, release notes, dependencies, permissions, credentials, deletion behavior, or generated/local file changes when relevant
  • I am targeting dev, and my PR title and commit messages use Conventional Commits in English

Summary by CodeRabbit

  • Tests

    • Increased test timeouts and stability; added helpers (deferred, timeout, polling), improved teardown via try/finally, normalized path/line-ending assertions, restored mocked spies, converted tests to effect-based style, and expanded CI workflow validations (action pinning, concurrency, docs-only detection, and per-platform unit job checks).
  • Chores

    • Reorganized CI: split Linux unit jobs by target with install steps, refined Windows unit reporting/artifacts, and updated aggregate check to require all Linux unit results.

@Astro-Han Astro-Han added bug Something isn't working ci Continuous integration / GitHub Actions flaky-test Non-deterministic test failure P1 High priority labels Apr 22, 2026
@coderabbitai

coderabbitai Bot commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@Astro-Han has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 18 minutes and 48 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 18 minutes and 48 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 263d20f0-02cd-4a51-b4f3-cda56d069ac3

📥 Commits

Reviewing files that changed from the base of the PR and between 1c346bd and 9aab003.

📒 Files selected for processing (10)
  • .github/workflows/ci.yml
  • packages/app/src/shell-frame-contract.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/prepare-embedded-server.test.ts
  • packages/opencode/src/tool/edit.ts
  • packages/opencode/test/config/config.test.ts
  • packages/opencode/test/config/seed-e2e.test.ts
  • packages/opencode/test/github/ci-workflow.test.ts
  • packages/opencode/test/plugin/workspace-adaptor.test.ts
  • packages/opencode/test/tool/edit.test.ts
📝 Walkthrough

Walkthrough

Split the single Linux unit job into package-scoped unit-app, unit-opencode, and unit-desktop with per-job caches, JUnit/artifact outputs, and package Turbo filters; made unit-windows a non-blocking signal; changed concurrency to be branch/PR-aware; fixed two flaky tests and expanded workflow contract tests to validate the new CI shape.

Changes

Cohort / File(s) Summary
CI Workflow Configuration
\.github/workflows/ci.yml
Replaced a single unit job with three Linux unit jobs (unit-app, unit-opencode, unit-desktop) each using distinct Turbo --filter, cache namespaces, bun install --frozen-lockfile, per-job JUnit check_name/report_paths, and artifact uploads; updated unit-windows globs/names/paths; changed concurrency.group expression and updated check job to depend on the three new unit jobs and aggregate their results.
Workflow Contract Tests
packages/opencode/test/github/ci-workflow.test.ts
Rewrote assertions with shared helpers and a pinned-actions map; added validations for pinned checkout/setup actions, persist-credentials:false, changes docs-only wiring, dev/PR concurrency semantics, split Linux unit job shape (needs/if/filters/junit/artifacts), non-blocking Windows job, and updated check aggregation behavior.
Opencode Seed E2E Test
packages/opencode/test/config/seed-e2e.test.ts
Increased AbortController timeout (5s→20s) and test timeout (15s→30s); on non-zero process exit now throws an Error including exit code, stdout, and stderr instead of a direct assertion.
Tool Edit Tests → Effect-based
packages/opencode/test/tool/edit.test.ts
Converted tests from manual ManagedRuntime to effect-based testEffect style; added effect helpers (init, run, expectRunFailure), deterministic deferred-based file-watcher event capture, removed manual runtime lifecycle, and updated layers/imports.
Workspace Adaptor Test
packages/opencode/test/plugin/workspace-adaptor.test.ts
Added waitFor(fn, timeout) polling helper and replaced fixed delay with polling until workspace status transitions away from "connecting", with explicit presence assertion.
Config install spy cleanup
packages/opencode/test/config/config.test.ts
Ensure Npm.install spy is restored via finally to avoid mock leakage outside the test.
Shell-frame file read normalization
packages/app/src/shell-frame-contract.test.ts
Normalize line endings in test read() helper by replacing \r\n with \n to make assertions platform-independent.
Desktop Electron CI tests (paths)
packages/desktop-electron/scripts/ci-smoke.test.ts, packages/desktop-electron/scripts/prepare-embedded-server.test.ts
Made path assertions platform-independent using path.join / path.resolve; added node:path import.

Sequence Diagram(s)

sequenceDiagram
    participant PR as Pull Request
    participant GH as GitHub Actions
    participant RunnerU as Runner (ubuntu)
    participant RunnerW as Runner (windows)
    participant Art as Artifact Store
    PR->>GH: push/open triggers workflow
    GH->>RunnerU: run `changes` job (docs-only detection)
    alt docs-only == false
        GH->>RunnerU: run `typecheck`
        GH->>RunnerU: run `unit-app`
        GH->>RunnerU: run `unit-opencode`
        GH->>RunnerU: run `unit-desktop`
        RunnerU->>Art: upload JUnit reports & artifacts per Linux job
        GH->>RunnerW: run `unit-windows` (continue-on-error)
        RunnerW->>Art: upload Windows JUnit & artifacts
    end
    GH->>GH: `check` aggregates Linux unit results (ignores windows) and posts combined status
    GH->>PR: report combined CI status
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped through CI with tiny paws and cheer,
Split the tests to run each package clear.
Windows whispers softly—it's only a sign,
Timeouts stretched kindly to let processes shine.
Artifacts glitter where the runners did steer.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'ci: split package unit jobs' is clear, concise, and accurately summarizes the primary change from splitting a monolithic unit job into package-specific Linux jobs.
Description check ✅ Passed The PR description follows the template structure with all major sections completed: Summary details the changes, Why explains the context and goals, Related Issue links #121, How To Verify provides verification commands, and the Checklist is fully checked.
Linked Issues check ✅ Passed The code changes fully address the coding requirements from issue #121: split Linux unit jobs by package with Turbo semantics, added Windows non-blocking signal, fixed known flaky tests (seed-e2e, tool.edit, workspace-adaptor), made tests platform-agnostic, updated workflow contract tests, and preserved docs-only behavior.
Out of Scope Changes check ✅ Passed All changes are aligned with the stated scope: workflow CI restructuring, flaky test stabilization, and test improvements. No out-of-scope changes like release workflow redesign, e2e gating, or broad test rewrites beyond identified flaky tests are present.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/fix-i121-ci-stability

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request focuses on improving test stability and CI workflow validation. It increases timeouts and adds detailed error reporting in seed-e2e.test.ts, refactors ci-workflow.test.ts to comprehensively validate GitHub Actions configurations, and enhances edit.test.ts with type-safe event subscriptions and asynchronous test helpers. Feedback from the reviewer suggests refining the withTimeout utility for better resource management and increasing a test timeout to 5,000ms to reduce flakiness in CI environments.

Comment thread packages/opencode/test/tool/edit.test.ts Outdated
Comment thread packages/opencode/test/tool/edit.test.ts Outdated

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/opencode/test/config/seed-e2e.test.ts (1)

16-65: ⚠️ Potential issue | 🟡 Minor

Replace manual temp directory creation with tmpdir() and await using for cleaner cleanup.

The test can improve by using the standard tmpdir() helper with await using syntax instead of manual mkdtemp and fs.rm cleanup. See acp/event-subscription.test.ts for examples of this pattern in non-Effect tests:

Example refactor
await using tmp = await tmpdir()
const [home, data, cache, config, state] = await Promise.all([
  tmpdir({ init: async () => "home" }).then(t => t.path),
  // ... or distribute across separate tmpdir calls
])
// cleanup is automatic when scope exits

The test doesn't require migration to testEffect(...)/it.live(...) since it doesn't exercise Effect services—it's a subprocess orchestration test that works fine with standard async/await.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/opencode/test/config/seed-e2e.test.ts` around lines 16 - 65, Replace
the manual mkdir+Promise.all and explicit fs.rm cleanup in the seed-e2e.test's
test block with the tmpdir() helper and JavaScript's "await using" scope so
temporary directories are auto-cleaned; specifically, inside the
withConfigDepsLock callback create tmpdir instances (via tmpdir() or
tmpdir({init: ...}) as needed) instead of calling mkdir("opencode-seed-*"),
extract their .path values for OPENCODE_TEST_HOME/XDG_* env entries, and remove
the Promise.allSettled fs.rm block and clearTimeout cleanup since the await
using scope will dispose the tmpdirs automatically while keeping the existing
AbortController/timer logic and Process.run usage intact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/opencode/test/config/seed-e2e.test.ts`:
- Around line 51-57: Remove the redundant assertion after the explicit throw:
the code already throws an Error when out.code !== 0 (the block that constructs
`new Error(...)` using `out.code`, `out.stdout`, and `out.stderr`), so delete
the final `expect(out.code).toBe(0)` assertion that follows it; keep the
existing throw-based check and any surrounding test scaffolding that relies on
the `out` variable.

In `@packages/opencode/test/tool/edit.test.ts`:
- Around line 56-78: Replace the custom ManagedRuntime and Promise helpers by
converting each test to use testEffect(...) with it.live(...): remove
subscribeBus, deferred, withTimeout and the ManagedRuntime setup and instead
write tests as Effect.gen(...) that yields required services (EditTool,
Bus.Service, FileWatcher) directly and uses runtime-provided effect combinators
for async/waiting; ensure bus subscriptions use Bus.Service.subscribeCallback
via yielded bus, and replace manual timeouts with effect-based test timeouts or
testEffect's timeout helpers so each test runs live under testEffect/it.live.

---

Outside diff comments:
In `@packages/opencode/test/config/seed-e2e.test.ts`:
- Around line 16-65: Replace the manual mkdir+Promise.all and explicit fs.rm
cleanup in the seed-e2e.test's test block with the tmpdir() helper and
JavaScript's "await using" scope so temporary directories are auto-cleaned;
specifically, inside the withConfigDepsLock callback create tmpdir instances
(via tmpdir() or tmpdir({init: ...}) as needed) instead of calling
mkdir("opencode-seed-*"), extract their .path values for
OPENCODE_TEST_HOME/XDG_* env entries, and remove the Promise.allSettled fs.rm
block and clearTimeout cleanup since the await using scope will dispose the
tmpdirs automatically while keeping the existing AbortController/timer logic and
Process.run usage intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 05cd13f1-cf52-4df1-bdfb-d55e6bb134ee

📥 Commits

Reviewing files that changed from the base of the PR and between 935ab33 and e098996.

📒 Files selected for processing (4)
  • .github/workflows/ci.yml
  • packages/opencode/test/config/seed-e2e.test.ts
  • packages/opencode/test/github/ci-workflow.test.ts
  • packages/opencode/test/tool/edit.test.ts

Comment thread packages/opencode/test/config/seed-e2e.test.ts Outdated
Comment thread packages/opencode/test/tool/edit.test.ts Outdated

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/ci.yml (1)

132-343: 🧹 Nitpick | 🔵 Trivial

Consider: The three Linux unit jobs share significant boilerplate.

While the current structure provides clear failure isolation per package, the repeated steps (checkout, node/bun setup, caching, install) could be consolidated using a matrix strategy or reusable composite action. However, given the PR objectives explicitly call for package-scoped jobs that make failures "easier to localize," and the tests validate this exact structure, the current approach is a reasonable trade-off for clarity.

💡 Alternative: Matrix-based approach (optional)

If duplication maintenance becomes burdensome, a matrix could consolidate the jobs while preserving package-scoped reporting:

unit:
  needs: changes
  if: needs.changes.outputs.docs_only != 'true'
  runs-on: ubuntu-latest
  timeout-minutes: 30
  strategy:
    fail-fast: false
    matrix:
      include:
        - package: app
          filter: "@opencode-ai/app"
          path: packages/app
        - package: opencode
          filter: "opencode"
          path: packages/opencode
        - package: desktop
          filter: "@opencode-ai/desktop-electron"
          path: packages/desktop-electron
  # ... steps using ${{ matrix.filter }}, ${{ matrix.path }}, etc.

This would require adjusting the check job to reference matrix job results differently.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/ci.yml around lines 132 - 343, The three jobs unit-app,
unit-opencode, and unit-desktop duplicate identical setup/install steps; replace
them with a single job (e.g., unit) that uses strategy.matrix.include entries
for each package (include keys: package, filter, path) and convert the repeated
steps (actions/checkout, actions/setup-node, oven-sh/setup-bun, actions/cache,
bun install, bun turbo test:ci) to use ${{ matrix.filter }} and ${{ matrix.path
}}; update the Publish unit reports and Upload unit artifacts steps to reference
the matrix values (e.g., report_paths: ${{ matrix.path
}}/.artifacts/unit/junit.xml and artifact name using ${{ matrix.package }}), set
strategy.fail-fast: false to preserve per-package failure isolation, and ensure
any other jobs that read these results (like the check job) are adjusted to
consume matrix job outputs if needed.
♻️ Duplicate comments (1)
packages/opencode/test/tool/edit.test.ts (1)

61-78: 🛠️ Refactor suggestion | 🟠 Major

Please avoid adding more ad hoc Promise test helpers in this Effect test file.

deferred/withTimeout extend manual async orchestration instead of moving this suite to the standard Effect test harness pattern already requested.

#!/bin/bash
set -euo pipefail

# Verify this file still uses custom runtime/promise wrappers and does not use the standard harness.
rg -n --type=ts 'ManagedRuntime\.make|runPromise\(|function deferred<|function withTimeout<|testEffect\(|\bit\.(effect|live)\(' packages/opencode/test/tool/edit.test.ts

As per coding guidelines: "Use testEffect(...) from test/lib/effect.ts for tests that exercise Effect services or Effect-based workflows." and "Avoid custom ManagedRuntime, attach(...), or ad hoc run(...) wrappers in Effect tests when testEffect(...) already provides the runtime."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/opencode/test/tool/edit.test.ts` around lines 61 - 78, The test file
introduces ad-hoc Promise helpers deferred and withTimeout which bypass the
standard Effect test harness; remove the functions deferred and withTimeout from
packages/opencode/test/tool/edit.test.ts and refactor any tests that use them to
use the existing test harness API testEffect (from test/lib/effect.ts) and its
provided runtime utilities (e.g., runPromise/testEffect's effect assertions or
timeouts) so the tests run under the managed Effect runtime instead of manual
promise orchestration; search for usages of deferred, withTimeout, runPromise,
ManagedRuntime.make, attach, or it.effect/it.live in this file and replace those
patterns with testEffect and the harness equivalents.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/opencode/test/plugin/workspace-adaptor.test.ts`:
- Around line 129-130: The waitFor predicate and subsequent assertion
incorrectly treat a missing status entry as success; update the polling to first
find the entry via Workspace.status().find(item => item.workspaceID === info.id)
and ensure the entry exists and its status !== "connecting" (e.g., entry &&
entry.status !== "connecting"), and update the expect to assert the found entry
exists and its status is not "connecting" so the test only passes after the
workspace status actually transitions.

In `@packages/opencode/test/tool/edit.test.ts`:
- Around line 351-353: The 1,000ms hardcoded timeout on
withTimeout(event.promise, 1_000, ...) is too short for CI and causes flakes;
update the call to use a larger timeout (e.g. 5_000) or replace the literal with
a shared test timeout constant (e.g. TEST_TIMEOUT = 5000) and reference that in
the withTimeout invocation to give filesystem/bus propagation more headroom.

---

Outside diff comments:
In @.github/workflows/ci.yml:
- Around line 132-343: The three jobs unit-app, unit-opencode, and unit-desktop
duplicate identical setup/install steps; replace them with a single job (e.g.,
unit) that uses strategy.matrix.include entries for each package (include keys:
package, filter, path) and convert the repeated steps (actions/checkout,
actions/setup-node, oven-sh/setup-bun, actions/cache, bun install, bun turbo
test:ci) to use ${{ matrix.filter }} and ${{ matrix.path }}; update the Publish
unit reports and Upload unit artifacts steps to reference the matrix values
(e.g., report_paths: ${{ matrix.path }}/.artifacts/unit/junit.xml and artifact
name using ${{ matrix.package }}), set strategy.fail-fast: false to preserve
per-package failure isolation, and ensure any other jobs that read these results
(like the check job) are adjusted to consume matrix job outputs if needed.

---

Duplicate comments:
In `@packages/opencode/test/tool/edit.test.ts`:
- Around line 61-78: The test file introduces ad-hoc Promise helpers deferred
and withTimeout which bypass the standard Effect test harness; remove the
functions deferred and withTimeout from packages/opencode/test/tool/edit.test.ts
and refactor any tests that use them to use the existing test harness API
testEffect (from test/lib/effect.ts) and its provided runtime utilities (e.g.,
runPromise/testEffect's effect assertions or timeouts) so the tests run under
the managed Effect runtime instead of manual promise orchestration; search for
usages of deferred, withTimeout, runPromise, ManagedRuntime.make, attach, or
it.effect/it.live in this file and replace those patterns with testEffect and
the harness equivalents.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d3f43f08-2a4d-4382-a95f-effc78726331

📥 Commits

Reviewing files that changed from the base of the PR and between e098996 and ffabe14.

📒 Files selected for processing (3)
  • .github/workflows/ci.yml
  • packages/opencode/test/plugin/workspace-adaptor.test.ts
  • packages/opencode/test/tool/edit.test.ts

Comment thread packages/opencode/test/plugin/workspace-adaptor.test.ts Outdated
Comment thread packages/opencode/test/tool/edit.test.ts Outdated

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

♻️ Duplicate comments (1)
packages/opencode/test/tool/edit.test.ts (1)

56-75: 🛠️ Refactor suggestion | 🟠 Major

This extends the custom runtime/Promise harness instead of moving the file onto testEffect(...).

The new subscribeBus, deferred, and withTimeout helpers add more ad hoc scaffolding around Effect services in a file that should use the repository’s Effect test harness.

Run this to confirm the file is still growing the custom-runtime pattern instead of the repo-standard testEffect(...)/it.live(...) pattern:

#!/bin/bash
set -euo pipefail

rg -n --type=ts 'ManagedRuntime\.make|subscribeBus|deferred\(|withTimeout\(' packages/opencode/test/tool/edit.test.ts
printf '\n--- reference patterns elsewhere ---\n'
rg -n --type=ts 'const it = testEffect|it\.live\(' packages/opencode/test

As per coding guidelines, "Use testEffect(...) from test/lib/effect.ts for tests that exercise Effect services or Effect-based workflows." and "Avoid custom ManagedRuntime, attach(...), or ad hoc run(...) wrappers in Effect tests when testEffect(...) already provides the runtime."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/opencode/test/tool/edit.test.ts` around lines 56 - 75, The test file
is using ad-hoc runtime helpers (subscribeBus, deferred, withTimeout and
runtime.runPromise/Bus.Service.use) instead of the repo-standard Effect test
harness; refactor the test to use testEffect/it.live from test/lib/effect.ts:
remove subscribeBus, deferred, and withTimeout helpers, move the test body into
testEffect(...) or it.live(...) and perform Bus subscription inside the
testEffect environment (use Bus.Service within the testEffect effect instead of
runtime.runPromise/Bus.Service.use), replace manual promise/timeouts with the
harness's async/timeout utilities or Effect-friendly equivalents, and ensure
assertions run inside the testEffect effect so the standard runtime handles
lifecycle and cleanup.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/opencode/test/github/ci-workflow.test.ts`:
- Around line 22-28: The helper function runStep should be renamed to stepByName
for clarity; update the function declaration (rename runStep to stepByName) and
change every call site that currently calls runStep(...) to call
stepByName(...), keeping the same parameter order and return behavior; ensure
any nearby helpers like checkoutStep remain unchanged and run the tests to
verify no references to runStep remain.

In `@packages/opencode/test/tool/edit.test.ts`:
- Around line 330-353: The test subscribes to FileWatcher.Event.Updated and
resolves the deferred on the first event regardless of file; update the
subscription callback (from subscribeBus(FileWatcher.Event.Updated, ...)) to
inspect the incoming payload.properties.file and only call event.resolve(...)
when payload.properties.file === filepath (and then optionally call
unsubUpdated() to stop listening), so the deferred (event.promise) only resolves
for the specific file edit triggered by edit.execute; ensure the current
references to event.resolve, event.promise, subscribeBus,
FileWatcher.Event.Updated, edit.execute, and filepath are used to implement this
filter.

---

Duplicate comments:
In `@packages/opencode/test/tool/edit.test.ts`:
- Around line 56-75: The test file is using ad-hoc runtime helpers
(subscribeBus, deferred, withTimeout and runtime.runPromise/Bus.Service.use)
instead of the repo-standard Effect test harness; refactor the test to use
testEffect/it.live from test/lib/effect.ts: remove subscribeBus, deferred, and
withTimeout helpers, move the test body into testEffect(...) or it.live(...) and
perform Bus subscription inside the testEffect environment (use Bus.Service
within the testEffect effect instead of runtime.runPromise/Bus.Service.use),
replace manual promise/timeouts with the harness's async/timeout utilities or
Effect-friendly equivalents, and ensure assertions run inside the testEffect
effect so the standard runtime handles lifecycle and cleanup.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 719677fe-ba89-4c3e-9f31-533fa6d9446b

📥 Commits

Reviewing files that changed from the base of the PR and between ffabe14 and c52c957.

📒 Files selected for processing (9)
  • .github/workflows/ci.yml
  • packages/app/src/shell-frame-contract.test.ts
  • packages/desktop-electron/scripts/ci-smoke.test.ts
  • packages/desktop-electron/scripts/prepare-embedded-server.test.ts
  • packages/opencode/test/config/config.test.ts
  • packages/opencode/test/config/seed-e2e.test.ts
  • packages/opencode/test/github/ci-workflow.test.ts
  • packages/opencode/test/plugin/workspace-adaptor.test.ts
  • packages/opencode/test/tool/edit.test.ts

Comment thread packages/opencode/test/github/ci-workflow.test.ts
Comment thread packages/opencode/test/tool/edit.test.ts Outdated

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

♻️ Duplicate comments (1)
packages/opencode/test/tool/edit.test.ts (1)

76-92: ⚠️ Potential issue | 🟠 Major

Use the actual watcher payload and scope the subscription to the target file.

FileWatcher.Event.Updated is published as { file, event }, so payload.properties is the wrong shape here. Separately, resolving on the first update from any file can still pick up unrelated watcher traffic and reintroduce the flake this helper is supposed to remove. Pass the expected path into nextFileUpdate, ignore non-matching events, and resolve the deferred with payload itself.

🛠️ Suggested fix
 const nextFileUpdate = <A, E, R>(
+  file: string,
   trigger: Effect.Effect<A, E, R>,
 ) =>
   Effect.acquireUseRelease(
     Effect.gen(function* () {
       const deferred = yield* Deferred.make<FileUpdate>()
       const bus = yield* Bus.Service
       const unsubscribe = yield* bus.subscribeCallback(FileWatcher.Event.Updated, (payload) => {
-        Deferred.doneUnsafe(deferred, Effect.succeed(payload.properties))
+        if (payload.file !== file) return
+        Deferred.doneUnsafe(deferred, Effect.succeed(payload))
       })
       return { deferred, unsubscribe }
     }),
@@
-          const event = yield* nextFileUpdate(
+          const event = yield* nextFileUpdate(
+            filepath,
             run({
               filePath: filepath,
               oldString: "",
               newString: "content",
             }),
@@
-          const event = yield* nextFileUpdate(
+          const event = yield* nextFileUpdate(
+            filepath,
             run({
               filePath: filepath,
               oldString: "original",
               newString: "modified",
             }),

Also applies to: 135-141, 267-273

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/opencode/test/tool/edit.test.ts` around lines 76 - 92, The helper
nextFileUpdate should accept the expected file path, subscribe to
FileWatcher.Event.Updated, filter events to only resolve when payload.file
matches that path, and resolve the Deferred with the full payload (not
payload.properties); update the signature of nextFileUpdate to take a path
string, change the subscribeCallback handler in the acquisition to check
payload.file === expectedPath and call Deferred.doneUnsafe(deferred,
Effect.succeed(payload)), and keep the same unsubscribe/timeout behavior; apply
the same change to the other occurrences referenced (around the other ranges
mentioned) so the helper only resolves on matching-file updates.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/opencode/test/tool/edit.test.ts`:
- Around line 575-591: The current test spawns two concurrent run(...) edits and
only asserts that at least one succeeded; update the assertion to verify exactly
one success and one failure (use Exit.isSuccess on each element of results to
count successes) and then read the final file content for filepath to assert it
equals either "1" or "2" (this ensures edits were serialized per-file). Locate
the test's run invocation and results variable in edit.test.ts and replace the
loose expect(...) with: count successes == 1 and count failures == 1, followed
by a file-read check that the file content is strictly "1" or "2".

---

Duplicate comments:
In `@packages/opencode/test/tool/edit.test.ts`:
- Around line 76-92: The helper nextFileUpdate should accept the expected file
path, subscribe to FileWatcher.Event.Updated, filter events to only resolve when
payload.file matches that path, and resolve the Deferred with the full payload
(not payload.properties); update the signature of nextFileUpdate to take a path
string, change the subscribeCallback handler in the acquisition to check
payload.file === expectedPath and call Deferred.doneUnsafe(deferred,
Effect.succeed(payload)), and keep the same unsubscribe/timeout behavior; apply
the same change to the other occurrences referenced (around the other ranges
mentioned) so the helper only resolves on matching-file updates.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1e399ea5-8357-4c34-a965-233f7d0cb8f2

📥 Commits

Reviewing files that changed from the base of the PR and between c52c957 and 1c346bd.

📒 Files selected for processing (1)
  • packages/opencode/test/tool/edit.test.ts

Comment thread packages/opencode/test/tool/edit.test.ts Outdated
@Astro-Han Astro-Han force-pushed the codex/fix-i121-ci-stability branch from 35b243f to 7ea96e9 Compare April 22, 2026 07:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working ci Continuous integration / GitHub Actions flaky-test Non-deterministic test failure P1 High priority

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Improve CI stability and split package unit jobs

1 participant