Skip to content

test(e2e): pass the harness's 60s initialize budget in qwen-serve-streaming - #11051

Closed
he-yufeng wants to merge 2 commits into
QwenLM:mainfrom
he-yufeng:fix/e2e-streaming-initialize-timeout
Closed

he-yufeng wants to merge 2 commits into
QwenLM:mainfrom
he-yufeng:fix/e2e-streaming-initialize-timeout

Conversation

@he-yufeng

Copy link
Copy Markdown
Contributor

What this PR does

Passes --initialize-timeout-ms 60000 in the qwen-serve-streaming.test.ts daemon spawn, aligning it with the shared daemon harness (integration-tests/cli/_daemon-harness.ts), instead of letting that suite inherit the 10000ms default.

Why it's needed

Two failed main E2E runs (#11034, #11043) show the same signature on different commits: AcpSessionBridge initialize timed out after ~10s in this suite's daemon restart/reload tests. Green runs interleave with the failures on the same day, so this is shared macOS runner slowness tripping the 10s budget, not a product regression. The streaming suite is the only serve E2E file that spawns its daemon manually without the harness's larger budget. Test-side only; the product default is unchanged.

Reviewer Test Plan

How to verify

Confirm the argument list change in integration-tests/cli/qwen-serve-streaming.test.ts and that _daemon-harness.ts:121 already passes the same value. Expected: the suite no longer fails with 10s AcpSessionBridge initialize timed out on loaded macOS runners; behavior of the tests themselves is unchanged.

Evidence (Before & After)

N/A (test infrastructure only)

Tested on

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

Environment (optional)

Local vitest run of integration-tests/cli/qwen-serve-streaming.test.ts on macOS arm64 against a full build.

Risk & Scope

  • Main risk or tradeoff: a genuinely hung bridge now takes 60s instead of 10s to fail in this suite; no product behavior is affected.
  • Not validated / out of scope: whether the daemon should adapt the budget itself; Windows/Linux local runs (CI covers them).
  • Breaking changes / migration notes: none.

Linked Issues

Fixes #11043

中文说明

本 PR 做了什么

qwen-serve-streaming.test.ts 的 daemon 启动参数中传入 --initialize-timeout-ms 60000,与共享 daemon harness(integration-tests/cli/_daemon-harness.ts)保持一致,不再让该测试套件继承默认的 10000ms。

为什么需要

main 分支两次失败的 E2E 运行(#11034#11043)在不同提交上呈现相同签名:本套件中重启/重连 daemon 的测试报 AcpSessionBridge initialize timed out after ~10s。同一天内绿色运行与失败交替出现,说明这是共享 macOS runner 变慢触发了 10s 预算,而非产品回归。该套件是唯一手动启动 daemon 且未使用 harness 大预算的 serve E2E 文件。仅改动测试侧,产品默认值不变。

评审验证计划

如何验证

查看 integration-tests/cli/qwen-serve-streaming.test.ts 的参数变更,并确认 _daemon-harness.ts:121 已传入相同数值。预期:在繁忙的 macOS runner 上本套件不再因 10s 初始化超时而失败;测试本身行为不变。

证据(前后对比)

N/A(仅测试基础设施)

测试平台

macOS 已测,Windows/Linux 未本地测(由 CI 覆盖)。

环境(可选)

在 macOS arm64 上对完整构建本地运行了 integration-tests/cli/qwen-serve-streaming.test.ts

风险与范围

  • 主要风险或取舍:真正挂死的 bridge 在本套件中需要 60s 而非 10s 才报错;不影响产品行为。
  • 未验证 / 超出范围:daemon 是否应自适应预算;Windows/Linux 本地运行。
  • 破坏性变更 / 迁移说明:无。

关联 Issue

Fixes #11043

…eaming

The serve streaming suite spawns its daemon manually and inherited the
10s initialize-timeout-ms default, which trips on loaded macOS CI
runners when these tests restart or re-attach a daemon child. Two
failed main runs (QwenLM#11034, QwenLM#11043) show the same signature:
AcpSessionBridge initialize timed out after ~10s on exactly the
restart/reload tests, while green runs interleave on the same day, so
this is runner slowness rather than a regression. The shared daemon
harness already passes 60000; align this spawn with it. Test-side
only, the product default is unchanged.

Signed-off-by: Yufeng He <40085740+he-yufeng@users.noreply.github.com>
@qwen-code-ci-bot

qwen-code-ci-bot commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Qwen Triage finishedview run. See the stage comments in this thread for the result.

Qwen Triage 已完成 —— 查看运行。结果见本线程中的各阶段评论。

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR — and for the diagnosis write-up on #11043, which made this easy to check rather than take on trust.

Template looks good ✓ — every required heading is present, and Risk & Scope volunteers the 60s-vs-10s tradeoff before a reviewer has to go looking for it.

Problem — observed, and I verified it against the real logs. #11043's E2E Test - macOS - shard 1/2 (job 101141350110) failed with DaemonHttpError: POST /session: AcpSessionBridge initialize timed out after 9996ms at qwen-serve-streaming.test.ts:519, in qwen serve — pollable turn results > reads a settled result after a normal Session reload; the retries died the same way at 9997ms and 9992ms. #11034's job (101094429327) shows the same signature at 9976ms and 9997ms. Every one lands a few milliseconds under the 10s ceiling, which is the slow-but-alive-child shape you describe, not a hang. One test failed of 235 in that run — a narrow flake, consistent with your read.

Direction — aligned. Test-side only, the production 10s default stays put, and 60s isn't a number you invented: _daemon-harness.ts:121 already passes exactly this, and qwen-serve-routes.test.ts:161 passes it too. Bringing a suite that bypasses the harness in line with the harness's own budget is the least surprising thing to do here.

Size — not applicable. One file, +5/-0, no core paths touched.

Approach — the change itself is minimal and I'd write it the same way. Two scope points to raise before the code review, both about reach rather than the diff:

  1. The description says this suite is "the only serve E2E file that spawns its daemon manually without the harness's larger budget." That doesn't hold in-tree. grep -rln -- "--initialize-timeout-ms" integration-tests/ returns only _daemon-harness.ts and qwen-serve-routes.test.ts, while qwen-serve-channel-workers.test.ts spawns manually four times (lines 281, 461, 589, 718) and qwen-serve-client-mcp.test.ts once (line 114), neither passing the flag. Those two suites are still on the 10s budget and can redden main with the same signature. Worth correcting the sentence either way — as written it tells a reviewer the flake class is closed when it isn't.

  2. fix(test): raise the ACP initialize budget for inline E2E daemon spawns (#11034) #11041 is open and unmerged, and it patches this same file at this same insertion point with the same flag and value ('--initialize-timeout-ms', String(ACP_INITIALIZE_TIMEOUT_MS) right after '--workspace', workspaceDir,) — plus the two suites above. The hunks are substantively identical, so whichever PR merges second will conflict. fix(test): raise the ACP initialize budget for inline E2E daemon spawns (#11034) #11041 also carries ~864 lines of formatter churn in qwen-serve-client-mcp.test.ts, and its Qwen Code CI run was cancelled, so it's neither green nor approved either. I can't pick a winner between the two from a diff — that's a maintainer call, and I've carried it into the final decision rather than guessing here.

Risk — no elevated risk signals. Stage 1e's high-risk path list doesn't match; the only changed file is a .test.ts.

Flagging those two for discussion and moving on to code review, since the diff is verifiable on its own merits. 🔍

中文说明

感谢贡献,也感谢你在 #11043 上写的诊断 —— 它让核对成为可能,而不必只凭描述相信。

模板完整 ✓ —— 所有必需标题齐全,Risk & Scope 也主动说明了 60s vs 10s 的取舍,不用评审者自己去翻。

问题 —— 已观测,而且我对照真实日志核实过。#11043E2E Test - macOS - shard 1/2(job 101141350110)失败于 DaemonHttpError: POST /session: AcpSessionBridge initialize timed out after 9996ms,位置 qwen-serve-streaming.test.ts:519,用例是 qwen serve — pollable turn results > reads a settled result after a normal Session reload;重试分别以 9997ms、9992ms 同样失败。#11034 的 job(101094429327)呈现相同签名,为 9976ms 与 9997ms。每一个都刚好卡在 10s 上限之下几毫秒,正是你说的"进程慢但存活"形态,不是挂死。该次运行 235 个用例中仅 1 个失败 —— 窄范围 flake,与你的判断一致。

方向 —— 对齐。仅改测试侧,生产环境 10s 默认值保持不变,而且 60s 不是你自创的数字:_daemon-harness.ts:121 已经传入完全相同的值,qwen-serve-routes.test.ts:161 也传了。让绕过 harness 的套件与 harness 自身预算对齐,是这里最不意外的做法。

规模 —— 不适用。单文件,+5/-0,未触及核心路径。

方案 —— 改动本身已是最小化,我也会这么写。有两点范围问题想在代码审查前提出,都关乎覆盖面而非 diff:

  1. 描述中说本套件是"唯一手动启动 daemon 且未使用 harness 大预算的 serve E2E 文件"。这在代码树中不成立。grep -rln -- "--initialize-timeout-ms" integration-tests/ 只返回 _daemon-harness.tsqwen-serve-routes.test.ts;而 qwen-serve-channel-workers.test.ts 手动启动了四次(281、461、589、718 行),qwen-serve-client-mcp.test.ts 启动一次(114 行),两者都没传该参数。这两个套件仍在 10s 预算下,可能以相同签名再次让 main 变红。无论如何建议修正这句话 —— 按现在的写法,会让评审者以为这类 flake 已经收敛,实际并没有。

  2. fix(test): raise the ACP initialize budget for inline E2E daemon spawns (#11034) #11041 处于 open 未合并状态,它在本文件同一插入点打了同样的参数与数值(在 '--workspace', workspaceDir, 之后加 '--initialize-timeout-ms', String(ACP_INITIALIZE_TIMEOUT_MS)),并额外覆盖了上面两个套件。两处 hunk 实质相同,因此后合并的 PR 必然冲突。fix(test): raise the ACP initialize budget for inline E2E daemon spawns (#11034) #11041 还在 qwen-serve-client-mcp.test.ts 中夹带约 864 行格式化改动,且其 Qwen Code CI 运行被取消,所以它既非绿色也未获批。我无法从 diff 判断两个 PR 该留哪个 —— 这是维护者的决定,我已把它带入最终结论,而不是在此处猜测。

风险 —— 无升级风险信号。Stage 1e 的高风险路径清单未命中;唯一改动文件是 .test.ts

以上两点先提出来讨论;代码审查继续进行,因为 diff 本身可以独立验证。🔍

Qwen Code · qwen3.8-max-2026-09-02

Reviewed at 9357c99168fe4aac1feb6c2cbeb6da87d73c98e7 · re-run with @qwen-code /triage

@qwen-code-ci-bot

qwen-code-ci-bot commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

Code review

I wrote down what I'd do before opening the diff: the root cause is that inline qwen serve spawns drift from the shared harness's budget, so find every default-suite test that starts the daemon itself instead of going through spawnDaemon() and pass the harness's 60s value — leaving the production default alone, and leaving the benchmark suites alone since they don't create sessions. Then sweep all of them in one pass, because a gap that drifted twice will drift a third time if only one file gets patched.

The first half is exactly what this PR does. The second half — the sweep — is what it doesn't do, and the description asserts the sweep is unnecessary. That's the one place I'd push back; the grep and line numbers are in the Stage 1 comment, so I won't repeat the case here.

On the diff itself, every load-bearing claim checked out:

  • --initialize-timeout-ms is a real declared qwen serve option (packages/cli/src/commands/serve.ts:589, type: 'number'), threaded through serve.ts:906-907 into initializeTimeoutMs and consumed at packages/acp-bridge/src/bridge.ts:2882.
  • The default it replaces really is 10s: DEFAULT_INIT_TIMEOUT_MS = 10_000 at bridge.ts:2587.
  • _daemon-harness.ts:121 passes '--initialize-timeout-ms', '60000' — the exact line the Test Plan points a reviewer at.
  • No side effect on the session-restore budget. This is what I most expected to bite, since --session-restore-timeout-ms's own help text warns that an explicit --initialize-timeout-ms can raise it. resolveSessionRestoreTimeoutMs returns Math.max(initializeTimeoutMs, DEFAULT_SESSION_RESTORE_TIMEOUT_MS) and DEFAULT_SESSION_RESTORE_TIMEOUT_MS = 60_000, so max(60000, 60000) leaves the restore deadline exactly where it was. A larger value would have widened it; 60000 does not.
  • Insertion point and argv form are right: string literals appended after '--workspace', workspaceDir, inside the args array, matching both the harness and qwen-serve-routes.test.ts.
  • The comment explains why rather than what, and cites the issue — consistent with AGENTS.md.

One stylistic note, not a finding: qwen-serve-routes.test.ts and #11041 both spell this as a named ACP_INITIALIZE_TIMEOUT_MS = 60_000 const passed through String(...) rather than an inline '60000'. Both styles exist in-tree and this PR follows the harness's, which is the one it cites, so I wouldn't change it on its own merits — but if #11041 lands first this file ends up carrying both spellings.

No correctness bugs, no security concerns, no regressions. Test-side only, so the product surface is untouched.

CI test evidence

This run carried no local testing — the review is static and I did not build or run any PR-derived code. The evidence below is the PR's own CI, fetched once through the API for 9357c99.

Final CI results for 9357c99 (auto-updated by the triage finalize job after CI completed):

Check Conclusion
Test (ubuntu-latest, Node 22.x) ❌ failure
Classify PR ✅ success
Dependency CVE audit ✅ success
Desktop Shell (ubuntu-22.04) ✅ success
Desktop Shell (windows-2022) ✅ success
Integration Tests (no-AK, No Sandbox) ✅ success
Lint & Static (ubuntu-latest, Node 22.x) ✅ success
Secret scan (TruffleHog) ✅ 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,失败项排在最前。

Nothing red. The Security Checks workflow run completed green. Three lanes were still running when I fetched — Qwen Code CI is the single pending pull_request workflow run — and I did not poll or sleep-wait for them.

The part that matters is what's skipped: Test (macos-latest, Node 22.x) and Integration Tests (CLI, No Sandbox). macOS is where the failure lives — both runs I read were on /Users/runner/... — and the CLI integration lane is where qwen-serve-streaming.test.ts actually executes. So this PR's CI never runs the suite it changes, on the platform it changes it for. A green board here is not evidence the flake is fixed, and I haven't treated it as such.

not verified: that the suite stops failing on a loaded macOS runner. It can't be verified from this PR — the lane that would come closest is skipped on forks, and a statistical flake (main already interleaves green and red runs of the same lane) isn't settled by any single run in either direction.

Sandboxed verification would partly settle this: @qwen-code /verify — a sponsored run, since the author has read-only access; a maintainer's @qwen-code /verify comment approves the head it was written against, and that run carries a pre-execution risk screen plus a full workspace wipe before any of the PR's code executes. Read the resulting report with the same skepticism as the fork's own CI logs: the code under verification is adversarial input, and a crafted PR can shape what the report says even though the sandbox bounds what it can do. Honest caveat on what it would and wouldn't buy — /verify can substantiate the mechanical claim (the daemon really boots with a 60s budget and the suite still passes against it), but it runs on Linux and cannot reproduce a loaded macOS runner, so it would not settle "the flake is gone." Only watching main's macOS E2E lane after merge does that. @qwen-code /tmux is unavailable here — it executes the author's code and gates on the author.

中文说明

代码审查 —— 我在打开 diff 前先写下了自己的方案:根因是内联的 qwen serve 启动与共享 harness 的预算脱节,所以应找出所有自行启动 daemon、未走 spawnDaemon() 的默认套件,统一传入 harness 的 60s 值,不动生产默认值,也不动 benchmark 套件(它们不创建 session);然后一次性扫完全部这类文件,因为脱节过两次的缺口,只补一个文件就会脱节第三次。

前半部分与本 PR 完全一致。后半部分(全量扫描)本 PR 没有做,而描述断言无需扫描 —— 这是我唯一想反驳的地方;grep 结果与行号已在 Stage 1 评论中,此处不再重复论证。

diff 本身,所有关键论断都核对通过:

  • --initialize-timeout-msqwen serve 真实声明的选项(packages/cli/src/commands/serve.ts:589type: 'number'),经 serve.ts:906-907 传入 initializeTimeoutMs,最终在 packages/acp-bridge/src/bridge.ts:2882 被消费。
  • 它替换掉的默认值确实是 10s:bridge.ts:2587DEFAULT_INIT_TIMEOUT_MS = 10_000
  • _daemon-harness.ts:121 传入 '--initialize-timeout-ms', '60000' —— 正是 Test Plan 让评审者去核对的那一行。
  • 对 session-restore 预算无副作用。 这是我最担心会出问题的地方,因为 --session-restore-timeout-ms 自己的帮助文本就警告显式的 --initialize-timeout-ms 会抬高它。resolveSessionRestoreTimeoutMs 返回 Math.max(initializeTimeoutMs, DEFAULT_SESSION_RESTORE_TIMEOUT_MS),而 DEFAULT_SESSION_RESTORE_TIMEOUT_MS = 60_000 —— 因此 max(60000, 60000) 让 restore 截止时间保持原样。更大的值会拓宽它,60000 不会。
  • 插入位置与 argv 形式正确:以字符串字面量追加在 args 数组中 '--workspace', workspaceDir, 之后,与 harness 及 qwen-serve-routes.test.ts 一致。
  • 注释解释的是"为什么"而非"做了什么",并引用了 issue —— 符合 AGENTS.md。

一点风格说明,不构成 finding:qwen-serve-routes.test.ts#11041 都写成具名常量 ACP_INITIALIZE_TIMEOUT_MS = 60_000 再经 String(...) 传入,而非内联 '60000'。两种写法在代码树中都存在,本 PR 跟随的是它所引用的 harness 写法,所以单看这一点我不会要求改 —— 但若 #11041 先合并,这个文件会同时留下两种写法。

无正确性缺陷、无安全隐患、无回归。仅测试侧改动,产品接口未受影响。

CI 测试证据 —— 本次运行没有本地测试 —— 审查是静态的,我没有构建或运行任何 PR 派生代码。上表证据来自 PR 自身的 CI,通过 API 对 9357c99 一次性获取。

无红色项。Security Checks workflow 已绿色完成。获取时有三条 lane 仍在运行 —— Qwen Code CI 是唯一 pending 的 pull_request workflow run —— 我没有轮询或 sleep 等待。

关键在于被跳过的部分:Test (macos-latest, Node 22.x)Integration Tests (CLI, No Sandbox)。macOS 正是失败发生的平台 —— 我读到的两次运行都在 /Users/runner/... 上 —— 而 CLI integration lane 正是 qwen-serve-streaming.test.ts 实际执行的地方。所以本 PR 的 CI 从未在它要修改的平台上运行它要修改的套件。这里的绿色并不代表 flake 已修复,我也没有把它当作证据。

未验证:在繁忙的 macOS runner 上该套件是否不再失败。这一点无法从本 PR 验证 —— 最接近的那条 lane 在 fork 上被跳过,而统计性 flake(main 上同一 lane 的绿色与红色运行本就交替出现)不会被任何单次运行判定,无论哪个方向。

沙箱验证可部分解决:@qwen-code /verify —— 因作者只有只读权限,这是一次 sponsored run:维护者的 @qwen-code /verify 评论会批准其所针对的 head,该运行在 PR 代码执行前带有执行前风险筛查与完整工作区擦除。阅读报告时请保持与阅读 fork 自身 CI 日志同等的怀疑:被验证的代码是对抗性输入,精心构造的 PR 可以影响报告"说什么",尽管沙箱限定了它"能做什么"。关于其价值的诚实说明 —— /verify 能证实机械性论断(daemon 确实以 60s 预算启动且套件仍通过),但它运行在 Linux 上,无法复现繁忙的 macOS runner,因此不能判定"flake 已消失"。只有合并后观察 main 的 macOS E2E lane 才能。@qwen-code /tmux 在此不可用 —— 它会执行作者代码并以作者权限为门槛。

Qwen Code · qwen3.8-max-2026-09-02

Reviewed at 9357c99168fe4aac1feb6c2cbeb6da87d73c98e7 · re-run with @qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Confidence: 3/5 — the five lines are correct and I verified every load-bearing claim behind them, but two questions I can't answer from the diff decide whether this is the PR that should land.

Stepping back. The change is right. I confirmed the flag exists and is wired end to end, that the default it replaces really is 10s, that the harness line the Test Plan points at says what it says, and — the part I expected to bite — that 60000 leaves the session-restore deadline untouched, because resolveSessionRestoreTimeoutMs takes Math.max(60000, 60000). I read the failure logs for both cited runs and the signature is exactly as advertised: AcpSessionBridge initialize timed out after 9996ms, at qwen-serve-streaming.test.ts:519, in the reload test, on a macOS runner, every retry landing a few milliseconds under the ceiling. That is a slow-but-alive child, not a hang, and raising the budget to the value the harness already uses is the least surprising fix available. If this were the only PR open, I'd be writing 4/5 and deferring the approval to CI.

It isn't the only PR open, and that's the first question. #11041 patches this same file at this same insertion point with the same flag and value, and additionally covers qwen-serve-channel-workers.test.ts and qwen-serve-client-mcp.test.ts. Two open PRs carrying a substantively identical hunk cannot both merge cleanly — the second one conflicts. #11041 is the more complete fix and the messier one: 24 lines of real change plus ~864 lines of formatter churn in a file that didn't need reformatting, CI cancelled, no approval. This one is five clean lines that leave two suites exposed. Choosing between "complete but noisy" and "clean but partial" is a call about what this repo wants to carry, and it isn't mine to make from a diff.

The second question sits underneath it. The description's scoping claim — that this is the only serve E2E file spawning its daemon manually without the harness budget — is false in-tree, and it's load-bearing: it's the stated reason the PR stops at one file. I'd rather the author correct that sentence than have a maintainer approve believing the flake class is closed, because channel-workers and client-mcp can redden main with the same signature next week and #11043's shape repeats.

So I'm neither approving nor requesting changes. The diff doesn't deserve request-changes — nothing in it is wrong, and the author diagnosed this independently and honestly, volunteering the 60s tradeoff unprompted. But adding the bot's approval would mean voting to ship one of two conflicting fixes before a human has chosen between them, on a PR whose own CI skips both the platform and the suite at issue.

⏸️ Deferring to a maintainer. Two things need a human call: (1) which of #11051 and #11041 should land, given the identical hunk in qwen-serve-streaming.test.ts — and if the answer is this one, whether the remaining two suites get a follow-up PR or fold in here; (2) whether the "only serve E2E file" line should be corrected before merge. I could not resolve an owner deterministically to @mention: this PR carries no labels, so the area map in .github/issue-owners.json matched nothing, there's no prior human reviewer on it to fall back to, and QWEN_MAINTAINER_HANDLE isn't set — so this comment is the escalation rather than a mention, and the PR is left unassigned rather than guessed at. Whoever picks it up: the diff is safe, the evidence is real, and the open question is scope and merge ordering, not correctness.

中文说明

Confidence: 3/5 —— 这 5 行代码是正确的,其背后每一个关键论断我都核实过;但有两个我无法从 diff 回答的问题,决定了该合并的是不是这个 PR。

退一步看。改动本身是对的。我确认了该参数存在且端到端接通、它替换的默认值确实是 10s、Test Plan 指向的 harness 那一行确实如描述所写;也确认了我原以为最可能出问题的一点 —— 60000 不会改变 session-restore 截止时间,因为 resolveSessionRestoreTimeoutMsMath.max(60000, 60000)。我读了所引用两次运行的失败日志,签名与所说完全一致:AcpSessionBridge initialize timed out after 9996ms,位于 qwen-serve-streaming.test.ts:519 的 reload 用例,macOS runner 上,每次重试都刚好卡在 10s 上限之下几毫秒。这是"进程慢但存活",不是挂死;把预算抬到 harness 已在使用的值,是可用的最不意外的修法。如果只有这一个 PR 开着,我会写 4/5 并把审批延后到 CI。

但它不是唯一开着的 PR,这是第一个问题。#11041 在同一文件、同一插入点打了同样的参数与数值,并额外覆盖了 qwen-serve-channel-workers.test.tsqwen-serve-client-mcp.test.ts。两个都开着的 PR 携带实质相同的 hunk,无法都干净合并 —— 后合并的必然冲突。#11041 是更完整但更脏的修法:24 行真实改动,外加约 864 行本不必重排的格式化改动,CI 被取消,且无批准。本 PR 是干净的 5 行,但留下两个套件仍暴露。在"完整但嘈杂"与"干净但局部"之间做选择,是关于本仓库愿意承载什么的判断,不该由我从 diff 里做。

第二个问题在它底下。描述中的范围论断 —— 本文件是唯一手动启动 daemon 且未使用 harness 预算的 serve E2E 文件 —— 在代码树中不成立,而且它是承重的:它正是本 PR 止步于单个文件所说的理由。我更希望作者修正这句话,而不是让维护者在以为这类 flake 已收敛的情况下批准 —— 因为 channel-workersclient-mcp 下周仍可能以相同签名让 main 变红,#11043 的形态会重演。

所以我既不批准,也不请求修改。这段 diff 不值得 request-changes —— 其中没有错的东西,作者是独立且诚实地完成诊断的,还主动说明了 60s 的取舍。但加上机器人的批准,就等于在人类尚未在两个互相冲突的修法之间做出选择前,为其中之一投票支持;而这个 PR 自己的 CI 恰好跳过了涉事平台与涉事套件。

⏸️ 转交维护者处理。 两件事需要人来定:(1)鉴于 qwen-serve-streaming.test.ts 中的相同 hunk,#11051#11041 该合并哪一个 —— 若答案是本 PR,剩余两个套件是走后续 PR 还是并入此处;(2)合并前是否应修正"唯一 serve E2E 文件"这句。我无法确定性地解析出可 @ 的负责人:本 PR 没有任何 label,因此 .github/issue-owners.json 的区域映射未命中,其上也没有先前的真人评审者可回退,QWEN_MAINTAINER_HANDLE 也未设置 —— 所以这条评论本身就是升级,而非一次 mention;PR 保持未指派,而不是靠猜测指派。接手的人请注意:diff 是安全的,证据是真实的,未决问题在于范围与合并顺序,而非正确性。

Qwen Code · qwen3.8-max-2026-09-02

Reviewed at 9357c99168fe4aac1feb6c2cbeb6da87d73c98e7 · re-run with @qwen-code /triage

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

⚠️ Downgraded from Approve to Comment: CI failing: Test (ubuntu-latest, Node 22.x). Partially reviewed — gaps disclosed.

Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.

中文说明

⚠️ 已从批准降级为评论:CI failing: Test (ubuntu-latest, Node 22.x)。 仅完成部分审查,审查缺口已披露。

未审查(原文为英文):build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.

— qwen3.8-max via Qwen Code /review (v0.23.0)

@qqqys qqqys left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

COMMENT — the change is fully superseded by merged #11041 and now conflicts with main.

  • Head 9357c991 is based on the pre-#11041 blob of integration-tests/cli/qwen-serve-streaming.test.ts. #11041 merged at 2026-09-05T01:14:44Z and brought the exact same fix to this file, in a better-supported form: a shared ACP_INITIALIZE_TIMEOUT_MS = 60_000 constant (main line 80) and the same --initialize-timeout-ms spawn pair at the identical site (main lines 358-359). Verified against main's current file content.
  • Consequently GitHub reports mergeable: CONFLICTING — the two edits collide in the same region — and a conflict-resolved version of this PR would contain zero delta against main (it may even reintroduce a redundant inline '60000' literal beside the constant #11041 established).
  • #11041 also covered the sibling suites (qwen-serve-channel-workers, qwen-serve-client-mcp) with the same budget, so this PR's whole scope is contained.

Suggested next step: close this PR as superseded by #11041. Nothing to salvage — if #11043's macOS restart path needs anything beyond what #11041 shipped, a fresh issue against the merged state would be the cleaner carrier.

For completeness: the lone red on this head is Test (ubuntu-latest), whose unit-suite scope never executes the only file this PR touches (integration-tests run in dedicated lanes, all green/skipped here); the failure matches the main-side reds seen across other PR heads this week and is not attributed to this change.

@wenshao

wenshao commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /resolve

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

Qwen Code resolved the merge conflicts and pushed the branch update.

Merge summary — PR #11051 ← origin/main

Root cause

Main merged b0a463c (fix(test): give inline E2E daemon spawns the CI ACP initialize budget, #11034/#11041), which makes the identical change this PR proposes: it adds --initialize-timeout-ms with a 60s budget to the same inline daemon spawn in integration-tests/cli/qwen-serve-streaming.test.ts. Both changes trace to the same macOS-CI AcpSessionBridge initialize timed out flake (#11030/#11033/#11034/#11043), so the two branches collided in one spawn-args array.

Textual or semantic

Semantic — both sides modify the same logic (the same spawn argument list), not merely adjacent lines. Taking both sides would pass --initialize-timeout-ms twice. Resolution keeps main's constant-based form, which subsumes the PR's intent (60000 == 60_000):

// top of file (auto-merged from main)
const ACP_INITIALIZE_TIMEOUT_MS = 60_000;

// beforeAll spawn args (resolved conflict)
      '--workspace',
      workspaceDir,
      '--initialize-timeout-ms',
      String(ACP_INITIALIZE_TIMEOUT_MS),
    ],

The PR's inline rationale comment was dropped, not lost: main's comment on the constant carries the same reasoning (10s default is a desktop budget; match qwen-serve-routes.test.ts), and the fuller history lives in b0a463c's commit message.

What is load-bearing

  • The spawn at beforeAll is the only spawn( site in this file; exactly one --initialize-timeout-ms pair belongs to it. A future edit re-adding the PR's literal '60000' pair would duplicate the flag.
  • The value must stay sourced from ACP_INITIALIZE_TIMEOUT_MS so this suite tracks the shared budget convention from fix(test): raise the ACP initialize budget for inline E2E daemon spawns (#11034) #11041; hardcoding a divergent number breaks that linkage.

What I could not verify

No build/tests run (per instructions). Net effect: the PR's entire 5-line diff is absorbed, so the merged tree is byte-identical to origin/main (git diff origin/main empty) — the PR now carries no unique content. Non-conflicted suites touched by main in the same commit (qwen-serve-channel-workers.test.ts, qwen-serve-client-mcp.test.ts) gained their own budget flags independently and are unaffected by this resolution. The only file edited was the conflicted one.

中文说明

根因:main 合入了 b0a463c#11034/#11041),它对同一文件 qwen-serve-streaming.test.ts 的同一个 daemon spawn 做了与本 PR 完全相同的修改——给内联启动加上 60 秒的 --initialize-timeout-ms,两者源于同一个 macOS CI 上 AcpSessionBridge initialize 超时(10 秒默认值)的 flake。

语义冲突:双方改的是同一段逻辑(同一处启动参数),若两边都保留会重复传参。解决方式采用 main 的常量写法(String(ACP_INITIALIZE_TIMEOUT_MS),常量值为 60_000),完全覆盖本 PR 的意图;PR 的内联注释被舍弃,因为 main 在常量声明处的注释已含同样的理由。

关键点:该文件只有一处 spawn,只能保留一组 --initialize-timeout-ms;数值必须继续引用常量,以跟随 #11041 的统一预算约定。

未验证项:按指令未运行构建或测试。由于 PR 的全部 5 行改动均被 main 吸收,合并后的树与 origin/main 完全一致(diff 为空),本 PR 不再携带独有内容。仅修改了发生冲突的文件;同一 main 提交中改动的其他测试套件不受本次解决影响。

@wenshao

wenshao commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

Local verification — real daemon, real qwen --acp child, deterministic flake reproduction

I built the verification environment locally instead of reading the diff, because the interesting question here is not whether five lines are typed correctly — it is whether the budget they set is actually load-bearing, and whether this PR still has anything to contribute after @qwen-code /resolve merged main into it.

Verdict: the change is correct and is already on main. This PR now carries zero content — I recommend closing it as superseded rather than merging it, and closing #11043 at the same time, which is still open and which nothing else references.

Environment: Debian 13, Linux 6.12.63 x86_64, 16 cores, Node v22.22.2, vitest 3.2.7. Full build from source (npm run build -- --cli-only && npm run bundle) at origin/main c39e83e; PR head 38103fc.


1. The PR no longer carries any content

git diff origin/main...38103fc535 is empty. Stronger than that: the PR head's tree (7c83a94a) is identical to the tree of the merge base e3d26283, and e3d26283 is already an ancestor of origin/main. The blob of the only file the PR ever touched is byte-identical on both sides (c730ea79), and b0a463c (#11041) is already an ancestor of the PR head.

zero diff

Merging this would append two commits to main that change nothing. Closing it costs nothing and loses nothing.

2. The budget is load-bearing — verified on the wire, not by reading

To reproduce the CI condition deterministically I put a shim between the daemon and its ACP child (QWEN_CLI_ENTRY → shim → real qwen --acp). The shim proxies the NDJSON JSON-RPC stream verbatim in both directions and changes exactly one thing: the arrival time of the initialize response. That is precisely what a loaded shared runner does, with none of the nondeterminism.

Same bundle, same real child, same 20 s injected delay, one variable:

daemon A/B

  • Without the flag: 504, {"error":"AcpSessionBridge initialize timed out after 9991ms","code":"init_timeout","phase":"channel.initialize"} — the same error class, same phase, same ~10 s budget as Main CI failed: E2E Tests on 74fe3a659dde #11043's 9996ms at qwen-serve-streaming.test.ts:519.
  • With --initialize-timeout-ms 60000: 200, session created after 21272 ms — the delay is absorbed.

3. Suite-level A/B, with a negative control

I ran the real suite three times against the built bundle:

run spawn args injected delay result
baseline as on main none 11/11 pass, 12.94 s
arm 1 as on main (flag present) 12 s 11/11 pass, 97.05 s
arm 2 flag surgically removed (pre-#11041 args) 12 s 11/11 fail

suite A/B

Every arm-2 failure is DaemonHttpError: POST /session: AcpSessionBridge initialize timed out after ~9.99s. The negative control is what makes this meaningful: the suite is green under the delay because of these two lines, not merely alongside them.

4. No collateral damage on the restore budget

The one thing worth checking about raising an initialize budget is whether it drags the session load/resume budget with it. It does not — probing the built acp-bridge dist directly:

DEFAULT_SESSION_RESTORE_TIMEOUT_MS = 60000
unset (production default)                 -> restore budget 60000 ms
initializeTimeoutMs: 10000 (old default)   -> restore budget 60000 ms
initializeTimeoutMs: 60000 (the flag)      -> restore budget 60000 ms
initializeTimeoutMs: 90000                 -> restore budget 90000 ms

resolveSessionRestoreTimeoutMs takes Math.max(initializeTimeoutMs, 60000), so 60000 is a fixed point. And the production default is genuinely untouched: DEFAULT_INIT_TIMEOUT_MS = 10_000 (packages/acp-bridge/src/bridge.ts:2587) — arm A above observed it live at 9991 ms.

5. One residual gap the sweep missed (non-blocking, for a follow-up)

The triage note said the benchmark suites were left alone "since they don't create sessions". Two of the three do. The one that matters:

spawnDaemonWithTime() (integration-tests/cli/_daemon-benchmark-helpers.ts:297) builds its own argument list and, unlike spawnDaemon() in _daemon-harness.ts:121, omits --initialize-timeout-ms. qwen-daemon-vs-cli-benchmark.test.ts:312 then calls createOrAttachSession on that daemon. The same test is its own A/B: iterations 0..n-2 go through spawnDaemon() (60 s), the last one through spawnDaemonWithTime() (10 s).

benchmark gap

Under the identical 12 s delay the harness-spawned iterations pass and the timed one fails with the same signature; adding the same two lines to that helper turns the test green. This is not urgent: the file is gated behind QWEN_BENCHMARK_ENABLED=1, which appears nowhere under .github/, so it never runs in CI today.

For completeness, the other two benchmark files are genuinely safe, but for different reasons than stated: qwen-daemon-startup-benchmark.test.ts never creates a session, so it never reaches the handshake at all; qwen-daemon-first-output-benchmark.test.ts does create sessions but is excluded from the default config (**/qwen-daemon-first-output-benchmark*) and runs under vitest.firstoutput.config.ts.

6. Housekeeping

  • Main CI failed: E2E Tests on 74fe3a659dde #11043 is still open, and this PR is the only thing cross-referencing it. Its failing commit 74fe3a6 (2026-09-04 18:33 UTC) predates b0a463c (2026-09-05 01:14 UTC), so main already fixes it — but closing this PR silently would leave the issue orphaned. Worth closing Main CI failed: E2E Tests on 74fe3a659dde #11043 with a pointer at b0a463c.
  • The earlier "⚠️ Downgraded from Approve to Comment: CI failing: Test (ubuntu-latest, Node 22.x)" is stale — that job passes on the current head.
  • Nothing here is a criticism of the PR. It diagnosed the flake correctly and reached the same fix independently; it simply lost a race by about 75 minutes.
中文说明

本地验证 —— 真实 daemon、真实 qwen --acp 子进程、可复现的 flake

我在本地搭了真实验证环境,而不是只读 diff。因为这里真正值得回答的问题不是"这五行有没有写对",而是这个预算到底起不起作用,以及在 @qwen-code /resolve 把 main 合进来之后,这个 PR 还剩下什么内容。

结论:改动是对的,而且已经在 main 上了。本 PR 现在不携带任何内容,建议按"已被取代"关闭而不是合并;同时把仍然处于 open 状态、且除本 PR 外无人引用的 #11043 一并关掉。

环境:Debian 13、Linux 6.12.63 x86_64、16 核、Node v22.22.2、vitest 3.2.7。在 origin/main c39e83e 上从源码完整构建(npm run build -- --cli-only && npm run bundle);PR head 38103fc

1. 本 PR 已无独有内容。 git diff origin/main...38103fc535 为空。更强的证明:PR head 的 tree7c83a94a)与 merge base e3d26283 的 tree 完全相同,而 e3d26283 已是 origin/main 的祖先;PR 唯一改过的那个文件两侧 blob 逐字节相同(c730ea79);b0a463c6ec(#11041)已是 PR head 的祖先。合并只会给 main 追加两个不改变任何内容的提交。

2. 这个预算确实是承重的 —— 在协议线上验证,而非靠阅读。 我在 daemon 与 ACP 子进程之间插了一个 shim(QWEN_CLI_ENTRY → shim → 真实 qwen --acp):NDJSON JSON-RPC 双向逐帧透传,只改一件事 —— initialize 响应的到达时间。这正是繁忙共享 runner 的效果,但完全确定。同一 bundle、同一真实子进程、同样注入 20 秒延迟,只变一个变量:不带 flag → 504AcpSessionBridge initialize timed out after 9991ms(与 #11043qwen-serve-streaming.test.ts:5199996ms 同类同阶段同预算);带 --initialize-timeout-ms 60000200,21272ms 建会话成功。

3. 套件级 A/B(含反向对照)。 对构建产物跑了三次真实套件:基线(无延迟)11/11 通过、12.94s;arm 1(main/PR head,带 flag)+12s 延迟,11/11 通过、97.05s;arm 2(外科式删掉 flag,还原 #11041 之前的参数)+同样 12s 延迟,11/11 全挂,每条都是 DaemonHttpError: POST /session: AcpSessionBridge initialize timed out after ~9.99s。反向对照才是关键:套件在延迟下是绿的,是因为这两行,而不是恰好与它同时为绿。

4. 对 restore 预算无副作用。 抬高 initialize 预算唯一值得担心的是会不会把 session load/resume 预算一起带偏。直接探测构建后的 acp-bridge dist:未设置 → 60000;10000 → 60000;60000 → 60000;90000 → 90000。resolveSessionRestoreTimeoutMsMath.max(initializeTimeoutMs, 60000),所以 60000 是不动点。产品默认值也确实没动:DEFAULT_INIT_TIMEOUT_MS = 10_000packages/acp-bridge/src/bridge.ts:2587)—— 上面 arm A 在 9991ms 处实测到了它。

5. 遗漏的一处(非阻塞,可另开 PR)。 triage 说 benchmark 套件"不创建会话"所以不用管,三个里有两个其实会创建。要紧的一个是:spawnDaemonWithTime()_daemon-benchmark-helpers.ts:297)自己拼参数列表,与 _daemon-harness.ts:121spawnDaemon() 不同,没有传 --initialize-timeout-ms;而 qwen-daemon-vs-cli-benchmark.test.ts:312 会在这个 daemon 上 createOrAttachSession。这条用例本身就是个 A/B:第 0..n-2 轮走 spawnDaemon()(60s),最后一轮走 spawnDaemonWithTime()(10s)。同样注入 12s 延迟:前面几轮通过,最后一轮以同样签名失败;给那个 helper 补上同样两行即转绿。不紧急:该文件由 QWEN_BENCHMARK_ENABLED=1 把守,而这个变量在 .github/ 下根本不存在,所以目前不会在 CI 里跑。另外两个 benchmark 文件确实安全,但理由与 triage 所述不同:qwen-daemon-startup-benchmark.test.ts 从不创建会话,压根到不了握手;qwen-daemon-first-output-benchmark.test.ts 会创建会话,但被默认配置排除(**/qwen-daemon-first-output-benchmark*),跑在 vitest.firstoutput.config.ts 下。

6. 收尾事项。 #11043 仍然 open,且只有本 PR 交叉引用了它;其失败提交 74fe3a6(2026-09-04 18:33 UTC)早于 b0a463c(2026-09-05 01:14 UTC),main 已经修好了 —— 但如果只是悄悄关掉本 PR,这个 issue 会被落下,建议引用 b0a463c 一并关闭。另外早先那条"⚠️ Downgraded from Approve to Comment: CI failing"已经过期,当前 head 上该 job 是通过的。最后:这些都不是对本 PR 的批评 —— 它对 flake 的诊断是对的,也独立得出了同样的修法,只是慢了大约 75 分钟。

Verified locally with Claude Code (model: Claude Opus 5, 1M context). Evidence images: wenshao/qwen-code@6861426 (branch assets-pr11051).

@he-yufeng

Copy link
Copy Markdown
Contributor Author

Confirmed superseded: current main passes ACP_INITIALIZE_TIMEOUT_MS through this suite's daemon spawn via #11041, which fixes the same root cause (inline spawns inheriting the 10s production default) across all three suites that build their own daemon args. Nothing left here, closing.

@he-yufeng he-yufeng closed this Sep 5, 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.

Main CI failed: E2E Tests on 74fe3a659dde

5 participants