Skip to content

fix(web-shell): use renamed session-activity mock in split-view rerender test (#11409) - #11412

Merged
wenshao merged 1 commit into
mainfrom
autofix/issue-11409
Sep 9, 2026
Merged

fix(web-shell): use renamed session-activity mock in split-view rerender test (#11409)#11412
wenshao merged 1 commit into
mainfrom
autofix/issue-11409

Conversation

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

What this PR does

This PR repairs one Web Shell unit test in the split-view session navigation suite. The test that pins "App must not rerender when the split view reports pending panes belonging to other sessions" referenced a mock variable that no longer exists on main, so the test aborted with a ReferenceError before making any assertion. The three offending lines now use the existing, correctly named session-activity mock — the same App-render sensor the test intended, under its current name.

Why it's needed

The nightly release v0.23.1-nightly.20260908.1f890086f1 failed (#11409): the release workflow's Workspace Tests (2/3) lane ran this test and exited non-zero, which failed the aggregated Quality Checks gate and blocked the release. The break is a semantic merge conflict: #11267 renamed the App-level prompt-state hook (and its test mock) on main while #11250 was open; #11250's CI was green on its own head, and its squash merge combined textually but left its new test block referencing the deleted name. The nightly was the first release validation to execute the combined tree.

Reviewer Test Plan

How to verify

Confirm the test now runs and still guards the intended behavior:

  • cd packages/web-shell && npx vitest run client/App.test.tsx -t "does not rerender App for other split sessions" — both outer pending variants should pass (they previously failed with ReferenceError: mockUseDaemonActivePromptBridge is not defined).
  • Full suite: cd packages/web-shell && npx vitest run --config vitest.config.ts — 288 files / 6712 tests pass.
  • Release lane reproduction: VITEST_RETRY=2 NO_COLOR=true .github/scripts/run-release-workspace-tests.sh 2 — all workspaces green, exit code 0 (previously the web-shell workspace failed this lane).
  • The sensor used by the test is the hook App calls on every render; if App were changed to rerender on foreign-session pending reports, both variants fail again (verified locally via a temporary mutation).

Evidence (Before & After)

N/A — test-only change, no user-visible behavior. Before: the two test variants fail with ReferenceError in any environment. After: they pass and still detect App rerenders triggered by other sessions' split panes.

Tested on

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

Environment (optional)

N/A — unit tests only (Vitest, Node 22).

Risk & Scope

  • Main risk or tradeoff: none expected; the change touches a single test file and swaps an undefined mock reference for the equivalent existing mock. A mutation probe confirmed the repaired assertions still fail when the guarded behavior regresses.
  • Not validated / out of scope: the CI-side question of how a semantic merge conflict reached main (required checks ran on the PR's pre-merge head) is not addressed here; changing required-check or merge-queue configuration is CI machinery and out of scope for this fix.
  • Breaking changes / migration notes: none.

Linked Issues

Fixes #11409

中文说明

本 PR 做了什么

本 PR 修复了 split-view 会话导航套件中的一个 Web Shell 单元测试。该测试用于固定"当 split view 上报属于其他会话的 pending 面板时,App 不得重渲染"这一行为,但它引用了一个在 main 上已不存在的 mock 变量,导致测试在进行任何断言之前就以 ReferenceError 中止。涉事的三行现在改用现有的、命名正确的会话活跃度 mock——这正是测试原本想要的 App 渲染探针,只是采用了它现在的名字。

为什么需要

每夜发布 v0.23.1-nightly.20260908.1f890086f1 失败(#11409):发布工作流的 Workspace Tests (2/3) 分片运行了该测试并以非零状态退出,导致聚合的 Quality Checks 门禁失败,阻塞了发布。这次破坏是一次语义合并冲突:#11267#11250 仍处于打开状态时在 main 上重命名了 App 层的 prompt 状态钩子(及其测试 mock);#11250 的 CI 在它自己的 head 上是绿色的,而它的压缩合并在文本层面合并成功,却让它新增的测试块继续引用已被删除的名称。每夜发布是第一个执行合并后代码树的发布验证。

评审者测试计划

如何验证

确认该测试现在可以运行、并且仍然守护预期行为:

  • cd packages/web-shell && npx vitest run client/App.test.tsx -t "does not rerender App for other split sessions" —— 两个 outer pending 变体都应通过(此前它们以 ReferenceError: mockUseDaemonActivePromptBridge is not defined 失败)。
  • 完整套件:cd packages/web-shell && npx vitest run --config vitest.config.ts —— 288 个文件 / 6712 个测试通过。
  • 发布通道复现:VITEST_RETRY=2 NO_COLOR=true .github/scripts/run-release-workspace-tests.sh 2 —— 所有工作区全绿,退出码 0(此前 web-shell 工作区在此通道失败)。
  • 该测试使用的探针是 App 每次渲染都会调用的钩子;如果把 App 改成在外来会话的 pending 上报时重渲染,两个变体会再次失败(已用临时变异在本地验证)。

前后对比证据

N/A —— 仅测试修改,无用户可见行为。修复前:两个测试变体在任何环境下都以 ReferenceError 失败。修复后:它们通过,并且仍能检测由其他会话的 split 面板触发的 App 重渲染。

已测试平台

系统 状态
🍏 macOS ⚠️ 未测试
🪟 Windows ⚠️ 未测试
🐧 Linux ✅ 已测试

环境(可选)

N/A —— 仅单元测试(Vitest,Node 22)。

风险与范围

  • 主要风险或取舍:预期无风险;修改仅涉及一个测试文件,把一个未定义的 mock 引用换成等价的现有 mock。变异测试已确认修复后的断言在被守护的行为退化时仍会失败。
  • 未验证 / 超出范围:语义合并冲突如何进入 main 这一 CI 侧问题(必需检查运行在 PR 合并前的 head 上)不在此处理;修改必需检查或合并队列配置属于 CI 基础设施,超出本次修复范围。
  • 破坏性变更 / 迁移说明:无。

关联 Issue

Fixes #11409

…der test (#11409)

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

Autofix E2E Report — Issue #11409

Summary

The nightly release v0.23.1-nightly.20260908.1f890086f1 (run 34279240951) failed because the aggregated Quality Checks job failed closed: the Workspace Tests (2/3) lane exited non-zero while every other lane (static, build, typecheck, scripts, shards 1 and 3, both integration lanes) passed.

Root cause

Shard 2 ran a Web Shell unit test that could not execute in any environment:

FAIL App.test.tsx > App session callbacks > does not rerender App for other split sessions (outer pending: false)
ReferenceError: mockUseDaemonActivePromptBridge is not defined

This is a semantic merge conflict, not a product bug:

  1. 6b7e5615c7 (fix(web-shell): show session active work #11267, landed 11:54 UTC) renamed the App-level hook useDaemonActivePromptBridge to useDaemonSessionActivityBridge on main, including its test mock mockUseDaemonSessionActivityBridge.
  2. feat(web-shell): Improve split-view session navigation #11250 (squash-merged as 70cf363395 at 17:33 UTC) had been written against the old name. Its CI ran green on its own head, where the old name still existed.
  3. The squash merge onto current main combined textually but left the PR's new test block referencing the deleted name. The 17:02 UTC preview release had already checked out an older commit, so the 21:12 UTC nightly was the first release validation to run the broken test.

The check-run annotations for the failed job show only GitHub's generic "Process completed with exit code 1" — consistent with run-release-workspace-tests.sh finding a real FAIL line (it stays silent in that case) rather than a Vitest transport timeout or an infrastructure death.

Fix

One test-only change in packages/web-shell/client/App.test.tsx (3 lines): the split-view rerender test now uses the existing, correctly named mockUseDaemonSessionActivityBridge mock. That mock wires useDaemonSessionActivityBridge, which App.tsx calls unconditionally on every render, so it is exactly the rerender sensor the test intends — the same hook the PR's sensor referenced under its pre-rename name.

A mutation probe confirms the repaired test still guards the behavior: with App.tsx temporarily changed so that foreign-session pending reports force a rerender, both variants of the test fail; with the code restored, they pass.

Two other failure groups appear only in this sandbox and are not part of the CI failure: ChannelBase.test.ts (EACCES creating ~/.qwen under a root-owned HOME) and exit-worktree.session.integ.test.ts both pass with a writable HOME, and the remaining first-attempt failures (docsCommand, extensionsCommand, Footer snapshots) were caused by this sandbox's SANDBOX/QWEN_* environment variables leaking into the test process.

Verification

  • npm run lint:ci (pre-fix, release quality_static equivalent) — passed
  • npm run typecheck (pre-fix) — passed
  • npm run test:scripts (pre-fix, release quality_scripts equivalent) — 82 files, 2310 passed, 17 skipped
  • npm run check:serve-fast-path-bundle (pre-fix) — passed
  • npm run build (pre-fix) — passed
  • npm run bundle + dist/review-sources.sha256 presence (pre-fix verify-package steps) — passed
  • npm run prepare:package (pre-fix) — passed
  • VITEST_RETRY=2 NO_COLOR=true .github/scripts/run-release-workspace-tests.sh 2 on the failing commit — reproduced: packages/web-shell App.test.tsx failed 2 tests with ReferenceError: mockUseDaemonActivePromptBridge is not defined
  • Post-fix npx vitest run client/App.test.tsx -t "does not rerender App for other split sessions" (packages/web-shell) — 2 passed
  • Post-fix full Web Shell suite npx vitest run --config vitest.config.ts — 288 files, 6712 tests, all passed
  • Mutation probe on App.tsx (force rerender on every pending-panes report) — both repaired tests fail; after restoring, both pass
  • Post-fix exact release lane VITEST_RETRY=2 NO_COLOR=true .github/scripts/run-release-workspace-tests.sh 2 — every workspace green (cli 341 files / 9627 tests, core 216 / 7275, web-shell 96 / 3020, channels/base 7 / 968, all others passed), exit code 0
  • Post-fix npm run build — passed
  • Post-fix npm run typecheck — passed
  • Post-fix npm run lint — passed
  • Pre-commit hook (lint-staged on the changed file) — passed
中文说明

Autofix E2E 报告 — Issue #11409

摘要

每夜发布 v0.23.1-nightly.20260908.1f890086f1(运行 34279240951)失败,原因是聚合的 Quality Checks 任务按失败关闭处理:Workspace Tests (2/3) 分片以非零状态退出,而其他所有通道(静态检查、构建、类型检查、脚本测试、分片 1 和 3、两条集成测试通道)全部通过。

根因

分片 2 运行了一个在任何环境下都无法执行的 Web Shell 单元测试:

FAIL App.test.tsx > App session callbacks > does not rerender App for other split sessions (outer pending: false)
ReferenceError: mockUseDaemonActivePromptBridge is not defined

这是一次语义合并冲突,而非产品缺陷:

  1. 6b7e5615c7fix(web-shell): show session active work #11267,11:54 UTC 合入)在 main 上将 App 层钩子 useDaemonActivePromptBridge 重命名为 useDaemonSessionActivityBridge,其测试 mock 也随之变为 mockUseDaemonSessionActivityBridge
  2. feat(web-shell): Improve split-view session navigation #11250(17:33 UTC 以 70cf363395 压缩合入)是基于旧名称编写的。它的 CI 在自己的 head 上运行为绿色,因为当时旧名称仍然存在。
  3. 压缩合并到当前 main 在文本层面合并成功,但 PR 新增的测试块仍引用已删除的名称。17:02 UTC 的预览发布检出的是更早的提交,因此 21:12 UTC 的每夜发布是第一个运行到该坏测试的发布验证。

失败任务的 check-run 注解只有 GitHub 通用的 "Process completed with exit code 1"——这与 run-release-workspace-tests.sh 发现真实 FAIL 行时保持沉默的行为一致(而非 Vitest 传输超时或基础设施故障)。

修复

仅测试文件的一处修改:packages/web-shell/client/App.test.tsx(3 行):split-view 重渲染测试改用现有的、命名正确的 mockUseDaemonSessionActivityBridge mock。该 mock 接入了 useDaemonSessionActivityBridge,而 App.tsx 在每次渲染时都会无条件调用它,因此它正是该测试所需的重渲染探针——与 PR 原本引用的探针是同一个钩子,只是改名前的旧名称。

变异测试(mutation probe)确认修复后的测试仍然守护原行为:临时修改 App.tsx 让外来会话的 pending 上报强制触发重渲染时,两个测试变体都会失败;恢复代码后它们通过。

另外两组失败仅出现在本沙箱中,与本次 CI 失败无关:ChannelBase.test.ts(在 root 拥有的 HOME 下创建 ~/.qwen 时 EACCES)和 exit-worktree.session.integ.test.ts 在 HOME 可写时全部通过;首次运行中的其余失败(docsCommand、extensionsCommand、Footer 快照)是本沙箱的 SANDBOX/QWEN_* 环境变量泄漏进测试进程所致。

验证

  • npm run lint:ci(修复前,等同于发布 quality_static 通道)—— 通过
  • npm run typecheck(修复前)—— 通过
  • npm run test:scripts(修复前,等同于发布 quality_scripts 通道)—— 82 个文件,2310 通过,17 跳过
  • npm run check:serve-fast-path-bundle(修复前)—— 通过
  • npm run build(修复前)—— 通过
  • npm run bundle + dist/review-sources.sha256 存在性检查(修复前 verify-package 步骤)—— 通过
  • npm run prepare:package(修复前)—— 通过
  • 在失败提交上运行 VITEST_RETRY=2 NO_COLOR=true .github/scripts/run-release-workspace-tests.sh 2 —— 复现:packages/web-shell 的 App.test.tsx 有 2 个测试因 ReferenceError: mockUseDaemonActivePromptBridge is not defined 失败
  • 修复后 npx vitest run client/App.test.tsx -t "does not rerender App for other split sessions"(packages/web-shell)—— 2 个通过
  • 修复后完整 Web Shell 套件 npx vitest run --config vitest.config.ts —— 288 个文件,6712 个测试,全部通过
  • App.tsx 的变异测试(让每次 pending-panes 上报都强制重渲染)—— 两个修复后的测试均失败;恢复后均通过
  • 修复后按发布通道原样运行 VITEST_RETRY=2 NO_COLOR=true .github/scripts/run-release-workspace-tests.sh 2 —— 所有工作区全绿(cli 341 文件 / 9627 测试,core 216 / 7275,web-shell 96 / 3020,channels/base 7 / 968,其余全部通过),退出码 0
  • 修复后 npm run build —— 通过
  • 修复后 npm run typecheck —— 通过
  • 修复后 npm run lint —— 通过
  • 提交前钩子(对变更文件运行 lint-staged)—— 通过

🧠 Handled by Qwen Code · model/模型 kimi-k3 · CLI 0.23.1

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Qwen Triage finished — CI landed green on 34e6ea3 and the deferred approval was posted. finalize run

Qwen Triage 已完成 —— 34e6ea3 的 CI 全绿,延迟审批已提交。查看 finalize 运行

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template looks good ✓

Problem: observed, with a named failure — not hardening against a hypothetical. The nightly v0.23.1-nightly.20260908.1f890086f1 failed its aggregated Quality Checks gate (#11409). I confirmed the cause independently rather than taking the description's word for it: on main@1f890086f1, mockUseDaemonActivePromptBridge has no declaration anywhere in the repository — a repo-wide search returns exactly three hits, at packages/web-shell/client/App.test.tsx:28940, :28941 and :28944, which are precisely the three lines this PR changes. The test therefore dies with a ReferenceError before reaching a single assertion, so it cannot pass in any environment.

Direction: aligned. A test that cannot execute is failing the release gate, and repairing it is squarely in scope. There is no product surface here, so there is no upstream direction signal to weigh — I did not go looking for one.

Size: not applicable. No core paths: one file under packages/web-shell/client/, +3/−3, all of it test code, so 0 production logic lines. Stage 0 does not engage.

Approach: minimal, and as far as I can tell the only correct option. I pulled #11267's own diff (6b7e5615c7) to check the equivalence claim instead of trusting the description: that commit renamed this exact symbol in five other places in this same file — the vi.hoisted destructure, the vi.fn() factory, the vi.mock wiring, the top-level beforeEach reset plus its mockImplementation, and an toHaveBeenCalledWith assertion — and also renamed App.tsx's import and call site, and the hook definition itself. #11250 (70cf363395) merged five hours later carrying a new test block still written against the pre-rename name. So this PR is the same rename applied to the three lines #11267 could not see.

The alternative — reinstating a mock under the old name — would be wrong, not merely larger: the vi.mock factory for session-catalog/session-catalog-hooks no longer exports useDaemonActivePromptBridge at all, so a fresh mockUseDaemonActivePromptBridge would never be called and expect(...).toHaveBeenCalled() would fail instead. Nothing to cut, no drive-by edits, no formatting churn.

Risk: no elevated risk signals. The high-risk path scan has nothing to match — the only changed file is filtered out as a .test.tsx.

One non-blocking observation, explicitly not for this PR: the reason this reached main is that required checks run against a PR's pre-merge head, so a rename landing while a PR is open can yield a green PR that breaks the combined tree. The description correctly scopes that out. Is there appetite for a separate look at post-merge or merge-queue validation? That belongs in its own issue rather than widening this diff.

Moving on to code review. 🔍

中文说明

感谢贡献!

模板完整 ✓

问题: 已观测到的真实故障,有明确的失败记录——不是针对假想场景的加固。每夜版本 v0.23.1-nightly.20260908.1f890086f1 的聚合 Quality Checks 门禁失败(#11409)。我没有直接采信 PR 描述,而是独立核实了根因:在 main@1f890086f1 上,mockUseDaemonActivePromptBridge整个仓库中没有任何声明——全仓搜索只有三处命中,位于 packages/web-shell/client/App.test.tsx 的 28940、28941、28944 行,正是本 PR 修改的那三行。因此该测试在执行任何断言之前就因 ReferenceError 中止,在任何环境下都不可能通过。

方向: 对齐。一个无法执行的测试正在让发布门禁失败,修复它完全在职责范围内。此处不涉及产品行为,因此没有需要权衡的上游方向信号——我也没有去硬找一个。

规模: 不适用。未触及核心路径:只有一个位于 packages/web-shell/client/ 下的文件,+3/−3,全部是测试代码,因此生产逻辑行数为 0。Stage 0 不触发。

方案: 改动最小,而且据我判断是唯一正确的选项。我拉取了 #11267 自身的 diff(6b7e5615c7)来核对"等价改名"这一说法,而不是采信描述:该提交在同一个文件里另外五处也做了完全相同的符号改名——vi.hoisted 解构、vi.fn() 工厂、vi.mock 接线、顶层 beforeEach 中的 reset 及其 mockImplementation,以及一处 toHaveBeenCalledWith 断言——同时还改了 App.tsx 的 import 与调用点,以及钩子定义本身。#1125070cf363395)在五小时后合入,其新增测试块仍按改名前的旧名编写。所以本 PR 就是把同一次改名补到 #11267 当时看不到的那三行上。

另一种做法——用旧名重新加一个 mock——不只是更大,而是错的:session-catalog/session-catalog-hooksvi.mock 工厂现在已经完全不导出 useDaemonActivePromptBridge,因此新建的 mockUseDaemonActivePromptBridge 永远不会被调用,expect(...).toHaveBeenCalled() 反而会失败。没有可砍的部分,没有顺手改动,没有格式化噪音。

风险: 无升级风险信号。高风险路径扫描没有可匹配项——唯一改动的文件作为 .test.tsx 已被过滤掉。

一条不阻塞的观察,且明确不属于本 PR 范围:这个问题能进入 main,是因为必需检查跑在 PR 合并前的 head 上,所以在 PR 开着时合入一次改名,就可能产生一个自身全绿、却破坏合并后代码树的 PR。描述里已正确地把这一点划到范围外。是否有意愿另开一个 issue 看看合并后校验或 merge queue?那比扩大本次 diff 更合适。

进入代码审查 🔍

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

Reviewed at 34e6ea308ba672aab80d11242e0e4ef0feceb723 · re-run with @qwen-code /triage

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Code review

No critical blockers, and no AGENTS.md violations. Test-only, three lines, one symbol substituted — nothing unrelated rode along.

What I actually spent the time on is whether the replacement mock is the same sensor, since a rename that quietly changes what a test measures is worse than a test that fails loudly. My own baseline before judging the diff: for a test referencing a symbol a rename deleted, the options are (a) repoint the references at the surviving equivalent, (b) re-add a mock under the old name, (c) replace the sensor with an explicit render counter, or (d) drop the test. (b) is wrong here, (c) and (d) throw away or duplicate working machinery, so (a) is what I'd have done — and it is what the PR did.

I then verified the premises of (a) rather than assuming them:

  • mockUseDaemonSessionActivityBridge is declared in the top-level vi.hoisted() block (App.test.tsx:250), so it is in module scope and resolves at line 28940 — the failure was a missing declaration, not a scoping or hoisting problem.
  • The vi.mock('./session-catalog/session-catalog-hooks') factory maps useDaemonSessionActivityBridge to that mock (App.test.tsx:1625) and exports no useDaemonActivePromptBridge. That is why option (b) would not work: a fresh mock under the old name would never be called, and expect(...).toHaveBeenCalled() would fail instead of the ReferenceError.
  • App.tsx:3304 calls useDaemonSessionActivityBridge(...) in the component body among the other hooks, so it fires on every App render.
  • It is the only production caller of that hook outside its defining module. ChatPane.tsx uses the compatibility wrapper useDaemonActivePromptBridge, and App.tsx imports ChatPane as import type only (App.tsx:175), so ChatPane never renders in this suite and cannot trip the sensor. The mock is therefore App-exclusive, and not.toHaveBeenCalled() genuinely means "App did not re-render" — not "nothing anywhere re-rendered".
  • The top-level beforeEach (App.test.tsx:9324) does mockReset() plus a mockImplementation (:9393:9394), so the call count starts at zero for each variant and the clear-then-assert sequence is meaningful.

Net: the repaired test measures the same thing it was written to measure, and it is not vacuous — its own positive assertion at line 28940 fails loudly if the sensor ever stops firing, so a silently-dead sensor cannot pass.

Test evidence

This is an unattended CI run (GITHUB_EVENT_NAME=pull_request_target), so the evidence below is the PR's own CI read through the API. I did not build, run, or check out any PR-derived code — no vitest, no gh pr checkout, no scripts from the diff.

The lane that matters here does cover the change: Test (ubuntu-latest, Node 22.x) runs npm run test:ci:workspaces (ci.yml:764), which fans out to every workspace defining a test:ci script, and packages/web-shell defines one as vitest run --config vitest.config.ts (packages/web-shell/package.json:34). So a green Test lane is direct evidence that the two previously-broken variants execute and pass — not a proxy. Worth noting the lane that originally caught this bug, the release workflow's Workspace Tests (2/3), does not run on pull requests; the PR-CI Test lane is its equivalent coverage.

At the time of writing there are no failures: 9 checks succeeded, 13 skipped, 5 still running — including Test (ubuntu-latest, Node 22.x) and Lint & Static (ubuntu-latest, Node 22.x). I did not poll or sleep-wait on them (the unit suite outlasts any sensible in-agent wait); the Qwen Triage Finalize job rewrites the table below once CI settles. The skipped lanes — Test (macos-latest…), Test (windows-latest…), Integration Tests (CLI, No Sandbox), verify, tmux-testing — are skipped by this repo's PR classification, not red.

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

Check Conclusion
Capture web-shell visuals (ubuntu-latest, Node 22.x) ✅ success
Classify PR ✅ 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
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,失败项排在最前。

Sandboxed verification would settle the one thing a green suite cannot: @qwen-code /verify — that the repaired test is load-bearing, i.e. that it fails again if App is changed to re-render on a foreign session's pending-panes report. The mutation probe supporting that claim is the author's, not something I re-ran, and a suite that passes identically with and without an assertion proves nothing. I rate this low-stakes rather than unimportant: the static chain above (App-exclusive sensor, called per render, reset per test, plus the test's own positive assertion) already makes a dead sensor impossible, so /verify would confirm what the structure implies.

Real-scenario tmux testing: N/A — unattended CI run, and nothing user-visible: the diff touches no product code, so there is no terminal surface to drive.

中文说明

代码审查

没有阻塞性问题,也没有违反 AGENTS.md 的地方。仅测试改动、三行、替换一个符号——没有夹带无关内容。

我真正花时间核实的是"替换后的 mock 是否是同一个探针",因为一次悄悄改变测试度量对象的重命名,比一个大声失败的测试更糟。在看 diff 之前我自己的判断基线是:对于引用了被重命名删除的符号的测试,可选方案有 (a) 把引用指向存活的等价符号、(b) 用旧名重新加一个 mock、(c) 换成显式的渲染计数器、(d) 删掉测试。这里 (b) 是错的,(c) 和 (d) 要么丢弃要么重复已有的可用机制,所以我会选 (a)——而 PR 正是这么做的。

随后我核实了 (a) 成立的各个前提,而不是想当然:

  • mockUseDaemonSessionActivityBridge 声明在顶层 vi.hoisted() 块中(App.test.tsx:250),因此处于模块作用域、在 28940 行可以解析——故障原因是缺少声明,不是作用域或提升问题。
  • vi.mock('./session-catalog/session-catalog-hooks') 工厂把 useDaemonSessionActivityBridge 映射到该 mock(App.test.tsx:1625),并且完全不导出 useDaemonActivePromptBridge。这正是方案 (b) 行不通的原因:用旧名新建的 mock 永远不会被调用,expect(...).toHaveBeenCalled() 会失败,而不是报 ReferenceError
  • App.tsx:3304 在组件体内、与其他钩子并列调用 useDaemonSessionActivityBridge(...),因此 App 每次渲染都会触发它。
  • 除定义模块外,它是该钩子唯一的生产调用方。ChatPane.tsx 用的是兼容包装 useDaemonActivePromptBridge,而 App.tsx 只以 import type 方式引入 ChatPane(App.tsx:175),所以 ChatPane 在本套件中根本不会渲染,也就不可能触发这个探针。因此该 mock 是 App 独占的,not.toHaveBeenCalled() 确实表示"App 没有重渲染",而不是"任何地方都没重渲染"。
  • 顶层 beforeEachApp.test.tsx:9324)执行 mockReset()mockImplementation:9393:9394),所以每个测试变体的调用计数都从零开始,"先清空再断言"的序列是有意义的。

结论:修复后的测试度量的仍是它原本要度量的东西,而且不是空测试——它在 28940 行的正向断言会在探针失效时大声失败,所以一个悄悄死掉的探针不可能通过。

测试证据

本次为无人值守 CI 运行(GITHUB_EVENT_NAME=pull_request_target),因此下面的证据是通过 API 读取的 PR 自身 CI 结果。我没有构建、运行或检出任何来自 PR 的代码——没有跑 vitest,没有 gh pr checkout,没有执行 diff 中的脚本。

这里关键的通道确实覆盖了本次改动:Test (ubuntu-latest, Node 22.x) 运行 npm run test:ci:workspacesci.yml:764),它会展开到所有定义了 test:ci 脚本的 workspace,而 packages/web-shell 的定义是 vitest run --config vitest.config.tspackages/web-shell/package.json:34)。所以 Test 通道变绿是"两个此前损坏的变体已能执行并通过"的直接证据,而不是间接指标。需要说明的是,最初发现该问题的通道——发布工作流的 Workspace Tests (2/3)——在 pull request 上并不运行;PR CI 的 Test 通道就是它的等价覆盖。

截至撰写时没有任何失败:9 项通过、13 项跳过、5 项仍在运行——其中包括 Test (ubuntu-latest, Node 22.x)Lint & Static (ubuntu-latest, Node 22.x)。我没有轮询或 sleep 等待(单元测试套件的耗时超过任何合理的等待预算);CI 结束后 Qwen Triage Finalize 任务会就地改写下方表格。被跳过的通道——Test (macos-latest…)Test (windows-latest…)Integration Tests (CLI, No Sandbox)verifytmux-testing——是本仓库 PR 分类的结果,不是红灯。

(CI 表格见上方英文部分,未重复粘贴。)

沙箱验证可以解决绿色套件无法解决的那一点:@qwen-code /verify —— 用以确认修复后的测试是承重的,即如果把 App 改成在外来会话的 pending-panes 上报时重渲染,该测试会再次失败。支持这一点的变异测试是作者的说法,不是我复跑的结果;而一个在断言存在与否两种情况下都同样通过的套件什么都证明不了。我把这一点评为低风险而非不重要:上面的静态链条(App 独占探针、每次渲染都调用、每个测试前重置,再加上测试自身的正向断言)已经让"探针死掉"不可能发生,所以 /verify 只是确认结构已经蕴含的结论。

真实场景 tmux 测试:N/A —— 本次为无人值守 CI 运行,且没有用户可见改动:diff 不涉及任何产品代码,因此没有可驱动的终端界面。

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

Reviewed at 34e6ea308ba672aab80d11242e0e4ef0feceb723 · re-run with @qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Confidence: 5/5 — clean at every stage; the only thing between this and merge is CI landing, which the deferred approval below handles.

Stepping back: this is the easy case that still deserves the hard look, because "obvious three-line test fix" is exactly where a silently-wrong repair sails through. The failure mode that matters for a rename repair is not "does it compile" — it is "does the test still measure what it claims to measure". I went looking for that specifically and it isn't present: the substituted mock is wired to the hook App calls on every render, nothing else in the suite can reach it, it is reset before each test, and the test's own positive assertion would fail loudly if the sensor ever went dead. So the repaired test is neither vacuous nor measuring something new.

The part I'd normally expect to go unchecked, and which turned out to be the interesting one: re-adding a mock under the old name — the "restore what was deleted" instinct — would have been affirmatively wrong here, not just larger, because the module mock no longer exports that hook name at all. Pulling #11267's diff settled it. That commit renamed this same symbol in five other places in this very file; these three lines arrived five hours later via #11250, which is why they were missed. The PR is the same rename completed, nothing more.

Everything in the diff is necessary: there are exactly three occurrences of the dead symbol in the entire repository and the PR changes exactly those three. No drive-by edits, no formatting churn, no scope creep. In six months this reads as a test that names the hook the code actually uses — I'd thank the author, not curse them.

Two honest caveats, neither blocking:

  • I have not seen this run. Test (ubuntu-latest, Node 22.x) — the lane that executes the repaired file — was still in progress when I wrote this, and I did not poll it. My confidence rests on the static chain above plus the fact that the lane genuinely covers packages/web-shell; the green suite is what the deferred approval is waiting for.
  • The mutation probe (that the test fails again if App is made to re-render on foreign-session reports) is the author's claim and I did not re-run it. I judged it structurally sound rather than independently confirmed, and named @qwen-code /verify in the Stage 2 comment as the lane that would close it.

On the gate's usual skepticism: I checked whether I was being worn down or being a pushover, and neither applies — this is one PR against one named failing release run (#11409), from the repo's own autofix pipeline, and I verified the problem exists myself instead of accepting the framing. A repo-wide search for the dead symbol returning three hits, all of them the changed lines, is about as direct as evidence gets.

What this PR deliberately does not do is prevent the next one: required checks ran green on #11250's pre-merge head while a rename landed on main underneath it, so the combined tree was never validated before the nightly hit it. That is a real recurring exposure and the description is right to scope it out of a release-unblocking fix — but it should not be dropped. A separate issue on post-merge or merge-queue validation is worth opening, and I've flagged it in the Stage 1 comment.

Approval is deferred until CI lands green on 34e6ea308ba672aab80d11242e0e4ef0feceb723; the finalize job posts the commit-pinned approval then, and withholds it if anything lands red or the head moves.

中文说明

Confidence: 5/5 —— 各阶段均无问题;距离合并只差 CI 跑完,这由下方的延迟审批处理。

退一步看:这是那种看起来简单、但仍然值得认真看的案例,因为"显而易见的三行测试修复"正是一个悄悄错误的修复最容易蒙混过关的地方。重命名类修复真正要防的失败模式不是"能不能编译",而是"这个测试是否仍在度量它声称度量的东西"。我专门去找了这一点,它不存在:被替换的 mock 接线到 App 每次渲染都会调用的钩子,套件中没有别的东西能触达它,它在每个测试前被重置,而且测试自身的正向断言会在探针失效时大声失败。所以修复后的测试既不是空测试,也没有在度量新的东西。

通常最可能被漏掉、而这次恰恰最有意思的一点是:用旧名重新加一个 mock——那种"把被删掉的东西恢复回来"的直觉——在这里是明确错误的,而不只是改动更大,因为模块 mock 已经完全不导出那个钩子名了。拉取 #11267 的 diff 确认了这一点。该提交在同一个文件里另外五处也改了同一个符号;而这三行是五小时后随 #11250 才进来的,所以被漏掉了。本 PR 就是把同一次重命名补齐,仅此而已。

diff 中每一处改动都是必要的:整个仓库里那个失效符号恰好只有三处出现,PR 改的正是这三处。没有顺手改动,没有格式化噪音,没有范围蔓延。六个月后回看,这就是一个"测试名字与代码实际使用的钩子一致"的状态——我会感谢作者,而不是骂他。

两点如实说明,均不阻塞:

  • 我没有看到它实际跑起来。Test (ubuntu-latest, Node 22.x)——也就是执行被修复文件的那条通道——在我撰写时仍在进行中,我没有轮询它。我的信心建立在上面的静态链条,以及该通道确实覆盖 packages/web-shell 这一事实上;绿色套件正是延迟审批在等的东西。
  • 变异测试(即把 App 改成在外来会话上报时重渲染,测试会再次失败)是作者的说法,我没有复跑。我的判断是它在结构上成立,而非独立确认,并已在 Stage 2 评论中点名 @qwen-code /verify 作为可以闭环的通道。

关于门禁惯常的怀疑态度:我检查了自己是否被消耗、或是否在做老好人,两者都不成立——这是针对一个具名失败发布运行(#11409)的单个 PR,来自本仓库自己的 autofix 流水线,而且我是自己核实了问题确实存在,而不是接受它的叙述框架。全仓搜索那个失效符号返回三处命中、且全部是被改动的行,这已经是相当直接的证据了。

本 PR 有意没有做的事,是防止下一次同类问题:必需检查在 #11250 合并前的 head 上是绿的,而一次重命名在其下方合入了 main,所以合并后的代码树在每夜发布撞上之前从未被验证过。这是一个真实且会复发的暴露面,描述把它划出一个"解阻发布"的修复之外是正确的——但不应该就此丢掉。另开一个关于合并后校验或 merge queue 的 issue 是值得的,我已在 Stage 1 评论中提出。

审批延迟至 CI 在 34e6ea308ba672aab80d11242e0e4ef0feceb723 上全绿后执行;届时 finalize 任务会发布绑定该提交的审批,若有红灯或 head 变动则会撤回不发。

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

Reviewed at 34e6ea308ba672aab80d11242e0e4ef0feceb723 · re-run with @qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

🖼️ web-shell visual preview

Rendered against a mock daemon (no real backend): the PR base vs this PR head 34e6ea3. Only screenshots that changed are shown (flows below, if any, are head-only) — refreshes on every push.

Screenshots · before / after

terminal-turn-error-copy-narrow-dark before/after

Full-resolution recordings (.webm) are attached to the workflow run.

Qwen Code · web-shell visuals

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

LGTM, looks ready to ship — CI landed green after the review. ✅

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

Partially reviewed — gaps disclosed.

Not explored to full depth (tool budget reached): "agent 6c": mutation run of the *unmodified* test with rerender() removed, to confirm whether the loop negatives alone already catch that drop (I only ran that mutation o…; "agent 6c": npm run typecheck and npm run lint for packages/web-shell at HEAD — correctness was checked by grep over the repo plus the full vitest run of App.test.ts…; "agent 4": none — I did not run the full App.test.tsx suite (only the two filtered cases), since the other 794 tests are outside this diff and the file's whole-suite run….

Not reviewed: reverse audit — stopped before round 1 by the review time budget.

中文说明

仅完成部分审查,审查缺口已披露。

未探索到全部深度(达到工具调用预算):"agent 6c"mutation run of the *unmodified* test with rerender() removed, to confirm whether the loop negatives alone already catch that drop (I only ran that mutation o…"agent 6c"npm run typecheck and npm run lint for packages/web-shell at HEAD — correctness was checked by grep over the repo plus the full vitest run of App.test.ts…"agent 4"none — I did not run the full App.test.tsx suite (only the two filtered cases), since the other 794 tests are outside this diff and the file's whole-suite run…

未审查:反向审计——评审时间预算不足,未能开始第 1 轮。

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

@qwen-code-dev-bot

qwen-code-dev-bot commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator Author

AutoFix round 1 finishedview run. See this round's report below.

中文说明

AutoFix 第 1 轮已完成 —— 查看运行。本轮报告见下方。

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下:

Autofix round — no action required

All feedback on this round was triaged; nothing required a code change.

Feedback triage

  • [rv:5148347672] @qwen-code-ci-bot (COMMENTED) — "Partially reviewed — gaps disclosed."
    The automated reviewer's own ledger records zero findings ("findings":[]). The body only discloses review-coverage gaps from its tool budget (an unfinished mutation probe, and typecheck/lint/full-suite runs it did not perform). It requests no change, so there is nothing to implement. The gaps are about review depth, not about the PR: this PR is a 3-line, test-only rename (mockUseDaemonActivePromptBridgemockUseDaemonSessionActivityBridge) in packages/web-shell/client/App.test.tsx, the renamed mock is used consistently throughout the file, and no stale references remain.

  • [ic:5593126723] @qwen-code-ci-bot — web-shell visual preview.
    Informational screenshot-diff notice from the visual-preview workflow (rendered against a mock daemon). The PR touches only a .test.tsx file, which is not part of the web-shell bundle and cannot affect rendered output; the flagged terminal-turn-error-copy-narrow-dark frame is render noise from the mock-daemon comparison, not a regression introduced by this change.

Repository state

  • CI checks on head 34e6ea3: all completed checks are SUCCESS (19) or SKIPPED (48); zero failures, and the "Failed checks" / "Still-red checks" sections are empty.
  • A maintainer-bot review has already APPROVED the PR ("LGTM, looks ready to ship — CI landed green after the review. ✅").
  • No inline review comments exist; no base-branch conflict resolution was requested.

No commit was made; the branch is unchanged.

中文说明

Autofix 本轮处理 —— 无需改动

本轮所有反馈均已分类处理,没有需要进行代码修改的事项。

反馈分类

  • [rv:5148347672] @qwen-code-ci-bot(COMMENTED)——“部分审查 —— 已披露审查缺口”。
    自动审查器自己的审查台账中记录的发现为零("findings":[])。正文仅披露了因其工具调用预算导致的审查覆盖缺口(一个未完成的变异探针,以及它未执行的 typecheck/lint/完整测试套件运行)。它没有要求任何修改,因此没有需要实现的内容。这些缺口关乎审查深度,而非 PR 本身:本 PR 仅在 packages/web-shell/client/App.test.tsx 中进行了 3 行、仅涉及测试的重命名(mockUseDaemonActivePromptBridgemockUseDaemonSessionActivityBridge),重命名后的 mock 在整个文件中用法一致,已无残留的旧引用。

  • [ic:5593126723] @qwen-code-ci-bot —— web-shell 视觉预览。
    这是视觉预览工作流(基于 mock daemon 渲染)发出的信息性截图差异通知。本 PR 只修改了一个 .test.tsx 文件,该文件不属于 web-shell 构建产物,不可能影响渲染输出;被标记的 terminal-turn-error-copy-narrow-dark 画面帧是 mock-daemon 对比产生的渲染噪音,并非本次改动引入的回归。

仓库状态

  • head 34e6ea3 上的 CI 检查:所有已完成的检查均为 SUCCESS(19 个)或 SKIPPED(48 个);零失败,“Failed checks”/“Still-red checks”部分为空。
  • 维护者机器人审查已 APPROVED 该 PR(“LGTM, looks ready to ship — CI landed green after the review. ✅”)。
  • 无任何行内审查评论;也未请求解决与基线分支的冲突。

本轮未提交任何提交;分支保持不变。

Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。


🧠 Handled by Qwen Code · model/模型 kimi-k3 · CLI 0.23.1

@wenshao
wenshao added this pull request to the merge queue Sep 9, 2026
Merged via the queue into main with commit c3023b3 Sep 9, 2026
87 checks passed
@wenshao

wenshao commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Maintainer verification — real local environment

I built a real environment for this PR and ran it: a dedicated worktree at the PR head 34e6ea308b with its own npm ci and a full npm run build, Linux / Node v22.22.2. Every result below is a real vitest run in that worktree, not a reading of the diff.

Verdict: the change itself is correct, but merging it now is a no-op — please close it as superseded by #11406 rather than merging.

git merge-tree --write-tree origin/main 34e6ea308b produces 35a388f06e528fc920ea89394f01e71683f8531b, and git rev-parse origin/main^{tree} is the same hash. Merging this PR would change nothing on main, because #11406 (3a75f37ef5, merged 2026-09-09 00:10:49Z) already landed the identical substitution. Fixes #11409 also points at an issue that is already closed (01:13:34Z).

merge is a no-op


1. The break reproduces exactly, and the fix clears it

On the nightly tree 1f890086f1 the two variants fail with the exact ReferenceError from nightly job 102243304038. On the PR head they pass.

reproduced red

both green

The PR's own full-suite claim holds, and it closes a caveat the PR could not: the full web-shell suite on the pre-fix tree is 1 failed | 287 passed (288) / 2 failed | 6710 passed (6712)those two tests are the only failures in 6712, so this is the complete remedy for the red, not a partial one. PR head and current main are both 288 passed / 6712 passed.

full suite

2. This PR's version is strictly weaker than what main already has

Ten arms, each a real vitest run, crossing three versions of the test file with test-side and production-side mutants:

mutation matrix

Arms 4 and 5 are the finding, and they close the gap the automated review disclosed (agent 6c: "mutation run of the unmodified test with rerender() removed"):

  • This PR (arm 4): delete rerender()1 failed | 1 passed. One variant still passes, because the positive expect(...).toHaveBeenCalled() guard is satisfied by setup-time calls, not by the rerender.
  • main (arm 5): delete rerender()2 failed, and the first failure is the positive guard (spy was NOT called). fix(web-shell): Replace undefined mock in split rerender tests (#11404) #11406's extra mockClear() line is what makes that guard measure the rerender.

A call-count census makes the mechanism explicit: at the positive guard this PR's version sees 6–7 recorded calls (only 1 of them the rerender), while main's version sees exactly 1.

Both versions do detect a genuine production regression — forcing App to rerender on every pending-pane report fails both variants in both versions (arms 8/9), and dropping the owner-session filter in handleSplitPendingPanesChange fails one variant in both (arms 6/7). So this PR is not broken; it is simply the weaker of two fixes for the same line, and main already has the stronger one.

census and gates

3. Two notes on the escape narrative, for the record

a) main's own push lane caught this 2h36m before the nightly. The PR says the nightly "was the first release validation to execute the combined tree" — accurate as worded, but it may read as though nothing saw the break earlier. ci.yml does carry push: branches: [main]; the post-merge run 34257817936 on 70cf363395 started at 17:33:27Z and failed at 18:36:28Z (Test (ubuntu-latest, Node 22.x), job 102182712398) — which is what issue #11404 was filed from, and what #11406 was written against. The nightly at 21:12:10Z was the second signal, not the first.

b) So the CI gap is not a missing gate — it is an unactioned one. The PR scopes out "how a semantic merge conflict reached main" as CI machinery. Worth recording where the real gap sits: the post-merge signal exists and fired correctly; what is missing is anything that blocks a release on it. I confirmed no static gate can substitute — on the broken tree, tsc --noEmit -p packages/web-shell/tsconfig.json exits 0 (the tsconfig excludes client/**/*.test.tsx) and eslint on the file exits 0 (no-undef resolves to [0, {"typeof": false}]). Only running the test catches this class.

timeline

Recommendation

Close #11412 as already fixed by #11406. Merging is harmless (it is provably a no-op), but it adds nothing and the linked issue is already resolved. Had it merged first, it would have left the positive guard satisfiable by setup-time calls — the weaker of the two fixes.

Harness, raw logs for all ten arms, the three full-suite runs and the gate probes: assets-pr11412.

中文版报告

维护者验证 —— 真实本地环境

我为本 PR 搭建了真实环境并实际运行:在 PR head 34e6ea308b 上单独建立 worktree,独立执行 npm ci 与完整 npm run build,环境为 Linux / Node v22.22.2。下面每一条结论都来自该 worktree 中真实的 vitest 运行,而非对 diff 的阅读。

结论:改动本身是正确的,但现在合并它是一个空操作 —— 建议以「已被 #11406 取代」关闭,而不是合并。

git merge-tree --write-tree origin/main 34e6ea308b 得到 35a388f06e528fc920ea89394f01e71683f8531b,而 git rev-parse origin/main^{tree} 是同一个哈希。合并本 PR 不会让 main 发生任何变化,因为 #114063a75f37ef5,已于 2026-09-09 00:10:49Z 合并)已经落地了完全相同的替换。Fixes #11409 指向的 issue 也已经关闭(01:13:34Z)。

merge is a no-op


1. 故障可精确复现,修复确实清除了红灯

在每夜构建的代码树 1f890086f1 上,两个变体以与 nightly job 102243304038 完全相同的 ReferenceError 失败;在 PR head 上它们通过。

reproduced red

both green

PR 自述的完整套件数据成立,并且补上了 PR 自身无法给出的一点:修复前的完整 web-shell 套件为 1 failed | 287 passed (288) / 2 failed | 6710 passed (6712) —— 这两个测试是 6712 个测试中仅有的失败,因此这是对红灯的完整修复,而非部分修复。PR head 与当前 main 均为 288 passed / 6712 passed

full suite

2. 本 PR 的版本严格弱于 main 上已有的版本

十条实验臂,每一条都是真实的 vitest 运行,交叉了三个版本的测试文件与测试侧 / 生产侧变异:

mutation matrix

第 4 与第 5 条是关键发现,它们也补上了自动评审自行披露的缺口(agent 6c"mutation run of the unmodified test with rerender() removed"):

  • 本 PR(第 4 臂):删除 rerender()1 failed | 1 passed。仍有一个变体通过,因为正向断言 expect(...).toHaveBeenCalled() 是被 setup 阶段的调用满足的,而不是被这次重渲染满足的。
  • main(第 5 臂):删除 rerender()2 failed,且首个失败正是正向断言(spy was NOT called)。让该断言真正度量重渲染的,是 fix(web-shell): Replace undefined mock in split rerender tests (#11404) #11406 多出来的那一行 mockClear()

调用计数普查把机制说清楚了:在正向断言处,本 PR 的版本看到 6–7 次已记录调用(其中只有 1 次来自重渲染),而 main 的版本恰好看到 1 次。

两个版本都确实能检测真实的生产退化 —— 强制 App 在每次 pending 面板上报时重渲染,会让两个版本的两个变体全部失败(第 8/9 臂);去掉 handleSplitPendingPanesChange 中的 owner 会话过滤,会让两个版本各失败一个变体(第 6/7 臂)。所以本 PR 并没有错,它只是同一行两种修复中较弱的那一个,而 main 已经拿到了较强的那个。

census and gates

3. 关于「逃逸路径」叙述的两点补充记录

a) main 自身的 push 通道比每夜构建早 2 小时 36 分就抓到了它。 PR 写道每夜构建"是第一个执行合并后代码树的发布验证"——按字面是准确的,但容易被读成此前无人发现。ci.yml 确实带有 push: branches: [main]70cf363395 上的合并后运行 34257817936 于 17:33:27Z 启动,并在 18:36:28Z 失败(Test (ubuntu-latest, Node 22.x),job 102182712398)—— issue #11404 正是据此提交的,#11406 也正是针对它写的。21:12:10Z 的每夜构建是第二个信号,不是第一个。

b) 因此 CI 的缺口不是「缺少门禁」,而是「门禁无人响应」。 PR 把"语义合并冲突如何进入 main"划为 CI 基础设施而排除在外。值得记录真实缺口所在:合并后信号是存在的,也正确地触发了;缺的是任何据此阻断发布的机制。我确认没有静态检查可以替代 —— 在损坏的代码树上,tsc --noEmit -p packages/web-shell/tsconfig.json 退出码为 0(tsconfig 的 exclude 排除了 client/**/*.test.tsx),对该文件运行 eslint 退出码同样为 0no-undef 解析为 [0, {"typeof": false}])。只有真正运行该测试才能抓到这一类问题。

timeline

建议

以「已由 #11406 修复」关闭 #11412 合并是无害的(已证明为空操作),但没有任何增益,且关联 issue 已解决。假如它先被合并,则会留下一个可被 setup 阶段调用满足的正向断言 —— 两种修复中较弱的那个。

测试装置、十条实验臂的原始日志、三次完整套件运行与门禁探测:assets-pr11412

@wenshao

wenshao commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator

Follow-up: merged — nothing to undo, and one correction to my comment above

This landed as c3023b3e6d while the verification above was still running. No action is needed: the merge is an empty commit.

$ git rev-parse c3023b3e6d^{tree}     35a388f06e528fc920ea89394f01e71683f8531b
$ git rev-parse c3023b3e6d~1^{tree}   35a388f06e528fc920ea89394f01e71683f8531b

main is byte-identical before and after — exactly the merge-tree prediction. Nothing to revert (a revert of an empty commit is itself empty and would only add noise), and the stronger guard from #11406 — the extra mockClear() that makes the positive assertion measure the rerender rather than setup-time calls — is untouched. I re-ran the full suite on current main c069801657: 288 files / 6712 tests, all passing.

Correction to my comment above. I wrote that Fixes #11409 pointed at an issue that was "already closed". That was wrong about the cause: #11409 was closed at 01:13:34Z, one second after this merge at 01:13:33Z — it was closed by this PR, not independently beforehand. (#11406 closed #11404, the post-merge-CI issue; #11409 was the separate nightly-release issue and was still open.) This does not change anything else: the merge was still a no-op, and the fix that actually made #11409's test pass had already landed in #11406.

The one item still worth acting on is unrelated to this PR: the post-merge push lane went red on 70cf363395 at 18:36:28Z and nothing blocked the 21:12:10Z nightly on it. Happy to open a separate issue for that if useful.

中文版

后续:已合入 —— 无需回滚,另更正上一条评论中的一处事实

本 PR 在上面的验证仍在进行时以 c3023b3e6d 合入。无需任何处理:这是一个空提交。

$ git rev-parse c3023b3e6d^{tree}     35a388f06e528fc920ea89394f01e71683f8531b
$ git rev-parse c3023b3e6d~1^{tree}   35a388f06e528fc920ea89394f01e71683f8531b

main 在合入前后逐字节相同 —— 与 merge-tree 的预测完全一致。没有需要回滚的内容(对空提交做 revert 本身也是空的,只会增加噪音),而且来自 #11406 的更强断言 —— 那行让正向断言度量重渲染、而非 setup 阶段调用的 mockClear() —— 未受影响。我在当前 main c069801657 上重跑了完整套件:288 文件 / 6712 测试全部通过。

更正上一条评论。 我写道 Fixes #11409 指向的 issue "已经关闭"。这一点的归因是错的:#11409 关闭于 01:13:34Z,比本次合并的 01:13:33Z 晚一秒 —— 它是被本 PR 关闭的,而不是此前独立关闭的。(#11406 关闭的是 #11404,即合并后 CI 的 issue;#11409 是另一个每夜发布的 issue,当时仍处于打开状态。)这不改变其余结论:本次合并仍然是空操作,而真正让 #11409 的测试转绿的修复早已随 #11406 落地。

唯一仍值得处理的一项与本 PR 无关:合并后的 push 通道在 18:36:28Z 就在 70cf363395 上变红,却没有任何机制据此阻断 21:12:10Z 的每夜发布。如有需要,我可以为此单独开一个 issue。

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Released in v0.23.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.

Release Failed for v0.23.1-nightly.20260908.1f890086f1 on 2026-09-08

3 participants