fix(integration-tests): await rig.setup in Qoder plugin install test (#8766) - #8768
fix(integration-tests): await rig.setup in Qoder plugin install test (#8766)#8768qwen-code-dev-bot wants to merge 7 commits into
Conversation
Autofix E2E report — issue #8766Failing test: Root causeThe new
Evidence:
FixOne line: Verification
中文说明Autofix E2E 报告 — issue #8766失败测试: 根因新增的
随后 证据:
修复一行改动: 验证
🧠 Handled by Qwen Code · model/模型 |
Code Coverage Summary
CLI Package - Full Text ReportCore Package - Full Text ReportFor detailed HTML reports, please see the 'coverage-reports-22.x-ubuntu-latest' artifact from the main CI run. |
|
Thanks for the PR! Template looks good ✓ Problem: observed bug with solid evidence — main-branch E2E failed on Direction: aligned — this keeps the integration suite trustworthy right after the Qoder plugin support landed. CHANGELOG: not applicable (test infrastructure, no product change). Size: not applicable — no core paths touched (1 file, +1/−1, all test code). Approach: minimal and correct — the one-word Risk: no elevated risk signals (no high-risk paths matched). Moving on to code review. 🔍 中文说明感谢贡献! 模板完整 ✓ 问题:已观测到的 bug,证据充分——main 分支 E2E 在 方向:对齐——Qoder 插件支持刚合入,这个修复保障了集成测试套件的可信度。CHANGELOG:不适用(测试基础设施,无产品变更)。 规模:不适用——未触及核心路径(1 个文件,+1/−1,全部为测试代码)。 方案:最小且正确——一词 风险:无升级风险信号(未命中高风险路径)。 进入代码审查 🔍 — Qwen Code · qwen3.8-max Reviewed at |
Code reviewIndependent proposal before reading the diff: the failure signature (install exits with The diff is a single-word change: Test evidence (PR's own CI at
|
| Check | Conclusion |
|---|---|
Classify PR |
✅ success |
Desktop Shell (ubuntu-22.04) |
✅ success |
Desktop Shell (windows-2022) |
✅ success |
Post Coverage Comment (ubuntu-latest, 22.x) |
✅ success |
Test (ubuntu-latest, Node 22.x) |
✅ success |
web-shell E2E Smoke (ubuntu-latest, Node 22.x) |
✅ success |
One row per check name (latest run); skipped checks omitted; failures sort first. / 每个检查名一行(取最新一次运行),省略 skipped,失败项排在最前。
CI hasn't settled yet, and it won't prove the central claim regardless: Integration Tests (CLI, No Sandbox) — the job that actually runs extensions-install.test.ts — is skipped on this PR, and the unit-test matrix doesn't cover this test either. Nothing in CI so far exercises the fixed code path; the finalize job will update the table above once CI lands.
Sandboxed verification would settle this: @qwen-code /verify — that installs a local Qoder plugin failed before the change and passes consistently after it is not observable from this PR's CI (the integration job is skipped); a targeted run of integration-tests/cli/extensions-install.test.ts against head vs base would pin the fix.
Not verified here: real-scenario execution — unattended CI runs never execute PR code. The author-reported before/after runs (3/3 failed → 4/4 passed) are the bot's claim, not independent evidence, though the static mechanism above is unambiguous.
中文说明
代码审查
读 diff 之前的独立判断:失败特征(安装以 Configuration file not found 退出、保留的测试目录中只剩 .qwen/settings.json)指向夹具写入后被删除——因此修复方式就是 await rig.setup(),让它开头的递归 rm 在测试写入夹具之前完成。PR 正是这么做的。
diff 是一词之差:installs a local Qoder plugin 用例中 rig.setup(...) → await rig.setup(...)。对照 test-helper.ts 验证:setup() 先赋值 testDir,然后执行 await rm(testDir, { recursive: true, force: true }),再重建目录——没有 await 时,这个递归删除会在 libuv 线程池上继续运行,而测试主体同时同步地向同一目录写入 .qoder-plugin/plugin.json、system-prompt.md 和一个技能,在负载较高的 runner 上删除就会落在写入之后。该 rm 上方的注释恰好记录了这类隐患。这是整个集成套件中唯一未 await 的 rig.setup 调用——其余 298 处全部 await。未触及产品代码。无审查发现。
测试证据(PR 自身 CI 在 17d9…d50 上的结果,通过 API 获取——本流程未执行 PR 代码)
CI 尚未结束,而且无论如何都无法证明核心论断:真正运行 extensions-install.test.ts 的 Integration Tests (CLI, No Sandbox) 在本 PR 上被跳过,单元测试矩阵也不覆盖该测试。目前 CI 中没有任何环节执行被修复的代码路径;CI 结束后 finalize 任务会更新上方表格。
沙箱验证可以一锤定音:@qwen-code /verify——修复前失败、修复后稳定通过这一点无法从本 PR 的 CI 观察到(integration 任务被跳过);对 head 与 base 定向运行 integration-tests/cli/extensions-install.test.ts 即可钉住该修复。
此处未验证:真实场景执行——无人值守 CI 从不执行 PR 代码。作者自述的 before/after 结果(3/3 失败 → 4/4 通过)是机器人的声明,不是独立证据,但上述静态机制已足够明确。
— Qwen Code · qwen3.8-max
Reviewed at 17d99ebae11e6df6ac2b3f90c8430578c4a92d50 · re-run with @qwen-code /triage
|
Confidence: 5/5 — observed main-branch failure, unambiguous mechanical root cause, and the minimal possible fix matching the suite-wide convention. Stepping back: this is the kind of PR the gate should wave through. The problem is real (three main-CI failures logged in #8766), the root cause is verifiable by reading Verdict: approve — but the 中文说明置信度:5/5 —— 已观测到的 main 分支失败、机制明确的根因,以及与全套件约定一致的最小修复。 退一步看:这正是门禁应该快速放行的 PR。问题是真实的(#8766 记录了三次 main CI 失败);根因可通过阅读 结论:批准——但该 head 上的 — Qwen Code · qwen3.8-max Reviewed at |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship — CI landed green after the review. ✅
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed — no blockers. Suggestions are inline.
中文说明
已审查——无阻断问题。 建议见行内评论。
— qwen3.8-max via Qwen Code /review (v0.21.8)
| test('installs a local Qoder plugin', async () => { | ||
| const rig = new TestRig(); | ||
| rig.setup('qoder plugin install test'); | ||
| await rig.setup('qoder plugin install test'); |
There was a problem hiding this comment.
[Suggestion] This test file is not collected by any per-PR test gate: it sits outside every npm workspace, so workspace-scoped test commands never collect it, and no per-PR CI job does either — the only pre-merge collector is the merge-queue-gated integration_cli job, which per its own workflow comment never triggers until merge queue is enabled on main, while e2e.yml runs it only post-merge. — Concrete cost: if this fix were wrong, or a future edit regressed this test, per-PR CI would stay green and the failure would surface only post-merge or at release time. Pre-existing CI-config property, untouched by this diff (the test itself passes — verified locally 2/2 under QWEN_SANDBOX=false); informational about gating, not a defect in this change.
中文说明
该测试文件未被任何 per-PR 测试关卡收集:它位于所有 npm workspace 之外,workspace 范围的测试命令不会收集它,也没有任何 per-PR CI job 会收集它——唯一在合并前收集它的 integration_cli job 受 merge queue 门控,按其工作流自身的注释,在 main 启用 merge queue 之前它永远不会触发;而 e2e.yml 只在合并后运行它。——具体代价:如果本修复有误,或未来的编辑导致该测试回归,per-PR CI 仍会显示绿色,失败只会在合并后或发布时才暴露。这是仓库预先存在的 CI 配置问题,本 diff 未改动(测试本身已通过——已在本地 QWEN_SANDBOX=false 下验证 2/2 通过);此为关于 CI 门控的提示信息,并非本改动的缺陷。
— qwen3.8-max via Qwen Code /review (v0.21.8)
|
🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下: Autofix review round — no action (PR #8768 / issue #8766)One finding was triaged this round — a single automated [Suggestion]. It was declined with recorded evidence, so no code changes were made and no commit was created. Finding dispositions[rc:3742172045]
|
|
🔀 Base updated: red check(s) [Test (ubuntu-latest, Node 22.x)] pass on current main — merged current main via update-branch; CI will re-run. 中文说明🔀 已更新 base:红色检查 [Test (ubuntu-latest, Node 22.x)] 在当前 main 上通过 —— 已通过 update-branch 合入当前 main,CI 将重新运行。 |
|
🔀 Base updated: red check(s) [Test (ubuntu-latest, Node 22.x)] pass on current main — merged current main via update-branch; CI will re-run. 中文说明🔀 已更新 base:红色检查 [Test (ubuntu-latest, Node 22.x)] 在当前 main 上通过 —— 已通过 update-branch 合入当前 main,CI 将重新运行。 |
|
🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下: Autofix review round — no action taken (PR #8768, issue #8766)The only new feedback this round is the failed check Test (ubuntu-latest, Node 22.x) (run 31486072868). There are no new review, inline, or issue comments. After diagnosis, there is no code change this PR can make, for the reasons below. Why there is nothing to changeThis PR's diff against Local reproduction of the Test job (evidence)I reproduced the Test job's steps locally in CI order (Node v22.23.2, clean CI-equivalent environment: fresh
The only local failures were traced to my environment, not the code:
Remaining steps I could not run exactly: ConclusionThe Test failure does not reproduce locally on this exact tree; every reproducible component of the job passes. Combined with the empty diff, this is consistent with a transient/CI-environment failure on content identical to current 中文说明Autofix 审查轮次 — 未采取任何操作(PR #8768,issue #8766)本轮唯一的新反馈是失败的检查 Test (ubuntu-latest, Node 22.x)(run 31486072868)。没有新的审查评论、行内评论或 issue 评论。经过诊断,本 PR 无法做出任何代码更改,原因如下。 为什么没有可更改的内容本 PR 相对于 Test 检查的本地复现(证据)我在本地按 CI 顺序复现了 Test 检查的各个步骤(Node v22.23.2,干净的类 CI 环境:全新
唯一的本地失败均追溯到我的环境,而非代码:
无法完全本地执行的剩余步骤: 结论Test 失败无法在这个完全相同的树上本地复现;该检查所有可复现的组成部分均通过。结合差异为空的事实,这与当前 Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。 🧠 Handled by Qwen Code · model/模型 |
|
🔀 Base updated: red check(s) [Test (ubuntu-latest, Node 22.x)] pass on current main — merged current main via update-branch; CI will re-run. 中文说明🔀 已更新 base:红色检查 [Test (ubuntu-latest, Node 22.x)] 在当前 main 上通过 —— 已通过 update-branch 合入当前 main,CI 将重新运行。 |
Local verification report (real build, macOS)Verdict: the fix is correct and now also verified on macOS — but this PR is a no-op against I built the PR head ( Environment
This adds the 🍏 macOS leg that the PR description marks as 1. The fix is load-bearing — 10×10 single-line A/BSame build, same command, same machine. Only line 56 was flipped between arms:
On this machine the race is not merely flaky, it is deterministic: the un-awaited version failed 10 out of 10 times, including all vitest retries (each failing run logs the same error 4–5 times: initial + The failure signature reproduced locally is byte-for-byte the one reported in #8766: 2. Root cause confirmed on the filesystem (
|
| Arm | Files surviving in qoder-plugin-install-test/ |
|---|---|
A (with await), exit 0 |
.qoder-plugin/plugin.json, .qwen/settings.json, skills/sample-skill/SKILL.md, system-prompt.md |
B (no await), exit 1 |
.qwen/settings.json only |
All three fixtures the test writes immediately after setup() are gone in arm B — deleted by TestRig.setup()'s own await rm(this.testDir, { recursive: true, force: true }) (integration-tests/test-helper.ts:222) still running on the libuv thread pool. This is direct evidence that the defect is the un-awaited setup, not the Qoder conversion/install path — that path works fine as soon as the fixtures survive (arm A installs and lists sample-qoder-plugin successfully).
3. Completeness
grep -rn 'rig\.setup(' integration-tests --include='*.ts' → 300 call sites, 0 un-awaited (the single non-await hit is a code comment in cli/settings-migration.test.ts:55). The one-line fix covers the whole suite; there is no sibling call site left behind.
4. …but this PR no longer changes anything
$ gh pr diff 8768 | wc -l
0
$ git diff origin/main pr8768-head -- integration-tests/cli/extensions-install.test.ts | wc -l
0
The same one-word change was merged into main on 2026-08-09 by #8793 (d8c15b3456). The two diffs are byte-identical — both are index 2d938bc85d..dae6b8a2ec. Consequences:
- Merging this PR would produce an empty commit; the tree of
mainwould not change. - Main CI failed: E2E Tests — cli/extensions-install.test.ts > installs a local Qoder plugin #8766 is already CLOSED (
2026-08-09T08:31:58Z), closed by fix(tests): await rig setup in Qoder plugin install integration test #8793. - The follow-up dedupe issue Main CI failed: E2E Tests — cli/extensions-install.test.ts > installs a local Qoder plugin #8799 has exactly one recurrence, on
ab61d81097dc— which is an ancestor of the fix commit, i.e. a CI run that started before fix(tests): await rig setup in Qoder plugin install integration test #8793 landed. There has been no recurrence of this failure onmainsince, and recentmainE2E runs (through0e8a361b37, 2026-08-11) are green.
Recommendation
| Change correctness | ✅ verified — deterministic 10/10 vs 0/10 A/B on macOS, root cause proven on the filesystem |
| Merge value | ❌ zero — net diff against main is empty; the fix shipped in #8793 |
| Suggested action | Close #8768 as superseded by #8793 (and let the autofix bot mark it resolved), no revert or follow-up needed |
Nothing here argues against the change itself — if it had not already landed, this evidence would support merging it as-is. It simply arrived second.
Out of scope / not validated: Windows E2E leg; sandboxed (QWEN_SANDBOX=docker|podman) runs; no product code was exercised beyond the extensions install|list|uninstall paths this test drives.
中文版本(点击展开)
本地验证报告(真实构建,macOS)
结论:修复本身正确,并且在 macOS 上也已验证通过;但本 PR 相对 main 已是空改动——同样的一行修复已经通过 #8793 合入。建议关闭本 PR,而不是合并。
我从源码构建了 PR head(494e4ec46d),用真实 bundle 跑了真实集成测试,并做了单行变异 A/B,以证明这一行 await 是必需的。
环境
| 项 | 值 |
|---|---|
| 操作系统 | macOS 15(Darwin 25.6.0),Apple Silicon |
| Node | v24.18.1 |
| 构建 | npm ci && npm run build && npm run bundle → dist/cli.js(qwen 0.21.9) |
| 命令 | npx cross-env QWEN_SANDBOX=false vitest run cli/extensions-install.test.ts |
| 配置 | 原样使用 integration-tests/vitest.config.ts(retry: 2,与 CI 一致) |
这补上了 PR 描述中标记为
1. 这行修复确实是关键——10×10 单行 A/B
同一构建、同一命令、同一台机器,两组之间只翻转第 56 行:
- A 组 = PR head 原样:
await rig.setup('qoder plugin install test'); - B 组 = 变异回修复前:
rig.setup('qoder plugin install test');
| 组 | 轮次 | 结果 |
|---|---|---|
A(有 await) |
10 | 10/10 通过 —— 每轮 Tests 2 passed (2),退出码 0 |
B(无 await) |
10 | 0/10 通过 —— 每轮 Tests 1 failed | 1 passed (2),退出码 1 |
在这台机器上该竞态并非偶发,而是确定性的:未 await 的版本 10 轮全挂,且 vitest 的重试同样全挂(每个失败轮次里同一条报错出现 4~5 次:首次 + retry x2 + 汇总)。
本地复现出的失败特征与 #8766 中报告的完全一致:
× installs a local Qoder plugin 3636ms (retry x2)
→ Process exited with code 1:
Configuration file not found at <testdir>/qoder-plugin-install-test/qwen-extension.json
2. 文件系统层面确认根因(KEEP_OUTPUT=true)
每组各跑一轮并保留输出目录,然后 find 该目录:
| 组 | qoder-plugin-install-test/ 中存活的文件 |
|---|---|
A(有 await),退出码 0 |
.qoder-plugin/plugin.json、.qwen/settings.json、skills/sample-skill/SKILL.md、system-prompt.md |
B(无 await),退出码 1 |
只剩 .qwen/settings.json |
B 组中测试在 setup() 之后立即写入的三个夹具全部消失——被 TestRig.setup() 自身那句仍在 libuv 线程池上执行的 await rm(this.testDir, { recursive: true, force: true })(integration-tests/test-helper.ts:222)删掉了。这直接证明缺陷在于未 await 的 setup,而非 Qoder 转换/安装路径:只要夹具存活,该路径工作正常(A 组能成功安装并在 list 中看到 sample-qoder-plugin)。
3. 覆盖完整性
grep -rn 'rig\.setup(' integration-tests --include='*.ts' → 300 处调用点,0 处未 await(唯一一处非 await 命中是 cli/settings-migration.test.ts:55 的注释)。这一行修复覆盖了整个套件,没有遗漏的同类调用点。
4. ……但本 PR 已经不再改变任何东西
$ gh pr diff 8768 | wc -l
0
$ git diff origin/main pr8768-head -- integration-tests/cli/extensions-install.test.ts | wc -l
0
同样的一词修改已于 2026-08-09 由 #8793(d8c15b3456)合入 main。两个 diff 逐字节相同——都是 index 2d938bc85d..dae6b8a2ec。因此:
- 合并本 PR 只会产生一个空提交,
main的目录树不会有任何变化。 - Main CI failed: E2E Tests — cli/extensions-install.test.ts > installs a local Qoder plugin #8766 已经 CLOSED(
2026-08-09T08:31:58Z),由 fix(tests): await rig setup in Qoder plugin install integration test #8793 关闭。 - 后续的去重 issue Main CI failed: E2E Tests — cli/extensions-install.test.ts > installs a local Qoder plugin #8799 只有一条复现记录,对应提交
ab61d81097dc——它是修复提交的祖先,也就是在 fix(tests): await rig setup in Qoder plugin install integration test #8793 合入之前就已启动的 CI run。此后main上再未复现该失败,最近的mainE2E run(直到 2026-08-11 的0e8a361b37)均为绿。
建议
| 改动正确性 | ✅ 已验证——macOS 上 10/10 vs 0/10 的确定性 A/B,根因在文件系统层面得到证明 |
| 合并价值 | ❌ 为零——相对 main 净 diff 为空;修复已随 #8793 发布 |
| 建议动作 | 以「被 #8793 取代」为由关闭 #8768,无需回滚或后续处理 |
以上没有任何一点是反对这个改动本身的——如果它还没落地,这些证据足以支持直接合并。它只是来晚了一步。
超出范围 / 未验证: Windows E2E 分支;沙箱模式(QWEN_SANDBOX=docker|podman);除该测试驱动的 extensions install|list|uninstall 路径外未涉及其他产品代码。
Evidence images are hosted on branch pr-assets/8768-verify (commit aabb68fe1c) in this repository.




What this PR does
Fixes a flaky-by-construction E2E test by awaiting the test-rig setup before writing fixture files. The
installs a local Qoder plugincase kicked offrig.setup()withoutawait, so the recursive delete that setup performs first raced with — and deleted — the plugin fixtures the test wrote immediately afterwards. The one-word fix (await rig.setup(...)) brings the test in line with every other call site in the integration suite. No product code is changed.Why it's needed
The main-branch E2E run failed on this test right after the Qoder plugin support landed (issue #8766).
TestRig.setup()starts withawait rm(this.testDir, { recursive: true, force: true }); when the call is not awaited, that delete is dispatched to the libuv thread pool while the test body synchronously writes.qoder-plugin/plugin.json,system-prompt.md, and a skill into the same directory. On a loaded CI runner the worker thread stats the directory after the fixtures exist and wipes them, soextensions installfinds no Qoder manifest and exits withConfiguration file not found at …/qwen-extension.json. This reproduced deterministically locally (3/3 attempts failed before the fix), and the kept test directory contained only.qwen/settings.json, proving the fixtures were deleted by the setup race rather than a defect in the Qoder install path — which works correctly once the fixtures survive.Reviewer Test Plan
How to verify
Run the focused integration test against a built bundle and confirm both cases in the file pass consistently:
Expected:
✓ installs a local extension, verifies a command, and updates itand✓ installs a local Qoder plugin. Before this change the second case failed withProcess exited with code 1: Configuration file not found at …/qoder-plugin-install-test/qwen-extension.json; it now passes across 4 consecutive runs. To observe the original race directly, run the pre-fix version withKEEP_OUTPUT=trueand note the kept test directory contains only.qwen/settings.json.Evidence (Before & After)
N/A (test-infrastructure change, no user-visible/TUI behavior affected).
Before:
Tests 1 failed | 1 passed (2)—× installs a local Qoder pluginwithConfiguration file not found at …/qoder-plugin-install-test/qwen-extension.json(initial + both vitest retries).After:
Tests 2 passed (2), stable across 4 consecutive runs.Tested on
Environment (optional)
Node.js 22,
QWEN_SANDBOX=false, bundled CLI (dist/cli.js) vianpm run build && npm run bundle.Risk & Scope
rig.setupcall sites; it cannot change product behavior.Linked Issues
Fixes #8766
中文说明
本 PR 做了什么
通过在执行夹具文件写入之前等待测试 rig 初始化完成,修复了一个构造上必然不稳定的 E2E 测试。
installs a local Qoder plugin用例在未加await的情况下调用了rig.setup(),导致 setup 首先执行的递归删除与该测试随后立即写入的插件夹具发生竞态——并把夹具删掉了。一词之差的修复(await rig.setup(...))使该测试与集成测试套件中所有其他调用点保持一致。未改动任何产品代码。为什么需要
Qoder 插件支持合入后,main 分支的 E2E 运行立即在该测试上失败(issue #8766)。
TestRig.setup()的第一步是await rm(this.testDir, { recursive: true, force: true });当该调用未被 await 时,这个删除操作被派发到 libuv 线程池,而测试主体随即同步地向同一目录写入.qoder-plugin/plugin.json、system-prompt.md和一个技能。在负载较高的 CI runner 上,工作线程会在夹具已存在之后才对该目录执行 stat,从而把它们全部删掉,于是extensions install找不到 Qoder 清单,以Configuration file not found at …/qwen-extension.json退出。该问题在本地可确定性复现(修复前 3/3 次尝试全部失败),且保留的测试目录中只剩.qwen/settings.json,证明夹具是被 setup 竞态删除的,而非 Qoder 安装路径存在缺陷——只要夹具存活,该路径工作完全正常。审阅者测试计划
如何验证
基于构建好的 bundle 运行定向集成测试,确认文件中的两个用例稳定通过:
预期:
✓ installs a local extension, verifies a command, and updates it和✓ installs a local Qoder plugin。在本改动之前,第二个用例会以Process exited with code 1: Configuration file not found at …/qoder-plugin-install-test/qwen-extension.json失败;现在已连续 4 次运行全部通过。如需直接观察原始竞态:运行修复前的版本并设置KEEP_OUTPUT=true,可以看到保留的测试目录中只剩.qwen/settings.json。证据(修复前后)
N/A(测试基础设施改动,无用户可见/TUI 行为变化)。
修复前:
Tests 1 failed | 1 passed (2)——× installs a local Qoder plugin,报错Configuration file not found at …/qoder-plugin-install-test/qwen-extension.json(首次 + vitest 两次重试均失败)。修复后:
Tests 2 passed (2),连续 4 次运行稳定通过。测试环境
环境(可选)
Node.js 22,
QWEN_SANDBOX=false,通过npm run build && npm run bundle构建的 CLI bundle(dist/cli.js)。风险与范围
rig.setup调用点的约定一致;不可能改变产品行为。关联 Issue
Fixes #8766