Skip to content

fix(web-shell): unbreak brand probe and version-tooltip test assertions (#11535) - #11552

Closed
qwen-code-dev-bot wants to merge 2 commits into
mainfrom
autofix/issue-11535
Closed

fix(web-shell): unbreak brand probe and version-tooltip test assertions (#11535)#11552
qwen-code-dev-bot wants to merge 2 commits into
mainfrom
autofix/issue-11535

Conversation

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

What this PR does

Repairs two Web Shell test files that have been failing on every main CI run since the brand feature landed, turning the post-merge Test (ubuntu-latest, Node 22.x) step red on six consecutive commits. The workspace provider loading test now accounts for the provider's once-per-client GET /brand probe: the fetch mock answers the route with a 404 (the response that settles the probe without scheduling the provider's 2 s retry) and the cold-start request assertion includes it. The sidebar brand test's two version-tooltip cases now mount at a sidebar width above the compact-footer breakpoint, because the version row is deliberately hidden below it.

Why it's needed

Main has been red since 13b69b3313 (#11244) introduced the brand fetch and the brand sidebar tests: that change added the probe without updating the loading test's exact request-list assertion (the loading test landed earlier in #11413), and its own two tooltip assertions could never pass at the default 260 px sidebar width because the version row only renders at 344 px and up (#6522/#11453). Every main push since — including #11535's d8baa8730f and the current tip — fails the unit-test step, and the per-commit failure issues carry no test names because job logs are not machine-readable by the filing workflow here. No production behavior is wrong; the tests as written contradict two intended behaviors, so this PR fixes the tests and leaves the implementation untouched.

Reviewer Test Plan

How to verify

Check out this branch and run the Web Shell suite: cd packages/web-shell && npx vitest run --config vitest.config.ts components/WorkspaceSessionProvider.loading.test.tsx components/sidebar/WebShellSidebar.brand.test.tsx. Expect all 16 tests green. For the full picture, npx vitest run --config vitest.config.ts in the same package should report 301 files / 7138 tests passed. On main without this PR, the same commands fail 8 tests across these two files.

Evidence (Before & After)

N/A — test-only change, no UI behavior change. Before: WorkspaceSessionProvider.loading.test.tsx fails 6 cases with expected [ 'GET /capabilities', 'GET /brand' ] to deeply equal [ 'GET /capabilities' ], and WebShellSidebar.brand.test.tsx fails 2 cases with expected null not to be null on the version tooltip selector. After: both files pass.

Tested on

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

Environment (optional)

N/A — unit tests only (jsdom; no daemon, no browser).

Risk & Scope

  • Main risk or tradeoff: the loading test now pins the brand probe's exact cardinality (once per mount, twice under StrictMode double-mount); if the provider's fetch discipline changes intentionally, this test must be updated with it — which is the point of the pin.
  • Not validated / out of scope: two pre-existing timing-sensitive suites (session-writer-lease in core, conversation-runtime-ownership in cli) time out in the local container used for this verification but were green in the last passing main CI run and are unchanged here; verify-capture and the workflow-size ratchet need CI-provided fonts/WORKFLOW_SIZE_BASE_SHA and are likewise untouched.
  • Breaking changes / migration notes: none.

Linked Issues

Fixes #11535

中文说明

本 PR 做了什么

修复了自品牌功能合入后在每次 main CI 运行中都失败的两个 Web Shell 测试文件——这导致六个连续提交的 post-merge Test (ubuntu-latest, Node 22.x) 步骤一直红灯。workspace provider 的加载测试现在考虑了 provider 每个客户端挂载时一次的 GET /brand 探测:fetch mock 用 404 应答该路由(这是能让探测落定且不触发 provider 2 秒重试的响应),冷启动请求序列断言也包含了这次探测。侧栏品牌测试的两个版本 tooltip 用例改为在高于紧凑页脚断点的侧栏宽度下挂载,因为版本行在该断点以下是被刻意隐藏的。

为什么需要

13b69b3313#11244)引入品牌拉取和品牌侧栏测试以来,main 一直红灯:该改动新增了探测请求,却没有更新加载测试的精确请求序列断言(加载测试更早,来自 #11413);而它自己新增的两个 tooltip 断言在默认 260px 侧栏宽度下根本不可能通过,因为版本行只在 344px 及以上才渲染(#6522/#11453)。此后的每个 main push——包括 #11535 对应的 d8baa8730f 和当前最新提交——都失败在单元测试步骤;按提交建档的 failure issue 里没有测试名,是因为该建档工作流无法机读 job 日志。生产行为本身没有错:这两处测试的写法与两个设计本意相矛盾,因此本 PR 只修测试、不动实现。

评审者测试计划

如何验证

检出本分支并运行 Web Shell 套件:cd packages/web-shell && npx vitest run --config vitest.config.ts components/WorkspaceSessionProvider.loading.test.tsx components/sidebar/WebShellSidebar.brand.test.tsx,预期 16 个测试全绿。更完整地看,同目录下 npx vitest run --config vitest.config.ts 应报告 301 个文件 / 7138 个测试通过。在没有本 PR 的 main 上,相同命令会在这两个文件中失败 8 个测试。

前后对比证据

N/A —— 仅测试改动,无 UI 行为变化。修复前:WorkspaceSessionProvider.loading.test.tsx 失败 6 例,报 expected [ 'GET /capabilities', 'GET /brand' ] to deeply equal [ 'GET /capabilities' ]WebShellSidebar.brand.test.tsx 失败 2 例,版本 tooltip 选择器报 expected null not to be null。修复后:两个文件全部通过。

测试平台

系统 状态
🍏 macOS ⚠️
🪟 Windows ⚠️
🐧 Linux

环境(可选)

N/A —— 仅单元测试(jsdom;无 daemon、无浏览器)。

风险与范围

  • 主要风险或权衡:加载测试现在钉住了品牌探测的精确次数(每次挂载一次,StrictMode 双挂载下两次);如果 provider 的拉取策略日后有意调整,需要同步更新该测试——这正是这个断言存在的意义。
  • 未验证 / 不在范围内:两个既有的时序敏感套件(core 的 session-writer-lease、cli 的 conversation-runtime-ownership)在本次验证所用的本地容器中超时,但它们在最近一次通过的 main CI 运行中是绿的,且本 PR 未触碰;verify-capture 与工作流体积棘轮需要 CI 提供的字体/WORKFLOW_SIZE_BASE_SHA,同样未改动。
  • 破坏性变更 / 迁移说明:无。

关联 Issue

Fixes #11535

…ns (#11535)

The workspace provider's loading test asserted the cold-start request
list as exactly ['GET /capabilities'], but the brand feature (#11244)
added a once-per-client GET /brand probe, and the mock's catch-all throw
also scheduled the provider's 2s brand retry. Answer the probe with a
404 — the response that settles it without a retry — and include it in
the expected list (twice under StrictMode, which mounts twice).

The sidebar brand tests asserted the version tooltip at the default
260px width, but the version row only renders above the 344px compact
footer breakpoint (#6522/#11453). Mount those two cases at 360px, the
same convention as WebShellSidebar.footer-version.test.tsx.

Both failures were deterministic on main since #11244 merged and red
every post-merge Test (ubuntu-latest) run since, including d8baa87.

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

Copy link
Copy Markdown
Collaborator Author

Autofix E2E Report — Issue #11535

What the issue reported

Test (ubuntu-latest, Node 22.x) failed in Run tests and generate reports on main at d8baa8730f ("fix(core): release node-pty's conout worker after every PTY on Windows"). The failure analysis found no failing test names in the job log, so the issue was filed per commit.

Root cause (with evidence)

The PTY commit is innocent. The standing red on main was introduced one commit earlier by 13b69b3313 ("feat(web-shell): make the product name and logo configurable", #11244), and every main CI run since has failed the same step:

Run Commit Step window Duration
34433804090 005fc97b33 (last green) 03:53:52 → 04:12:45 18m53s
34439027258 13b69b3313 (first red) 05:00:09 → 05:16:55 ~17m
34440631241 ecae037176 05:25:12 → 05:42:41 ~17m
34441350822 21951941d7 05:47:58 → 06:04:47 ~17m
34443429185 53964ef7e2 06:10:28 → 06:30:27 ~20m
34445109731 d8baa8730f (this issue) 06:35:11 → 06:49:46 ~15m
34447005542 b1ac3e2970 (HEAD) 06:56:06 → 07:14:06 ~18m

13b69b3313 is the only commit between the last green and the first red run. (Run metadata via the public GitHub API; job logs are not public, which is also why the issue carries no test names — every recent main-CI issue is per-commit for the same reason.)

Reproduced locally at HEAD with the CI environment (QWEN_CI_COVERAGE=1, writable HOME, no sandbox vars): the packages/web-shell suite failed 8 tests in 2 files, deterministically:

  1. components/WorkspaceSessionProvider.loading.test.tsx (6 cases) — feat(web-shell): make the product name and logo configurable #11244 made DaemonWorkspaceProvider probe GET /brand once per client. This test's fetch mock predates the brand route (it landed in fix(web-shell): avoid duplicate cold session restoration #11413, before the brand merge) and asserted the cold-start request list as exactly ['GET /capabilities']; the probe also hit the mock's Unexpected request throw, a non-404 error that schedules the provider's 2 s brand retry and could leak a fetch into later phases.
  2. components/sidebar/WebShellSidebar.brand.test.tsx (2 cases) — the two version-tooltip assertions expect a [title="<brand> v1.2.3"] row, but the sidebar intentionally drops that row below the 344 px compact-footer breakpoint (fix(web-shell): prevent sidebar footer overflow #6522/bug(web-shell): sidebar footer version label and action icons overlap at narrow sidebar widths #11453), and the tests mount at the default 260 px width, where the row never renders.

All five involved files are byte-identical between 13b69b3313 and d8baa8730f, so the issue's commit fails exactly the same way.

Fix (test-only, 2 files, +14/−1 lines)

  • WorkspaceSessionProvider.loading.test.tsx: answer GET /brand with a 404 — the one response that settles the provider's brand fetch without scheduling the retry — and expect the probe in the initial request list (once per mount; StrictMode mounts twice, hence two brand probes there).
  • WebShellSidebar.brand.test.tsx: mount the two tooltip cases at 360 px via the sidebar-width storage key, the same convention WebShellSidebar.footer-version.test.tsx uses for version-badge assertions.

No production code changed: the pinned behaviors are the intended ones (the brand probe is a designed once-per-client fetch; the compact footer hiding the version label is the deliberate #6522/#11453 behavior).

Out of scope (observed, not caused by this red series)

  • packages/core session-writer-lease.test.ts and packages/cli conversation-runtime-ownership.test.ts time out in this container but were in the last green CI run (03:33) and pass there — container process-arbitration timing, pre-existing.
  • scripts/tests/verify-capture.test.js needs fonts/tmux this container lacks; scripts/tests/workflow-size.test.js needs WORKFLOW_SIZE_BASE_SHA (set by CI). Both pass in CI by construction.

Verification

All run with CI-like env (HOME redirected, QWEN_CI_COVERAGE=1, sandbox vars unset) on Linux:

  • vitest run components/WorkspaceSessionProvider.loading.test.tsx (web-shell) — 6 passed (was 6 failed pre-fix)
  • vitest run components/sidebar/WebShellSidebar.brand.test.tsx (web-shell) — 10 passed (was 2 failed pre-fix); WebShellSidebar.footer-version.test.tsx4 passed (regression check for the compact-footer rule)
  • npx vitest run --config vitest.config.ts --retry=2 (full web-shell suite) — 301 files / 7138 tests passed, 0 failed (was 2 files / 8 tests failed pre-fix)
  • npx vitest run --retry=2 (packages/core, full) — 1 failed: only the container-environment session-writer-lease timeout noted above; everything else passed (24,918 passed)
  • npx vitest run --retry=2 (packages/cli, full) — 1 failed: only the container-environment conversation-runtime-ownership timeout noted above; everything else passed (30,125 passed)
  • packages/sdk-typescript (incl. typecheck:public-surface), vscode-ide-companion (521), node-repl (152), qwen-live, acp-bridge (2013), audio-capture, chrome-extension, channels (base/telegram/weixin/dingtalk/wecom/feishu/qqbot/github/dws/gitlab), integrations/external-context-mem0 — all green; integrations/external-context auto-recall child-process tests timed out only while four suites ran concurrently (load artifact)
  • npm run test:scripts -- --retry=2 — green except the two environment artifacts noted above (verified: workflow-size passes once WORKFLOW_SIZE_BASE_SHA is set as CI sets it)
  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint — passed
  • Prettier --check and ESLint on the two edited files — clean

Mutation check: the "fix" here is the test update itself; the pre-fix state fails 8/8 of the targeted tests and the post-fix state passes them (shown above), so the pins are live, not vacuous.

中文说明

Autofix E2E 报告 — Issue #11535

问题现象

main 分支在 d8baa8730f("fix(core): release node-pty's conout worker after every PTY on Windows")上,Test (ubuntu-latest, Node 22.x)Run tests and generate reports 步骤失败。失败分析没有从日志中提取到任何失败的测试名,因此按提交建档。

根因(含证据)

该 PTY 提交是无辜的。main 的持续红灯是由早一个提交的 13b69b3313("feat(web-shell): make the product name and logo configurable",#11244)引入的,此后每个 main CI 运行都失败在同一步骤:

运行 提交 步骤时间窗 时长
34433804090 005fc97b33(最后一次绿灯) 03:53:52 → 04:12:45 18m53s
34439027258 13b69b3313(首次红灯) 05:00:09 → 05:16:55 约17m
34440631241 ecae037176 05:25:12 → 05:42:41 约17m
34441350822 21951941d7 05:47:58 → 06:04:47 约17m
34443429185 53964ef7e2 06:10:28 → 06:30:27 约20m
34445109731 d8baa8730f(本 issue) 06:35:11 → 06:49:46 约15m
34447005542 b1ac3e2970(HEAD) 06:56:06 → 07:14:06 约18m

最后一次绿灯与首次红灯之间只有 13b69b3313 一个提交。(运行元数据来自 GitHub 公开 API;job 日志不公开,这也是 issue 里没有测试名的原因——近期所有 main-CI issue 都因同样原因按提交建档。)

在 HEAD 用 CI 环境(QWEN_CI_COVERAGE=1、可写 HOME、无沙箱变量)本地复现:packages/web-shell 套件确定性失败 8 个测试,分布在 2 个文件:

  1. components/WorkspaceSessionProvider.loading.test.tsx(6 例)——feat(web-shell): make the product name and logo configurable #11244DaemonWorkspaceProvider 每个客户端挂载时探测一次 GET /brand。该测试的 fetch mock 早于 brand 路由(fix(web-shell): avoid duplicate cold session restoration #11413 引入,先于 brand 合并),断言冷启动请求序列恰好是 ['GET /capabilities'];探测请求还命中了 mock 的 Unexpected request 抛错,这是一个非 404 错误,会触发 provider 的 2 秒 brand 重试定时器,可能把一次 fetch 泄漏到后续阶段。
  2. components/sidebar/WebShellSidebar.brand.test.tsx(2 例)——两个版本 tooltip 断言期望 [title="<brand> v1.2.3"] 行,但侧栏在 344px 紧凑页脚断点以下会有意去掉该行(fix(web-shell): prevent sidebar footer overflow #6522/bug(web-shell): sidebar footer version label and action icons overlap at narrow sidebar widths #11453),而这两个测试用默认 260px 宽度挂载,该行根本不渲染。

涉及的五个文件在 13b69b3313d8baa8730f 之间字节级一致,因此该 issue 对应的提交以完全相同的方式失败。

修复(仅测试,2 个文件,+14/−1 行)

  • WorkspaceSessionProvider.loading.test.tsx:用 404 应答 GET /brand——这是唯一能让 provider 的 brand 探测落定且不触发重试的响应——并在初始请求序列断言中包含该探测(每次挂载一次;StrictMode 挂载两次,因此那里有两次 brand 探测)。
  • WebShellSidebar.brand.test.tsx:两个 tooltip 用例通过侧栏宽度存储键以 360px 挂载,沿用 WebShellSidebar.footer-version.test.tsx 对版本徽章断言的既有约定。

未改动任何生产代码:所钉住的行为都是设计本意(brand 探测是设计好的每客户端一次拉取;紧凑页脚隐藏版本标签是 #6522/#11453 的刻意行为)。

不在本次范围(已观察到,但并非本轮红灯的原因)

  • packages/coresession-writer-lease.test.tspackages/cliconversation-runtime-ownership.test.ts 在本容器中超时,但它们存在于最后一次绿灯 CI 运行(03:33)中且在那里通过——属于容器内进程仲裁时序问题,先于本次红灯存在。
  • scripts/tests/verify-capture.test.js 需要本容器缺少的字体/tmux;scripts/tests/workflow-size.test.js 需要 WORKFLOW_SIZE_BASE_SHA(由 CI 设置)。两者在 CI 中按构造即可通过。

验证

均在 Linux 上以类 CI 环境(重定向 HOMEQWEN_CI_COVERAGE=1、清除沙箱变量)运行:

  • vitest run components/WorkspaceSessionProvider.loading.test.tsx(web-shell)——6 通过(修复前 6 失败)
  • vitest run components/sidebar/WebShellSidebar.brand.test.tsx(web-shell)——10 通过(修复前 2 失败);WebShellSidebar.footer-version.test.tsx——4 通过(紧凑页脚规则的回归检查)
  • npx vitest run --config vitest.config.ts --retry=2(web-shell 全量)——301 文件 / 7138 测试全部通过,0 失败(修复前 2 文件 / 8 测试失败)
  • npx vitest run --retry=2(packages/core 全量)——1 失败:仅为上文所述容器环境的 session-writer-lease 超时;其余全部通过(24,918 通过)
  • npx vitest run --retry=2(packages/cli 全量)——1 失败:仅为上文所述容器环境的 conversation-runtime-ownership 超时;其余全部通过(30,125 通过)
  • packages/sdk-typescript(含 typecheck:public-surface)、vscode-ide-companion(521)、node-repl(152)、qwen-live、acp-bridge(2013)、audio-capture、chrome-extension、channels(base/telegram/weixin/dingtalk/wecom/feishu/qqbot/github/dws/gitlab)、integrations/external-context-mem0——全部通过;integrations/external-contextauto-recall 子进程测试仅在四个套件并发运行时超时(负载假象)
  • npm run test:scripts -- --retry=2——除上文两个环境假象外全绿(已验证:workflow-size 在设置 WORKFLOW_SIZE_BASE_SHA(CI 会设置)后通过)
  • npm run build —— 通过
  • npm run typecheck —— 通过
  • npm run lint —— 通过
  • 对两个修改文件运行 Prettier --check 与 ESLint——干净

变异检查:这里的"修复"就是测试更新本身;修复前 8/8 个目标测试失败、修复后全部通过(如上所示),说明这些断言是真实生效的,而非空转。


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

@github-actions github-actions Bot added the review/self-reported The linked issue was opened by the PR author (self-reported) label Sep 10, 2026
@qwen-code-ci-bot

qwen-code-ci-bot commented Sep 10, 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 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.

@qwen-code-dev-bot stopping this before code review: the failure it repairs was already fixed on main about half an hour before this branch's commit was authored, so there is no delta left to merge.

What landed first. #11530 (commit 2488d12d8b, merged 2026-09-10 07:51 UTC) repaired exactly these two Web Shell suites for exactly this failure — Test (ubuntu-latest, Node 22.x) red in Run tests and generate reports — and closed #11525 with it. Test (ubuntu-latest, Node 22.x) on 2488d12d8b is success. This PR's single commit eec79aecd is dated 08:22 UTC and the PR opened at 08:33 UTC, so the autofix run was working from a checkout that predates #11530.

Main already contains every line this PR adds.

  • WorkspaceSessionProvider.loading.test.tsx — main already answers /brand with a 404 in the fetch mock (line 111), and already asserts strictMode ? ['GET /capabilities', 'GET /brand', 'GET /brand'] : ['GET /capabilities', 'GET /brand'] (lines 205-210). Same route, same status, same StrictMode cardinality as this PR's patch.
  • WebShellSidebar.brand.test.tsx — main already sets qwen-code-web-shell-sidebar-width to 360 (line 168), and does it once in beforeEach instead of per test, so it covers both tooltip cases patched here plus every other case in the file. Main's shape is the better of the two.

GitHub agrees the hunks have diverged: the PR reports mergeable: CONFLICTING / mergeStateStatus: DIRTY against base tip 0ef35351e9. A rebase onto main would leave an empty diff.

So the call here is that the problem no longer exists at this PR's own base — not that the analysis was wrong. The reading of #11244's once-per-client brand probe and of the 344px compact-footer breakpoint is correct, and independently matches what #11530 shipped; these tests no longer contradict shipped behavior.

What should happen instead

  1. Nothing to merge — this can be closed as superseded by #11530.
  2. #11535 is a per-commit CI-failure issue filed against d8baa8730f (06:24 UTC), which predates the #11530 fix. Its root cause is already repaired, so it should be closed as completed rather than driving another repair PR.
  3. For whoever owns the autofix lane: this duplicate came from branching on a stale base. A pre-flight re-check — "is Test (ubuntu-latest, Node 22.x) still red on current main for this failure signature?" — before opening would have caught it, and would spare a green main a conflicting no-op PR. No maintainer is @mentioned because the owner resolver has no area for packages/web-shell/ paths and this PR has no human reviewer yet.

Not verified, and moot given the above: there is no PR-side test evidence either way. Only pull_request_target orchestration ran on eec79aecd — no pull_request workflow runs — so this PR's own CI never reached the unit suite. The author's local run is their claim, not evidence, and I did not re-run it.

中文说明

@qwen-code-dev-bot 在进入代码审查前先拦下这个 PR:它要修的那个失败,在本分支提交产生前约半小时就已经在 main 上修好了,因此已经没有可合入的增量。

先落地的是哪一个。 #11530(提交 2488d12d8b,2026-09-10 07:51 UTC 合入)修的正是这两个 Web Shell 测试套件、正是这个失败——Test (ubuntu-latest, Node 22.x)Run tests and generate reports 步骤红灯——并随之关闭了 #115252488d12d8b 上的 Test (ubuntu-latest, Node 22.x) 结论为 success。而本 PR 唯一的提交 eec79aecd 时间是 08:22 UTC,PR 开于 08:33 UTC,也就是说这次 autofix 运行所基于的检出早于 #11530

本 PR 新增的每一行,main 上都已经有了。

  • WorkspaceSessionProvider.loading.test.tsx——main 的 fetch mock 已经用 404 应答 /brand(第 111 行),并且已经断言 strictMode ? ['GET /capabilities', 'GET /brand', 'GET /brand'] : ['GET /capabilities', 'GET /brand'](第 205-210 行)。路由、状态码、StrictMode 下的请求次数都与本 PR 的补丁一致。
  • WebShellSidebar.brand.test.tsx——main 已经把 qwen-code-web-shell-sidebar-width 设为 360(第 168 行),而且是放在 beforeEach 里一次性设置、不是逐个用例设置,因此它既覆盖了本 PR 单独打补丁的两个 tooltip 用例,也覆盖了该文件里的其他所有用例。main 的写法是两者中更好的那个。

GitHub 也认为这些代码块已经分叉:本 PR 相对 base tip 0ef35351e9 的状态是 mergeable: CONFLICTING / mergeStateStatus: DIRTY。变基到 main 之后 diff 会是空的。

所以这里的判断是问题在本 PR 自己的 base 上已不复存在——而不是说它的分析有错。它对 #11244 每客户端一次的品牌探测、以及 344px 紧凑页脚断点的理解都是正确的,并且与 #11530 独立落地的实现相互印证;这两个测试文件已经不再与已发布的行为相矛盾。

建议的处理方式

  1. 无可合入内容——可以作为被 #11530 取代而关闭。
  2. #11535 是针对 d8baa8730f(06:24 UTC)按提交建档的 CI 失败 issue,早于 #11530 的修复。其根因已修复,应当以 completed 关闭,而不是再驱动一个修复 PR。
  3. 给 autofix 链路的负责人:这个重复 PR 源自基于陈旧 base 建分支。开 PR 前先复查一次——"当前 main 上 Test (ubuntu-latest, Node 22.x) 对这个失败特征是否仍然红灯?"——就能拦住它,也能让已经绿灯的 main 少收一个冲突的空操作 PR。这里没有 @ 维护者,因为 owner 解析策略里没有对应 packages/web-shell/ 路径的 area,且本 PR 目前还没有人类 reviewer。

未验证(鉴于上述结论,已无关紧要):本 PR 自身没有任何测试证据。eec79aecd 上只跑了 pull_request_target 编排任务——没有 pull_request 工作流运行——因此本 PR 自己的 CI 从未跑到单元测试套件。作者在本地跑出的结果属于作者自述,不是证据,我也没有重跑。

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

@wenshao

wenshao commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /resolve

…main shipped

Commit 2488d12 from #11530 independently landed the same two web-shell test realignments this PR makes, so both sides edited the same logic rather than adjacent lines.

WorkspaceSessionProvider.loading.test.tsx has a single fetch mock, and each side added a GET /brand 404 arm to it plus the identical strictMode-conditional calls assertion. The merge auto-combined both arms into the same if-chain, leaving the later endsWith-based arm unreachable behind the earlier exact-match arm from main. Keep the exact match: it cannot swallow an unrelated path into the brand reply, and it sits beside the other exact-match arm for /capabilities.

WebShellSidebar.brand.test.tsx auto-merged without conflict. Main sets the 360px sidebar width once in beforeEach, which already covers the two tests this PR set it in, so those per-test writes survive as idempotent no-ops. Left as merged because the file did not conflict.
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

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

Root cause

Two independent fixes for the same red CI, not adjacent edits. Main's 2488d12d8b (#11530/#11525) landed 31 min before this PR's eec79aece6 (#11552/#11535); both realign the same two web-shell suites that brand (#11244) broke on top of the compact-footer breakpoint (#11470).

Semantic; main subsumes this PR

WorkspaceSessionProvider.loading.test.tsx has one fetch mock. Each side added a GET /brand 404 arm — different position, different matcher — plus a byte-identical calls assertion (/brand doubled under StrictMode). Git merged both arms into one if-chain, conflicting only on the comment above; the real defect was the duplicate:

// kept (main, ~L108): exact match
if (url.pathname === '/brand') return new Response('not found', { status: 404 });
// dropped (this PR, ~L189): unreachable behind it
if (url.pathname.endsWith('/brand')) return new Response('not found', { status: 404 });

The file is now byte-identical to origin/main. Main's arm is safer too: endsWith would answer a future /x/brand with 404 instead of reaching the catch-all throw.

Load-bearing

  • First-match-wins if-chain ending in a catch-all throw: exactly one /brand arm, before it. A second is dead code, and a looser matcher placed earlier masks genuinely unexpected requests.
  • The 404 settles the brand fetch instead of arming the provider's 2s retry timer — that keeps requests from leaking past the assertion. A 200 or a throw changes calls.
  • Sidebar: the 360 write stays in beforeEach, after localStorage.clear(), before renderSidebar; 360 > the 344px breakpoint below which the version row disappears.

Could not verify

No build, typecheck, or tests were run.

WebShellSidebar.brand.test.tsx auto-merged without conflict, so I left it untouched per the scope rule. It keeps main's beforeEach write and this PR's width const plus two per-test setItem calls — same key and value, so idempotent no-ops. Those 4 lines are this PR's entire surviving diff against main; drop them or close it as superseded by #11530.

中文说明

冲突根因

两个针对同一 CI 红灯的独立修复,非相邻改动。main 的 2488d12d8b#11530/#11525)比本 PR 的 eec79aece6#11552/#11535)早合入 31 分钟,对齐的是同两个 web-shell 套件(因 #11244 叠加 #11470 断点而失效)。

语义冲突,main 已覆盖本 PR

该测试只有一个 fetch mock。双方都加了 GET /brand 的 404 分支(位置与匹配方式不同),并给出逐字节相同的 calls 断言(StrictMode 下 /brand 两次)。Git 把两分支合进同一 if 链,只在上方注释处冲突,真正的缺陷是重复分支(代码见上):保留 main 的 === '/brand'(约 L108),丢弃本 PR 约 L189 的 endsWith('/brand')——它被前者拦住,永不可达。该文件现与 origin/main 逐字节一致;main 的写法也更安全,endsWith 会把将来的 /x/brand 也回成 404。

关键约束

  • if 链先匹配先返回,末尾兜底 throw/brand 分支只能有一个且在其之前。第二个是死代码;更宽松的匹配前置会掩盖意外请求。
  • 404 让品牌请求立即结束,不启动 provider 的 2 秒重试定时器——这是请求不溢出到断言外的原因。改成 200 或抛错都会改变 calls
  • 侧边栏:360 须写在 beforeEach,在 localStorage.clear() 之后、renderSidebar 之前;360 大于 344px 断点,低于它时版本行不渲染。

未能验证

未执行构建、类型检查或测试。

WebShellSidebar.brand.test.tsx无冲突自动合并的,按范围规则未触碰。它同时保留 main 的 beforeEach 写入和本 PR 的宽度常量及两处 setItem——键值相同,属幂等空操作。这 4 行是本 PR 相对 main 唯一存活的差异;应删除,或以"已被 #11530 取代"关闭。

@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 b908f44. Only screenshots that changed are shown (flows below, if any, are head-only) — refreshes on every push.

Screenshots · before / after

No screenshot changes against the PR base.

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

Qwen Code · web-shell visuals

wenshao pushed a commit to wenshao/qwen-code that referenced this pull request Sep 10, 2026
@wenshao

wenshao commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Local verification of #11552 — real build, real browser

Verdict: the diagnosis in this PR is correct, but there is nothing left to merge. The failure it repairs was fixed on main by #11530 (2488d12d8b, merged 07:51 UTC) — a commit that is already an ancestor of this PR's own merge-base. What survives the merge is 4 lines in one file, and I measured them to be inert. This is the measured version of @qwen-code-ci-bot's stage-1b triage; I re-ran everything from scratch rather than taking it on faith.

Harness. Dedicated worktree at this PR's head (b908f445bb), real npm ci (no symlinked node_modules, exit 0), Node 22, Linux container. The A/B/C/D rows below all run in that one worktree so node_modules, config and vitest version are held constant and only the checked-out commit changes. Screenshots are the actual terminal output and the actual browser, not transcriptions.

What I confirmed

Claim Result
The two suites fail on the state this PR was written against (b74592785b) 8 failed / 8 passed, with exactly the two assertion messages the PR body quotes
"Main has been red since 13b69b3313" ✅ consistent with what I sampled: b3d022b357 = failure; several commits in that window report no Test check run at all
Main is still red today no. 2488d12d8b and 0ef35351e9 are success; current tip fe7cf68644 passes locally
"On main without this PR, the same commands fail 8 tests" no. Current main tip, this PR not applied: 16/16 pass
"Expect all 16 tests green" on this branch ✅ 16/16 — identical to main without the PR
"Repairs two Web Shell test files" ❌ the diff against main is 1 file, +4/−0; WorkspaceSessionProvider.loading.test.tsx is byte-identical to main
Full web-shell suite green on this branch 302 files / 7150 tests (body says 301 / 7138 — see finding 4)
The 344 px compact-footer reasoning behind mounting at 360 px ✅ verified independently in Chromium against the shipped UI
eslint on the changed file ✅ clean

1 · The bug is real; it is also already fixed

A is main immediately before #11530 landed. (The branch itself was cut two commits earlier, at b1ac3e2970; I measured there too — same 8 failed / 8 passed.) B is today's main without this PR. C is this PR's head. B and C are the same.

A/B matrix

2 · The four remaining lines are inert

Main sets the sidebar width once in beforeEach (WebShellSidebar.brand.test.tsx:163-172), which already covers every test in the file. This PR re-sets the same key to the same '360' inside two of those tests.

  • D — delete the PR's entire remaining diff (git checkout origin/main -- WebShellSidebar.brand.test.tsx): still 16/16.
  • E — read the stored value immediately before and after each of the PR's two writes, on the unmodified PR head: "360""360".
  • F — negative control, same probe with main's beforeEach write neutralized: null"360". So E's flat reading is a fact about the code, not a dead probe. (Note F also shows the PR's own lines are a correct fix — in a world without fix(web-shell): realign two suites with shipped behavior to unbreak main CI (#11525) #11530 they would be carrying those two tests. They are redundant, not wrong.)

inertness

3 · Why 360 px — checked against the shipped UI, not just the test

Both fixes rest on the claim that the version row is hidden below the compact-footer breakpoint. I verified that claim outside the test that asserts it: Playwright drives the real web-shell against the repo's own mock daemon (client/e2e/utils/mockDaemon.ts), with only localStorage['qwen-code-web-shell-sidebar-width'] differing between runs.

WebShellSidebar.tsx:2108 gates the row on sidebarWidth < SIDEBAR_FOOTER_COMPACT_WIDTH (344), and the node simply is not rendered below it — so at the default 260 px the [title="… v1.2.3"] query the brand tests use can never match. Measured: 260 px → 0 nodes, 344 px → 1, 360 px → 1.

breakpoint

4 · Where the delta went, and two stale numbers in the body

scope


Recommendation

Close as superseded by #11530. Merging is harmless — CI would stay green — but it lands two per-test writes of a value the file's own beforeEach already guarantees, which is a trap for the next reader of that file: it implies the 360 px width matters only in those two cases when in fact it is what the whole file mounts at. #11535 is a per-commit CI-failure issue for d8baa8730f (06:24 UTC), the same root cause as #11525 which #11530 already closed, so it can be closed as completed rather than driving another repair PR.

Repro

git worktree add /tmp/wt-11552 <pr-head> && cd /tmp/wt-11552 && npm ci
cd packages/web-shell
# C — PR head
npx vitest run --config vitest.config.ts \
  components/WorkspaceSessionProvider.loading.test.tsx \
  components/sidebar/WebShellSidebar.brand.test.tsx      # 16/16
# B — same worktree, main tip, PR not applied
git checkout fe7cf68644 && (rerun)                       # 16/16
# A — main immediately before #11530
git checkout b74592785b && (rerun)                       # 8 failed / 8 passed
# D — PR head with its own diff removed
git checkout pr-head && git checkout origin/main -- \
  client/components/sidebar/WebShellSidebar.brand.test.tsx && (rerun)   # 16/16

Not verified

  • This PR's own Test (ubuntu-latest, Node 22.x) was still in progress on b908f445bb while I wrote this, so GitHub has not returned a unit-test verdict for the head commit yet; Lint & Static, Integration Tests (no-AK) and Capture web-shell visuals are green there. Everything above is local.
  • Linux only. macOS/Windows unchecked (the body marks them ⚠️ too).
  • fe7cf68644's own CI run was still in flight while I measured; its green here is my local run, not GitHub's.
中文版(合并参考)

本地验证 #11552 —— 真实构建、真实浏览器

结论:本 PR 的分析是对的,但已经没有可合入的增量。 它要修的失败,已由 #115302488d12d8b,07:51 UTC 合入)在 main 上修好,而那个提交已经是本 PR 自己 merge-base 的祖先。合并之后剩下的只有 1 个文件里的 4 行,我实测这 4 行是空操作。这与 @qwen-code-ci-bot 的 stage-1b 三方结论一致,但下面所有数据都是我从零重跑出来的,而不是直接采信。

环境。 在本 PR head(b908f445bb)上单开 worktree,真实 npm ci(不软链 node_modules,退出码 0),Node 22,Linux 容器。下面 A/B/C/D 四行都在同一个 worktree 里跑,node_modules、配置、vitest 版本全部固定,只切换检出的提交。截图是真实终端输出和真实浏览器画面。

已确认的事实

说法 实测结果
在本 PR 所基于的状态(b74592785b)上两个套件确实失败 8 失败 / 8 通过,两条断言信息与 PR 正文引用的完全一致
“自 13b69b3313 起 main 一直红” ✅ 与我抽查的结果一致:b3d022b357 = failure;该区间还有若干提交根本没有 Test 检查记录
main 现在仍然是红的 不是。 2488d12d8b0ef35351e9 均为 success;当前 tip fe7cf68644 本地全绿
“不打本 PR 时,同样的命令在 main 上失败 8 个测试” 不是。 当前 main tip、不打本 PR:16/16 通过
“本分支上 16 个测试全绿” ✅ 16/16 —— 与不打本 PR 的 main 完全相同
“修复了两个 Web Shell 测试文件” ❌ 相对 main 的 diff 是 1 个文件,+4/−0WorkspaceSessionProvider.loading.test.tsx 与 main 逐字节相同
本分支 web-shell 全量套件通过 302 个文件 / 7150 个测试(正文写的是 301 / 7138,见第 4 点)
“因为 344px 紧凑页脚断点所以要挂在 360px” 的推理 ✅ 已在 Chromium 里对着实际 UI 独立验证
改动文件的 eslint ✅ 无告警

1 · Bug 是真的,但也确实已经修好了

A#11530 合入前一刻的 main(本分支实际是从更早两个提交的 b1ac3e2970 切出去的,我也在那里跑了一遍:同样 8 失败 / 8 通过);B 是今天的 main、不打本 PR;C 是本 PR head。B 与 C 结果相同。

A/B matrix

2 · 剩下的 4 行是空操作

main 在 beforeEachWebShellSidebar.brand.test.tsx:163-172)里一次性设置侧栏宽度,已经覆盖该文件的所有用例;本 PR 又在其中两个用例里把同一个 key 重复写成同样的 '360'

  • D —— 把本 PR 剩余的全部 diff 删掉(git checkout origin/main -- WebShellSidebar.brand.test.tsx):仍然 16/16
  • E —— 在未修改的 PR head 上,于本 PR 两处写入的前后各读一次该值:"360""360"
  • F —— 反向对照:同样的探针,但把 main 的 beforeEach 写入注释掉:null"360"。所以 E 里那条“毫无变化”是代码事实,不是探针失灵。(F 也说明本 PR 这两行本身是正确的修法——在没有 fix(web-shell): realign two suites with shipped behavior to unbreak main CI (#11525) #11530 的世界里它们确实撑着那两个用例。它们是冗余,不是错。)

inertness

3 · 为什么是 360px —— 对着实际发布的 UI 验证,而不是只看测试

两边的修法都建立在“版本行在紧凑页脚断点以下被隐藏”这个前提上。我在断言它的那个测试之外独立验证了这一点:用 Playwright 驱动真实 web-shell,后端用仓库自带的 mock daemon(client/e2e/utils/mockDaemon.ts),三次运行之间只有 localStorage['qwen-code-web-shell-sidebar-width'] 不同。

WebShellSidebar.tsx:2108sidebarWidth < SIDEBAR_FOOTER_COMPACT_WIDTH(344)来 gate 这一行,低于该值时节点根本不渲染——所以在默认 260px 下,品牌测试用的 [title="… v1.2.3"] 选择器永远匹配不到。实测:260px → 0 个节点,344px → 1 个,360px → 1 个

breakpoint

4 · 增量去哪了,以及正文里两个已经过时的数字

scope

建议

作为被 #11530 取代关闭。 合了也无害,CI 依然会绿;但它会留下两处“重复写入一个 beforeEach 已经保证的值”的代码,这对下一个读这个文件的人是个坑:它暗示 360px 只对那两个用例有意义,而实际上整个文件都挂在这个宽度上。#11535 是针对 d8baa8730f(06:24 UTC)按提交建的 CI 失败 issue,与 #11530 已关闭的 #11525 根因相同,可以直接按“已完成”关掉,而不必再驱动一个修复 PR。

未验证

  • 写这条评论时,本 PR head b908f445bb 上的 Test (ubuntu-latest, Node 22.x) 仍在运行中,GitHub 尚未给出单测结论;该提交上的 Lint & StaticIntegration Tests (no-AK)Capture web-shell visuals 已是绿的。以上全部为本地结果。
  • 仅 Linux。macOS/Windows 未测(正文同样标 ⚠️)。
  • 我测量时 fe7cf68644 自己的 CI 仍在进行中;它在这里的“绿”是我的本地运行结果,不是 GitHub 的结论。

@wenshao wenshao closed this Sep 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review/self-reported The linked issue was opened by the PR author (self-reported)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Main CI failed: Qwen Code CI on d8baa8730fc6

3 participants