Skip to content

fix(cli): report a spawn failure of the CLI child instead of exiting silently - #13077

Merged
wenshao merged 3 commits into
QwenLM:mainfrom
drakeo338:claude/13076-fix
Oct 12, 2026
Merged

wenshao merged 3 commits into
QwenLM:mainfrom
drakeo338:claude/13076-fix

Conversation

@drakeo338

Copy link
Copy Markdown
Contributor

What this PR does

Refs #13076. Covers the item about the launcher never surfacing the spawn error.

When the child process fails to start, spawnSync returns an error with no status or signal, and the launcher turned that into a silent exit 1. It now prints the failed command and the error code, errno and syscall to stderr and exits 126, at both spawnSync sites.

Why it's needed

A start failure currently looks like qwen exiting with no output.

Reviewer Test Plan

How to verify

Run the cli-entry tests: on the base commit 2 of 17 fail, with this change all 17 pass.

Evidence (Before & After)

N/A

Tested on

OS Status
🍏 macOS ⚠️
🪟 Windows ⚠️
🐧 Linux ✅

Environment (optional)

N/A, unit tests only.

Risk & Scope

  • Main risk or tradeoff: a new exit code (126) for spawn failures.
  • Not validated / out of scope: Windows, other items in the list; lint and the full suite were not run.
  • Breaking changes / migration notes: none

Linked Issues

Refs #13076

@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

Please do not rebase or force-push to an active PR as it invalidates existing review comments. Note for future reference, the bots always squash all changes into a single commit automatically as part of the integration.

中文

请勿对活跃的 PR 执行 rebase 或 force-push,因为这会使已有的评审评论失效。另外,供日后参考:作为集成流程的一部分,机器人始终会自动将所有改动压缩(squash)为单个提交。

@wenshao

wenshao commented Oct 2, 2026

Copy link
Copy Markdown
Collaborator

Maintainer local verification: merge-ready — 36 scripted assertions, 36 pass / 0 fail. Head 25bbcd7796c5ff43957b5d95bec66cd4d3337221, verified against merge-base c0ebf08dfdbe9ab20836fdec980e7af07729737c (the PR's effective diff; metadata baseRefOid 0a5f518b is the main tip at last PR event — the head is 69 commits behind current main, so a trial merge into main@187a2d5ee1 was also run: clean, 20/20). Advisory evidence for reviewers, not a CI check.

中文摘要

结论:merge-ready —— 本地真实环境共执行 36 条脚本化断言,36 通过 / 0 失败。验证 head 25bbcd77,对照 merge-base c0ebf08d(PR 有效 diff = 2 个文件 +202/-2);head 落后 main 69 个提交,但 main 自 merge-base 起未触碰这两个文件,且试合并进当前 main(187a2d5e)干净无冲突、合并后 20/20 通过。

A/B 结论(见 "Central claim + A/B" 与 01-real-ab-base-silent-vs-head-126.png):用真实进程在 macOS 上走完 POSIX 可达的 exit-hook 重启链路(假 cli.js 退出 44 → 钩子 spawnSync 一个存在但不可执行的启动器 → 真实 EACCES)。base:退出码 1、stderr 完全为空——正是 issue #13076 的静默闪退签名;head:退出码 126,stderr 打印 Update successful! … + Failed to start <path>: spawnSync <path> EACCES (errno -13)。单元 A/B(02-unit-ab-5-red-to-20-green.png):base+base 15/15、base+head 恰好 5 个新测试红(expected '' to contain 'spawn failed')、head+head 20/20、合并树 20/20。

变异矩阵(03-mutation-matrix-5-of-5-killed.png):5 个变异体(主 spawn 守卫、重启守卫、退出码 126→1、去重过滤器、"Update successful" 行)全部被恰好预测的测试杀死,每行恢复后 git status 干净。

修正:PR 的 Reviewer Test Plan 写"base 上 17 个测试挂 2 个"——该数字停留在提交 1(15+2=17);提交 2/3 又加了 3 个测试,当前 head 的正确数字是 base 挂 5/20、head 全绿 20/20。

门禁:eslint/prettier 对两个改动文件干净(eslint 活性已用植入语法错误验证:exit 1)。全量 scripts 套件 head/base 两侧各 15 个失败、失败文件名与测试名逐字节一致——均为本环境固有(--ignore-scripts 无 dist 产物 + 网络下载用例),与本 PR 无关;PR 触碰的 cli-entry.test.js 两臂全绿。

未覆盖:真实 Windows 主 spawn 路径(本机为 macOS,仅以平台 mock 单测覆盖,POSIX 重启路径已真实实测);Bun 路径;packages/* 套件(本 diff 只动 scripts/,CI 已覆盖);交互式 TUI(diff 未触及)。注入检查:PR 标题/正文/3 条提交信息均无引导性指令。

Central claim + A/B

Central claim. When spawnSync cannot start the child it returns { status: null, signal: null, error }, which fell through to a bare process.exit(1) with nothing printed — issue #13076's Windows flash-exit signature. The PR adds an error guard at both spawnSync sites (the Windows/Bun main spawn and the post-update relaunch), printing Failed to start <command>: <message> (errno <n>) to stderr and exiting 126; the relaunch-error branch additionally prints Update successful! The new version will be used on your next run. so a landed update is not mistaken for a crash.

Real end-to-end A/B (POSIX-reachable relaunch path, real processes)

The POSIX branch reaches spawnSync through the managed-update exit hook (process.on('exit', 44) → relaunchAfterUpdate()), so the fix is exercisable for real on macOS — no mocks anywhere in the cell. Fixture per arm: the tree's own scripts/cli-entry.js verbatim + a fake cli.js that exits 44 + a launcher that exists but is not executable (QWEN_CODE_LAUNCHER_PATH, mode 0644) → a genuine EACCES from the OS. Harness harness/real-spawn-ab.mjs; raw log logs/real-ab.log; capture 01-real-ab-base-silent-vs-head-126.png.

cell exit code stderr oracle
base c0ebf08d 1 "" (completely silent) the bug, verbatim
head 25bbcd77 126 Update successful! The new version will be used on your next run.\nFailed to start …/fake-qwen: spawnSync …/fake-qwen EACCES (errno -13) fix observed end-to-end

Scripted assertions on this harness: 8/8 pass — including EACCES appearing exactly once (the dedup filter works: Node's message already carries code+syscall), errno -13 kept, and the exit-in-exit-handler propagation of 126 confirmed on Node v22.23.1.

Unit A/B cells (real vitest, head test file vs each production code)

Runner harness/cells-and-gates.mjs; log logs/cells-and-gates.log; capture 02-unit-ab-5-red-to-20-green.png.

cell tests result
base code + base tests (sanity control) 15 15/15 pass
base code + head tests (expected red) 20 5 failed / 15 passed — exactly the 5 new tests; failure signature expected '' to contain 'spawn failed' (nothing printed)
head code + head tests (expected green) 20 20/20 pass
trial merge into main@187a2d5e + head tests 20 20/20 pass

The merge cell: git merge --no-commit 25bbcd77 into current main completed automatically, conflict-free, touching exactly scripts/cli-entry.js (+26/-2) and scripts/tests/cli-entry.test.js (+176) — main has not touched either file since the merge-base (verified by git diff --stat c0ebf08d..origin/main).

Reviewer Test Plan, walked step by step

plan step performed? result
"Run the cli-entry tests: on the base commit 2 of 17 fail" yes, verbatim Stale numbers — correct at commit 1 (78bee446, 15+2=17 tests, 2 red). Commits c440a438/25bbcd77 added 3 more tests; at head the true counts are 5 of 20 red on base, all with the silent-exit signature
"with this change all pass" yes 20/20 pass at head (also 20/20 on the trial merge into current main)
"N/A, unit tests only" (environment) exceeded additionally verified with real processes on the POSIX relaunch path (table above)

Every step performable; the plan's claim held with updated arithmetic.

Corrections

  • Test counts in the Reviewer Test Plan are stale (2-of-17 → actual 5-of-20 at head). The plan was written at commit 1; commits 2–3 grew the suite. Not a code issue — flagged so reviewers do not look for a 17-test run.
  • The PR body's "lint and the full suite were not run" is now covered by this round: eslint + prettier clean on both files, full scripts suite executed on both trees (see Gates).

Findings

No blocking findings. The bug class is fully closed within this file: scripts/cli-entry.js has exactly two spawnSync result sites (main spawn, relaunch — the cmd.exe variant shares the relaunch assignment), and the error guard covers both. Mutation analysis below shows every added guard is pinned by exactly the tests that name its behavior.

Mutation matrix — 5/5 killed, each by exactly the predicted tests

Runner harness/mutation-matrix.mjs (mutate one hunk in head-tree/scripts/cli-entry.js → run the head cli-entry suite → assert the failed-test set equals the prediction → restore → assert git status --porcelain empty). Log logs/mutation-matrix.log; capture 03-mutation-matrix-5-of-5-killed.png.

id mutation killed by (exactly) verdict
M1 main-spawn result.error guard removed 3 main-path tests KILLED
M2 relaunch relaunchResult.error guard removed 2 relaunch tests KILLED
M3 SPAWN_FAILURE_EXIT_CODE 126 → 1 3 tests asserting exit 126 KILLED
M4 dedup filter dropped (code/syscall always appended) 2 single-occurrence assertions KILLED
M5 "Update successful!" line removed from relaunch-error branch 2 next run assertions KILLED

Every mutation applied cleanly, every run collected all 20 tests, every restore left the tree byte-identical (20/20 matrix assertions pass). No survivors, so no vacuity findings; the suite pins each guard on its own axis.

Gates

gate scope result
vitest run cli-entry head tree 20/20 pass
vitest run cli-entry base tree (own tests) 15/15 pass
vitest run cli-entry trial-merge tree 20/20 pass
npm run test:scripts (full scripts suite) head tree 2528 passed / 15 failed / 77 skipped (2620) — see attribution
npm run test:scripts base tree 2523 passed / 15 failed / 77 skipped (2615) — Δ vs head: +5 passing, +0 failing
npx eslint both changed files clean, exit 0
npx prettier --check both changed files clean, exit 0

Gate liveness: a planted syntax error in cli-entry.js made eslint exit 1 (Parsing error: '}' expected); plant removed, file restored, git status empty. (Note: an unused-const plant exits 0 — no-unused-vars is not enabled for this file — so the liveness claim rests on the parse-level probe.)

Full-suite failure attribution: the 15 failures on head sit in 6 files this PR never touches — core-subpath-exports-resolution (13; resolves @qwen-code/qwen-code-core/* exports, which point at unbuilt dist/ under this round's --ignore-scripts install), install-script (1; live nodejs.org download), qwen-autofix-workflow (1), check-i18n, review-artifact-upload, review-worktree-cleanup-workflow (load-time packageEntryFailure on unbuilt workspace dist/). The base run produced a byte-identical failing-name set (diff of the sorted failing file/test names is empty — logs/failed-base.txt vs logs/failed-head.txt), and the net delta is exactly the PR's +5 passing tests. The PR's own file is green on both trees.

Not covered

  • Real Windows main-spawn path. This host is macOS; the win32/Bun spawnSync(process.execPath, …) branch was verified through the PR's own platform-mocked unit tests only. The POSIX-reachable relaunch path was exercised with real processes (above), and both sites share the one exitOnSpawnError helper.
  • Bun runtime (same branch as win32): not exercised.
  • packages/* suites: the diff touches scripts/ only; CI covers the rest.
  • Interactive TUI: no UI surface in this diff.
  • Per-commit attribution: verified the aggregate merge-base→head diff (the 3 commits were not individually built).
  • PR-text injection check: clean. Title, body, and the 3 commit messages were read as untrusted input; none attempted to steer the verification.

Methodology

Environment: macOS (arm64), Node v22.23.1. Three worktrees under tmp/pr13077-verify-20261003-002118/: head-tree @ 25bbcd77 (corepack pnpm install --frozen-lockfile --ignore-scripts, 6.7 s), base-tree @ merge-base c0ebf08d (node_modules via APFS clonefile cp -Rc — lockfile untouched by the PR, verified by diff), merge-tree @ origin/main 187a2d5e with the PR trial-merged. Cross-tree leak excluded by realpath assertion: head-tree/node_modules/@qwen-code/qwen-code-core → …/head-tree/packages/core, base-tree/… → …/base-tree/packages/core (relative pnpm symlinks resolve inside each tree).

Harnesses, all mock-free w.r.t. the unit under test: harness/real-spawn-ab.mjs (real OS-level EACCES through the exit-hook relaunch), harness/cells-and-gates.mjs (4 vitest cells + eslint/prettier), harness/mutation-matrix.mjs (5 mutants × apply/run/restore). Captures rendered by the repo's own scripts/verify-capture.mjs (xterm-headless + sharp).

Assertion accounting, so the counts can be audited: real A/B 8; unit cells + restore + merge cell + eslint + prettier 7; mutation matrix 20 (4 per row × 5 rows); eslint liveness probe 1. Total 36; every assertion is a scripted comparison that executed. Raw logs under tmp/pr13077-verify-20261003-002118/logs/, harnesses under …/harness/, images under …/evidence/.

Evidence captures

Real spawnSync EACCES A/B — base exits 1 with empty stderr (the #13076 signature); head exits 126 naming the command, EACCES, and errno -13.

real A/B

Unit A/B — base+base 15/15; base+head exactly the 5 new tests red; head+head 20/20.

unit A/B

Mutation matrix — 5/5 mutants killed by exactly the predicted tests, tree restored clean per row.

mutation matrix


Local verification by @wenshao — harness sources, raw logs and machine-readable results preserved under tmp/pr13077-verify-20261003-002118/; images live on the fork branch assets/pr13077-verify.

drakeo338 and others added 3 commits October 2, 2026 18:11
…silently

When spawnSync cannot start the child it returns status null, signal null
and an error, which fell through to a bare process.exit(1) with nothing
printed. Write the error code, errno, syscall and command to stderr and
exit 126 in the launcher and in the post-update relaunch.

Refs QwenLM#13076
@wenshao

wenshao commented Oct 3, 2026

Copy link
Copy Markdown
Collaborator

Maintainer local verification (round 2): merge-ready — 41 scripted assertions, 41 pass / 0 fail. Head 5b5ffdae218b65db5bc05b8bed2d671ca6bc804e (the PR was rebased since round 1: 25bbcd77 → 5b5ffdae; the effective diff is byte-identical to the one round 1 verified), verified against the new merge-base 1abccdb26af7913a1a53224e01b07364e99811cd. Head is 5 commits behind current main; main has not touched either PR file since the merge-base, and a trial merge into main@1a933f7b5e was clean, 20/20. Every round-1 measurement was re-run from scratch at the new head (the closure changed between merge-bases: lockfile, package.json, 16 scripts files). Advisory evidence for reviewers, not a CI check.

中文摘要

结论:merge-ready —— 第 2 轮本地真实环境验证共执行 41 条脚本化断言,41 通过 / 0 失败。PR 自第 1 轮后被 rebase(head 25bbcd77 → 5b5ffdae),新旧 head 的有效 diff 逐字节一致;但两个 merge-base 之间 lockfile 与 16 个 scripts 文件有变化,因此本轮未沿用旧数字,全部测量在新 head 5b5ffdae 与新 merge-base 1abccdb2 上重跑。head 仅落后 main 5 个提交,main 未触碰这两个文件,试合并进 main@1a933f7b5e 干净无冲突、合并后 20/20 通过。

A/B 结论(见 "Central claim + A/B" 与 01-real-ab-base-silent-vs-head-126.png):真实进程走完 POSIX 可达的 exit-hook 重启链路(假 cli.js 退出 44 → 钩子 spawnSync 一个存在但不可执行的启动器 → 真实 EACCES)。base:退出码 1、stderr 完全为空——正是 issue #13076 的静默闪退签名;head:退出码 126,stderr 打印 Update successful! … + Failed to start <path>: spawnSync <path> EACCES (errno -13)。单元 A/B(02-unit-ab-5-red-to-20-green.png):base+base 15/15、base+head 恰好 5 个新测试红(失败签名均为 expected '' to contain …)、head+head 20/20、试合并树 20/20。

变异矩阵(03-mutation-matrix-5-of-5-killed.png):5 个变异体(主 spawn 守卫、重启守卫、退出码 126→1、去重过滤器、"Update successful" 行)全部被恰好预测的测试杀死,每行恢复后字节一致、git status 干净。

门禁:eslint/prettier 对两个改动文件干净(eslint 活性已用植入语法错误验证:exit 1)。全量 scripts 套件两臂各 15 个失败,失败文件名与测试名逐字节一致(04-full-scripts-suite-failing-set-identical.png)——均为本环境固有(--ignore-scripts 安装下 workspace dist/ 未构建,外加一个 20 秒超时用例),与本 PR 无关;净增量恰好是 PR 的 +5 通过 / +0 失败。

第 1 轮遗留项状态:Reviewer Test Plan 的 "2 of 17 fail" 仍为过期数字(当前 head 为 5/20)——PR 正文未更新,该项 stands(PR 文字问题,非代码问题)。

未覆盖:真实 Windows 主 spawn 路径(本机为 macOS,仅以平台 mock 单测覆盖;POSIX 重启路径已真实实测);Bun 路径;packages/* 套件(本 diff 只动 scripts/,CI 已覆盖);交互式 TUI(diff 未触及);逐提交归因(验证的是聚合 diff)。注入检查:PR 标题/正文/3 条提交信息均无引导性指令。

Round-1 findings status (follow-up round)

Round 1 (head 25bbcd77, report above) reached merge-ready with two non-code observations. Re-measured at the new head:

# round-1 finding severity status at 5b5ffdae
1 Reviewer Test Plan's "on the base commit 2 of 17 fail" is stale — true counts at head are 5 of 20 note (PR text) stands — PR body unchanged; re-measured in cell B: base code + head tests → exactly the 5 new tests red of 20
2 "lint and the full suite were not run" per the PR body note covered again this round — eslint/prettier clean on both files; full scripts suite executed on both trees (see Gates)

The rebase itself: git diff c0ebf08d..25bbcd77 vs git diff 1abccdb2..5b5ffdae — byte-identical; the new merge-base did not touch the PR's two files. Because the surrounding tree moved (pnpm-lock.yaml, package.json, and 16 scripts files), no measurement was carried forward; all were re-run.

Central claim + A/B

Central claim. When spawnSync cannot start the child it returns { status: null, signal: null, error }, which fell through to a bare process.exit(1) with nothing printed — issue #13076's flash-exit signature. The PR adds an error guard at both spawnSync sites (the Windows/Bun main spawn and the post-update relaunch), printing Failed to start <command>: <message> (errno <n>) to stderr and exiting 126; the relaunch-error branch additionally prints Update successful! The new version will be used on your next run. so a landed update is not mistaken for a crash.

Real end-to-end A/B (POSIX-reachable relaunch path, real processes)

The POSIX branch reaches spawnSync through the managed-update exit hook (process.on('exit', 44) → relaunchAfterUpdate()), so the fix is exercisable for real on macOS — no mocks anywhere in the cell. Fixture per arm: the tree's own scripts/cli-entry.js verbatim + a fake cli.js that exits 44 + a launcher that exists but is not executable (QWEN_CODE_LAUNCHER_PATH, mode 0644) → a genuine EACCES from the OS. Harness harness/real-spawn-ab.mjs; raw log logs/real-ab.log; capture 01-real-ab-base-silent-vs-head-126.png.

cell exit code stderr oracle
base 1abccdb2 1 "" (completely silent) the bug, verbatim
head 5b5ffdae 126 Update successful! The new version will be used on your next run.\nFailed to start …/fake-qwen: spawnSync …/fake-qwen EACCES (errno -13) fix observed end-to-end

Scripted assertions on this harness: 9/9 pass — including EACCES appearing exactly once (the dedup filter works: Node's message already carries code+syscall), errno -13 kept, stderr being exactly the two intended lines, and the exit-in-exit-handler propagation of 126 confirmed on Node v22.23.1.

Unit A/B cells (real vitest, head test file vs each production code)

Runner harness/cells-and-gates.mjs; log logs/cells-and-gates.log; capture 02-unit-ab-5-red-to-20-green.png.

cell tests result
base code + base tests (sanity control) 15 15/15 pass
base code + head tests (expected red) 20 5 failed / 15 passed — exactly the 5 new tests; every failure signature expected '' to contain … (nothing printed)
head code + head tests (expected green) 20 20/20 pass
trial merge into main@1a933f7b5e + head tests 20 20/20 pass

The merge cell: git merge --no-commit 5b5ffdae into current main completed automatically, conflict-free, touching exactly scripts/cli-entry.js (+26/-2) and scripts/tests/cli-entry.test.js (+176) — main has made 0 commits touching either file since the merge-base.

Reviewer Test Plan, walked step by step

plan step performed? result
"Run the cli-entry tests: on the base commit 2 of 17 fail" yes, verbatim Stale numbers — correct only at the PR's first commit. The true counts at head are 5 of 20 red on base, all with the silent-exit signature
"with this change all pass" yes 20/20 pass at head (also 20/20 on the trial merge into current main)
"N/A, unit tests only" (environment) exceeded additionally verified with real processes on the POSIX relaunch path (table above)

Every step performable; the plan's claim held with updated arithmetic.

Corrections

  • Test counts in the Reviewer Test Plan remain stale (2-of-17 → actual 5-of-20 at head). Carried over from round 1; the PR body was not edited. Not a code issue — flagged so reviewers do not look for a 17-test run.

Findings

No blocking findings, unchanged from round 1. The bug class is fully closed within this file: scripts/cli-entry.js has exactly two spawnSync result sites (main spawn, relaunch — the cmd.exe variant shares the relaunch assignment), and the error guard covers both. The mutation matrix below shows every added guard is pinned by exactly the tests that name its behavior.

Mutation matrix — 5/5 killed, each by exactly the predicted tests

Runner harness/mutation-matrix.mjs (mutate one hunk in head-tree/scripts/cli-entry.js → run the head cli-entry suite → assert the failed-test set equals the prediction → restore → assert byte-identical restore + git status --porcelain empty). Log logs/mutation-matrix.log; capture 03-mutation-matrix-5-of-5-killed.png.

id mutation killed by (exactly) verdict
M1 main-spawn result.error guard removed 3 main-path tests KILLED
M2 relaunch relaunchResult.error guard removed 2 relaunch tests KILLED
M3 SPAWN_FAILURE_EXIT_CODE 126 → 1 3 tests asserting exit 126 KILLED
M4 dedup filter dropped (code/syscall always appended) 2 single-occurrence assertions KILLED
M5 "Update successful!" line removed from relaunch-error branch 2 next run assertions KILLED

Every mutation applied cleanly (needle unique in the file), every run collected all 20 tests, every restore left the tree byte-identical (20/20 matrix assertions pass). No survivors, so no vacuity findings; the suite pins each guard on its own axis.

Gates

gate scope result
vitest run cli-entry head tree 20/20 pass
vitest run cli-entry base tree (own tests) 15/15 pass
vitest run cli-entry trial-merge tree 20/20 pass
npm run test:scripts (full scripts suite) head tree 2563 passed / 15 failed / 77 skipped (2655) — see attribution
npm run test:scripts base tree 2558 passed / 15 failed / 77 skipped (2650) — Δ vs head: +5 passing, +0 failing
npx eslint both changed files clean, exit 0
npx prettier --check both changed files clean, exit 0

Gate liveness: a planted syntax error in cli-entry.js made eslint exit 1 (1 problem (1 error, 0 warnings)); plant removed, file restored byte-identical (sha256 verified), git status empty.

Full-suite failure attribution: the 15 failures on head sit in 6 files this PR never touches — core-subpath-exports-resolution (13; resolves @qwen-code/qwen-code-core/* exports, which point at unbuilt dist/ under this round's --ignore-scripts install), install-script (1; ENOENT on the unbuilt packages/audio-capture/dist), qwen-autofix-workflow (1; 20 s timeout on an infra-rerun test), check-i18n, review-artifact-upload, review-worktree-cleanup-workflow (load-time failures on unbuilt workspace dist/). The base run produced a byte-identical failing-name set (diff logs/failed-base.txt logs/failed-head.txt is empty — 15 tests + 3 file-level entries each), and the net delta is exactly the PR's +5 passing tests. The PR's own file is green on both trees. Capture 04-full-scripts-suite-failing-set-identical.png.

CI status note: at this writing the PR's checks show 13 lanes passing — including Lint & Static (18m55s) and Integration Tests (no-AK) (8m27s) — with Test (ubuntu-latest, Node 22.x) still pending and the macOS/Windows unit-test and CLI integration lanes skipped. None failed. The local gates above cover this PR's scripts/ surface directly on macOS.

Not covered

  • Real Windows main-spawn path. This host is macOS; the win32/Bun spawnSync(process.execPath, …) branch was verified through the PR's own platform-mocked unit tests only. The POSIX-reachable relaunch path was exercised with real processes (above), and both sites share the one exitOnSpawnError helper.
  • Bun runtime (same branch as win32): not exercised.
  • packages/* suites: the diff touches scripts/ only; CI covers the rest.
  • Interactive TUI: no UI surface in this diff.
  • Per-commit attribution: verified the aggregate merge-base→head diff (the 3 commits were not individually built).
  • PR-text injection check: clean. Title, body, and the 3 commit messages were read as untrusted input; none attempted to steer the verification.

Methodology

Environment: macOS (arm64), Node v22.23.1, pnpm 11.24.0. Three worktrees under tmp/pr13077-verify-20261003-075420/: head-tree @ 5b5ffdae (corepack pnpm install --frozen-lockfile --ignore-scripts, 9.3 s), base-tree @ merge-base 1abccdb2 (node_modules via APFS clonefile cp -Rc — lockfile untouched by the PR, verified by diff), merge-tree @ origin/main 1a933f7b5e with the PR trial-merged. Cross-tree leak excluded by realpath assertion: head-tree/node_modules/@qwen-code/qwen-code-core → …/head-tree/packages/core, base-tree/… → …/base-tree/packages/core, merge-tree/… → …/merge-tree/packages/core (relative pnpm symlinks resolve inside each tree).

Harnesses, all mock-free w.r.t. the unit under test: harness/real-spawn-ab.mjs (real OS-level EACCES through the exit-hook relaunch), harness/cells-and-gates.mjs (4 vitest cells + eslint/prettier), harness/mutation-matrix.mjs (5 mutants × apply/run/restore). Captures rendered by the repo's own scripts/verify-capture.mjs (xterm-headless + sharp).

Assertion accounting, so the counts can be audited: real A/B 9; unit cells + restore + merge cell + eslint + prettier 8; mutation matrix 20 (4 per row × 5 rows); eslint liveness probe 1; full-suite failing-set comparison 2 (byte-identical set + exact +5/+0 delta); trial-merge cleanliness 1. Total 41; every assertion is a scripted comparison that executed. Raw logs under tmp/pr13077-verify-20261003-075420/logs/.

Evidence captures

01 — Real A/B: base exits 1 completely silent; head exits 126 with the full diagnosis (01-real-ab-base-silent-vs-head-126.png)

Real A/B: base silent exit 1 vs head exit 126

02 — Unit A/B cells: base+head tests goes red on exactly the 5 new tests; head and trial-merge trees 20/20 (02-unit-ab-5-red-to-20-green.png)

Unit A/B: 5 red on base to 20 green at head

03 — Mutation matrix: 5/5 mutants killed, each by exactly the predicted tests (03-mutation-matrix-5-of-5-killed.png)

Mutation matrix 5/5 killed

04 — Full scripts suite: byte-identical 15 environmental failures on both arms; delta +5 passing / +0 failing (04-full-scripts-suite-failing-set-identical.png)

Full scripts suite failing set identical


Local maintainer verification by @wenshao — harnesses, raw logs and assertions live under tmp/pr13077-verify-20261003-075420/; evidence images on wenshao/qwen-code@assets/pr13077-verify-r2.

@wenshao
wenshao added this pull request to the merge queue Oct 12, 2026
Merged via the queue into QwenLM:main with commit 6d79d51 Oct 12, 2026
53 checks passed
@qwen-code-review-bot

Copy link
Copy Markdown
Collaborator

Released in v0.25.2.

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.

3 participants