fix(webui): make the delta-resume reconnect test deterministic (#10200) - #10203
Conversation
The 'preserves session and uses delta resume after a retriable SSE error' test asserted the resumed transcript after a fixed 20 ms wait counted from render, racing two asynchronous hops: the 1 ms reconnect and the 16 ms batched transcript dispatch. On loaded runners the reconnect plus dispatch flush lands after the wait ends, so the assertion saw only the pre-error chunk and the nightly macOS/Windows lanes failed (run 33007778391, Windows annotation at DaemonSessionProvider.test.tsx). Wait on a deferred the mock generator resolves once the resumed chunk is pulled by the consumer, then drain the batched dispatch with the same flushTranscriptDispatch() idiom the sibling reattach test uses. Assertions are unchanged.
Autofix report — issue #10200 (Main CI failed: Qwen Code CI on a82a11a)What failedThe nightly
The issue body says the run failed "before any test result was reported" only because the failure-signature analyzer found no The predecessor nightly (32889631784, issue #10054) failed on 2026-08-25 on the standing Windows-only clusters (dws-event-stream, SessionMessageHandler drive-qualified URLs, node-repl EBUSY rmdir) that commit Root cause
The test waited FixMade the test deterministic with that same idiom: the mock generator resolves a Mutation probes (witness for the added deterministic wait)The race cannot be reproduced by raw slowness on a fast local machine, so the probes slow the reconnect deterministically instead (
macOS lane noteThe macOS lane failed at the same step with no test annotation available through the public API (job logs require authentication, which this flow does not have). Its most likely cause is the same timing flake — both lanes ran the identical suite the same day, and the Windows lane's single identified failure is this test — but that attribution is inferred, not proven. If the macOS lane fails again tonight with a different signature, the per-commit issue flow will capture it. Verification
中文说明自动修复报告 — issue #10200(Main CI failed: Qwen Code CI on a82a11a)失败内容2026-08-26 的每日定时
issue 正文写"在报告任何测试结果之前失败",只是因为失败签名分析器没有找到可用于去重的 前一天的定时运行(32889631784,issue #10054)在 2026-08-25 失败于长期存在的 Windows 专属失败簇(dws-event-stream、SessionMessageHandler 带盘符的 URL、node-repl EBUSY rmdir),这些已由提交 根因
测试从渲染起等待 修复用同样的写法让测试变得确定:mock 生成器在恢复块被消费方取走时兑现 变异探针(为新增的确定性等待提供见证)在快速本地机器上无法靠"慢"复现该竞态,因此探针改为确定性地放慢重连(
关于 macOS 通道macOS 通道在同一步骤失败,但公开 API 中没有可用的测试注释(作业日志需要认证,而本流程没有凭证)。其最可能的原因是同一个时序性 flake——两个通道在同一天运行了完全相同的测试套件,且 Windows 通道唯一被确认的失败就是这个测试——但这一归因是推断,不是证明。如果今晚 macOS 通道再次以不同的失败签名失败,按提交建 issue 的流程会将其记录下来。 验证
🧠 Handled by Qwen Code · model/模型 |
|
|
|
Thanks for the PR! Template looks good ✓ Problem: observed, not theoretical. The nightly Direction: aligned. The nightly is the only signal the macOS and Windows lanes produce, and replacing a wall-clock wait with an explicit delivery signal is the right way to make that signal trustworthy. No direct CHANGELOG reference (test-only change), but the area is clearly relevant. Size: not applicable — 0 production lines. The whole diff is one test file, +4/−1. Approach: scope is exactly right. The change adopts the deferred + Risk: no elevated risk signals — test-only change, no high-risk paths matched. Moving on to code review. 🔍 中文说明感谢贡献! 模板完整 ✓ 问题:已观测到,不是理论性的。每日定时 方向:对齐。每日定时运行是 macOS 与 Windows 通道唯一的信号来源,把按墙钟等待换成显式送达信号是让该信号可信的正确做法。CHANGELOG 无直接引用(纯测试改动),但该领域显然相关。 规模:不适用——0 行生产代码。整个 diff 只有一个测试文件,+4/−1。 方案:范围恰好。改动采用了相邻 风险:无升级风险信号——纯测试改动,未命中高风险路径。 进入代码审查 🔍 — Qwen Code · qwen3.8-max Reviewed at |
Code reviewReading just the title and motivation, my independent proposal for this flake would be: drop the wall-clock Verified against the base tree while reading:
No blockers, no convention violations. Testing evidenceUnattended CI run — PR code was not built or executed here; the evidence below is the PR's own CI, read through the API at the reviewed commit. The Linux unit lane ( Final CI results for
One row per check name (latest run); skipped checks omitted; failures sort first. / 每个检查名一行(取最新一次运行),省略 skipped,失败项排在最前。 Sandboxed verification would settle part of this: 中文说明代码审查只看标题和动机,我对这个 flake 的独立方案是:去掉按墙钟的 对照基线树核实过:
无阻塞项,无规范违规。 测试证据无人值守 CI 运行——此处未构建或执行 PR 代码;以下证据是通过 API 读取的该 PR 自身在被审提交上的 CI。 Linux 单元测试通道( CI 表格见上方机器可读区域(机器人编排作业已省略):两条平台测试通道按设计被跳过,Linux 通道进行中,其余已完成检查均为绿色。 沙盒验证可以解决其中一部分: — Qwen Code · qwen3.8-max Reviewed at |
|
Confidence: 5/5 — clean across every stage: an observed flake with a CI annotation pinning it, a race mechanism I could verify against the base code, and a minimal fix that reuses the file's established idiom with byte-identical assertions. Stepping back: this is the nightly failing for the right reason to fix. The macOS and Windows test lanes only run on the nightly, and a wall-clock race in one test has been turning them red (#10200, and #10054 the day before), which is how real regressions get drowned out on those platforms. The fix removes the only deadline gating the assertion — the remaining waits are drains, not races — so the test now fails only if the delta-resume behavior it pins actually breaks. It also brings this test in line with the sibling reattach test, leaving one idiom in the file instead of two. The author is the repo's autofix bot and opened the linked issue itself ( The one thing no pre-merge signal can give is the macOS/Windows empirical confirmation, since those lanes are nightly-only — tonight's run is the real before/after. Approval deferred until CI lands green on 中文说明置信度:5/5 —— 各阶段都干净:一个有 CI 注释定位的已观测 flake,一个可以对照基线代码核实的竞态机理,以及一个复用文件既有写法、断言逐字节不变的最小修复。 退一步看:这正是值得修的夜间失败。macOS 与 Windows 测试通道只在每日定时运行中出现,而一个测试里的墙钟竞态一直在把它们染红(#10200,以及前一天的 #10054)——真正的回归就是这样在这些平台上被噪音淹没的。该修复移除了唯一卡住断言的时限——剩下的等待都是排空,不是竞态——所以现在只有当它所钉住的 delta-resume 行为真的坏了,测试才会失败。它也把这个测试与相邻的 reattach 测试对齐,让文件里只剩一种写法而不是两种。作者是仓库的 autofix 机器人且自己开了关联 issue( 唯一无法在合并前拿到的是 macOS/Windows 的实证确认,因为那些通道只在夜间运行——今晚的运行就是真正的 before/after。 在 — Qwen Code · qwen3.8-max Reviewed at |
🖼️ web-shell visual previewRendered against a mock daemon (no real backend): the PR base vs this PR head Screenshots · before / afterFull-resolution recordings (.webm) are attached to the workflow run. — Qwen Code · web-shell visuals |
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. |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Test Plan (not a blocker): src/daemon/session/DaemonSessionProvider.test.tsx — no such file or directory.
中文说明
Test Plan(非阻断):src/daemon/session/DaemonSessionProvider.test.tsx — no such file or directory。
— qwen3.8-max via Qwen Code /review (v0.22.2)
|
🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下: Autofix review round — no action taken on this PRThis round's feedback contained zero code findings (the automated review's own ledger posted no findings). The only actionable item was the red What the failing check actually wasVia the public Actions API (step-level conclusions for job 98325758176), the only failed step is Run tests and generate reports ( Root cause:
|
|
🔀 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 将重新运行。 |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Not reviewed: build-and-test — the test suites never ran: the harness's build-to-test pipeline aborted on a pre-existing web-shell tsc failure at the merge base (files untouched by this PR), and the PR's ubuntu CI lane was terminated mid-run by a runner ENOSPC.
Test Plan (not a blocker): src/daemon/session/DaemonSessionProvider.test.tsx — no such file or directory.
Deferred under the convergence posture (round 2, not a blocker) — recorded, not requested in this round:
packages/webui/src/daemon/session/DaemonSessionProvider.test.tsx:12201 — [probe] Unbounded deferred wait obscures regression diagnostics
中文说明
未审查:build-and-test — the test suites never ran: the harness's build-to-test pipeline aborted on a pre-existing web-shell tsc failure at the merge base (files untouched by this PR), and the PR's ubuntu CI lane was terminated mid-run by a runner ENOSPC。
Test Plan(非阻断):src/daemon/session/DaemonSessionProvider.test.tsx — no such file or directory。
收敛姿态下延后(第 2 轮,非阻断)——已记录,本轮不要求修改:共 1 条(原文未翻译,列表见上方英文部分)。
— qwen3.8-max via Qwen Code /review (v0.22.2)
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
No issues found. LGTM! ✅
Test Plan (not a blocker): src/daemon/session/DaemonSessionProvider.test.tsx — no such file or directory.
中文说明
未发现问题。LGTM!✅
Test Plan(非阻断):src/daemon/session/DaemonSessionProvider.test.tsx — no such file or directory。
— qwen3.8-max via Qwen Code /review (v0.22.2)
qqqys
left a comment
There was a problem hiding this comment.
Approving. Independent check of the current head (7c4e3d95a8): test-only determinism fix (4+/1-) — the wall-clock wait(20) is replaced by a deferred that resolves exactly when the resume event is delivered, followed by flushTranscriptDispatch(); no production code touched, no blocking issues. Both the maintainer and the bot have approved at this head and all ran CI lanes are green; concur.
|
🕐 Review received — an automatic review of the current head is still running, so this round is held until it lands (a push now would cancel it and discard its work, #8888). Your feedback stays queued for the next eligible round. 中文说明🕐 已收到评审 —— 当前 head 上仍有一轮自动 review 在运行,本轮暂缓(现在推送会取消该 review 并丢弃其工作,#8888)。反馈保持排队,等待下一次可运行的轮次处理。 |
What this PR does
The nightly
Qwen Code CIrun is the only trigger left for the macOS and Windows test lanes, and the 2026-08-26 run failed on both at the test step. The Windows lane's check-run annotation pins the failure to one test in the daemon session provider suite:preserves session and uses delta resume after a retriable SSE error, whose transcript assertion saw only the pre-error chunk instead of the pre-error chunk plus the resumed delta. This PR makes that test deterministic: instead of asserting after a fixed 20 ms wait counted from render, the test now waits on a deferred that its own mock generator resolves the moment the resumed chunk is pulled by the consumer, then drains microtasks and the provider's batched transcript-dispatch timer — the same idiom the sibling reattach test already uses. The test's three assertions are unchanged.Why it's needed
The test raced two asynchronous hops against its fixed budget: the reconnect scheduled after the first SSE attempt throws, and the provider's 16 ms batched transcript dispatch that applies the resumed chunk to the reducer. On a fast machine both complete inside the 20 ms window; on loaded CI runners the flush lands after the assertion, so the transcript still holds only the pre-error chunk and the lane goes red. This is the failure the nightly captured after the standing Windows-only failure clusters were repaired by #10064 — a timing flake, not a product regression, but load-bearing because the nightly is the only signal these two lanes produce.
Reviewer Test Plan
How to verify
Run the test in
packages/webui:npx vitest run src/daemon/session/DaemonSessionProvider.test.tsx -t "preserves session and uses delta resume after a retriable SSE error"— it passes repeatedly (verified 5 consecutive runs). To see the race the fix removes, temporarily setreconnectDelayMs: 25(above the old 20 ms budget) in the test'srenderWithProvideroptions and restore the oldawait wait(20); await flushPromises();act block: the test fails (expected "retriableEvents" to be called 2 times, but got 1 times), reproducing the CI failure mode. Keeping the committed act block withreconnectDelayMs: 25passes — the deterministic wait absorbs any reconnect latency. The full suitecd packages/webui && npm run test:ciis green (35 files, 638 tests), and the assertions themselves are byte-identical to before, so the pinned behavior is unchanged.Evidence (Before & After)
N/A — test-only change, no user-visible behavior. CI evidence: run 33007778391 Windows annotation
DaemonSessionProvider.test.tsx:12207expected"before error after resume", received"before error".Tested on
Environment (optional)
Unit tests only:
npx vitest run/npm run test:ciinpackages/webui, Node 22.23.2, no sandbox.Risk & Scope
FAILline from these logs (hence the per-commit issue) lives in.github/and is deliberately untouched here.Linked Issues
Fixes #10200
Related: #10054 (same per-commit nightly failure from the previous day)
中文说明
本 PR 做了什么
每日定时的
Qwen Code CI运行是 macOS 与 Windows 测试通道仅剩的触发器,2026-08-26 的运行在两个通道的测试步骤都失败了。Windows 通道的 check-run 注释把失败定位到 daemon session provider 测试套件中的一个测试:preserves session and uses delta resume after a retriable SSE error,其转录断言只看到了错误前的块,而没有看到错误前的块加上恢复后的增量。本 PR 让该测试变得确定:不再从渲染开始固定等 20 毫秒后断言,而是等待一个由测试自己的 mock 生成器在恢复块被消费方取走的那一刻兑现的 deferred,然后排空微任务和 provider 的批处理转录分发定时器——这正是相邻的 reattach 测试已经在使用的写法。测试的三个断言保持不变。为什么需要
该测试用固定预算与两个异步跳步竞态:第一次 SSE 尝试抛出后调度的重连,以及把恢复块应用到 reducer 的 provider 16 毫秒批处理转录分发。在快速机器上两者都能在 20 毫秒窗口内完成;在负载较高的 CI 运行器上,刷新落在断言之后,转录里仍然只有错误前的块,通道于是变红。这正是 #10064 修复长期存在的 Windows 专属失败簇之后,每日定时运行捕获的失败——是时序性 flake,不是产品回归,但由于每日定时运行是这两个通道唯一的信号来源,它仍然必须修复。
评审者测试计划
如何验证
在
packages/webui中运行该测试:npx vitest run src/daemon/session/DaemonSessionProvider.test.tsx -t "preserves session and uses delta resume after a retriable SSE error"— 可重复通过(已验证连续 5 次运行)。要看到这个修复所消除的竞态,可临时把测试renderWithProvider选项中的reconnectDelayMs设为 25(高于旧的 20 毫秒预算),并恢复旧的await wait(20); await flushPromises();act 块:测试会失败(expected "retriableEvents" to be called 2 times, but got 1 times),复现 CI 的失败模式。保持提交的 act 块并把reconnectDelayMs设为 25 则通过——确定性等待可以吸收任意重连延迟。完整套件cd packages/webui && npm run test:ci为绿色(35 个文件,638 个测试),且断言本身与之前逐字节一致,因此钉住的行为没有变化。前后证据(Before & After)
N/A — 纯测试改动,无用户可见行为。CI 证据:运行 33007778391 的 Windows 注释
DaemonSessionProvider.test.tsx:12207期望"before error after resume",实际为"before error"。测试平台
环境(可选)
仅单元测试:在
packages/webui中运行npx vitest run/npm run test:ci,Node 22.23.2,无沙箱。风险与范围
FAIL行(从而产生按提交计数的 issue)的分析器位于.github/,本 PR 有意不动它。关联 Issue
Fixes #10200
相关:#10054(前一天同样的按提交计数每日定时失败)