fix(webui): Make cross-session switching transactional - #8882
Conversation
E2E verification reportValidated the final PR head BaselineOn pre-change main, both action-driven and controlled A→B switches detached A, aborted its SSE, cleared its transcript, and exposed B/loading before B settled. Rejecting B left an empty B/error state, and a same-workspace controlled target remounted the session provider. Real-daemon scenarios
Result: 2/2 passed. Additional verification
The test environment emitted existing React |
🖼️ 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 |
|
Re-run after two more review rounds were addressed and the branch was rebased twice. Gate still passes:
Moving on to code review. 🔍 中文说明在作者处理了另外两轮评审意见并两次 rebase 之后重新运行。门禁仍然通过:
进入代码审查。🔍 — Qwen Code · qwen3.8-max Reviewed at |
Code reviewBoth blockers from my last pass are resolved, and the two review rounds since then landed cleanly. 1. The web-shell suite is green again. The two missed SDK mocks were extended minimally — 2. The R1/R2 Critical fixes are real fixes, not patches over symptoms. I reviewed the ~230 production lines added by the two fix commits: the passive-assistant timer is cleared inside 3. The rebases were faithful. The branch was rebased over #8864 (first pass) and then again over #8883/#8915 this morning. I diffed the pre-rebase head against the current one for every changed file: 15 of 21 files are byte-identical, and the other 6 differ only by the merged PRs' own hunks — #8883's manual-clear/retry path ( No new Critical findings from me on this head. The 19 deferred R1/R2 Suggestions are recorded per-thread under the mature-PR rule — they should land as follow-up issue(s) so they aren't lost. sequenceDiagram
participant P1 as User
participant P2 as WebShell wrapper
participant P3 as Session coordinator
participant P4 as Daemon restore RPC
participant P5 as Staging store
participant P6 as Source session A
P1->>P3: switch to session B
P3->>P3: coalesce identical targets, keep latest only
P3->>P6: keep A mounted - stream, transcript, prompts
P3->>P4: restore B with stable client id
P4->>P5: replay B into shadow transcript
P5->>P3: staged target ready
P3->>P3: guards - lifecycle, deadline, identity
alt commit
P3->>P6: flush and stop A
P3->>P2: install B synchronously, notify commit
else failure, timeout, supersede
P3->>P4: detach staged B best-effort
P3->>P2: keep A, surface structured failure
end
Files changed (21 of 21 shown)
Test evidence (from the PR's own CI via API — no PR code executed here)One correction to my previous comment: the macOS/Windows unit legs and the integration suite are merge_group-only jobs by design ( The head moved once while this review was running (a final rebase over #8883/#8915 at 07:08 UTC, content verified above). On the pre-rebase head Final CI results for
One row per check name (latest run); skipped checks omitted; failures sort first. / 每个检查名一行(取最新一次运行),省略 skipped,失败项排在最前。 Not verified: live behavior — unit CI can show the tests pass, not that the transactional path is load-bearing. Sandboxed verification is already in motion for exactly that claim: a 中文说明代码审查:上轮的两个阻塞项均已解决,此后两轮评审的修复也干净落地。
本 head 上我没有新的 Critical 发现。延后的 19 条 R1/R2 Suggestions 已按成熟 PR 规则逐线程记录——建议落成 follow-up issue 以免丢失。 测试证据(来自 PR 自身 CI 的 API 数据——此处未执行任何 PR 代码):更正上轮说法——macOS/Windows 单测与集成测试是 merge_group 专属作业, 未验证:运行时行为——单测 CI 只能证明测试通过,无法证明事务化路径真正 load-bearing。沙箱验证已在进行中:本次 triage 运行附带的 — Qwen Code · qwen3.8-max Reviewed at |
|
Confidence: 3/5 — the review itself is clean (both my blockers resolved, every Critical from two review rounds fixed, rebases verified faithful, maintainer already approved), but this PR is capped at defer by policy: it's a cross-package change well over the 1,000-production-line advisory threshold, and the bot does not cast the deciding approval on those — plus the rebased head's CI is still in flight. Stepping back: the approach still matches what I'd propose independently — keep the source mounted, restore into staging, one synchronous commit, discard on failure — and the machinery added since my first pass is the part the concurrency hazards genuinely demand, not accretion. The two fix commits are a good sign about how this code will age: each Critical from the adversarial rounds got a structural fix (operation tokens, logical-session identity, honest result propagation) with a paired regression test, not a suppression. The deferred Suggestions were deferred by the book — recorded per thread under the mature-PR rule — though they should land as a follow-up issue so nothing quietly evaporates. What settled this run:
Housekeeping: the three stale 中文说明置信度:3/5 —— 评审本身是干净的(我提出的两个阻塞项均已解决,两轮评审的全部 Critical 已修复,rebase 已逐文件核实为忠实集成,维护者也已批准),但本 PR 按政策封顶为 defer:这是远超 1,000 行生产代码建议线的跨包改动,机器人不为其投出决定性的一票——此外 rebased head 的 CI 仍在运行中。 退一步看:方案依然与我独立设想的一致——保持源会话挂载、staging 恢复、一次同步 commit、失败即丢弃——首轮之后新增的机制是并发风险真正需要的部分,而非堆砌。两个修复提交说明了这份代码未来的维护质量:对抗性评审中的每个 Critical 都得到了结构性修复(操作 token、逻辑会话身份、如实的结果传递)并配有回归测试,而不是把问题压下去。延后的 Suggestions 也按规矩延后——按成熟 PR 规则逐线程记录——但应落成 follow-up issue,避免无声丢失。 本轮的结论依据:
事务性说明:本机器人名下三个过期的 — Qwen Code · qwen3.8-max Reviewed at |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Requesting changes on the execution, not the design — see the Stage 2 notes above. Two blockers: the web-shell unit suite is red on this head (89 failures — client/index.test.tsx and client/components/ChatPane.test.tsx mock the webui SDK module without the new useConnection / useDaemonSessionOwnerGuard exports this PR now uses), and the branch conflicts with main after #8864. The transactional design itself is sound; once the mocks are extended and the rebase is green, re-run /triage.
执行层面需要修改,设计本身没有问题——详见上方 Stage 2 评论。两个阻塞项:该 head 上 web-shell 单测是红的(89 个失败——client/index.test.tsx 和 client/components/ChatPane.test.tsx 对 webui SDK 模块的 mock 缺少本 PR 新使用的 useConnection / useDaemonSessionOwnerGuard 导出),且分支在 #8864 合入后与 main 冲突。事务化设计本身是健全的;补齐 mock、rebase 变绿后重新运行 /triage 即可。
— Qwen Code · qwen3.8-max
175640d to
a6cdc44
Compare
|
Please do not rebase or force-push to an active PR as it invalidates existing review comments. Note for future reference, the bots always squash all changes into a single commit automatically as part of the integration. 中文请勿对活跃的 PR 执行 rebase 或 force-push,因为这会使已有的评审评论失效。另外,供日后参考:作为集成流程的一部分,机器人始终会自动将所有改动压缩(squash)为单个提交。 |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Not explored to full depth (tool budget reached): You are review agent reverse-audit — Reverse audit agen...: none — all checks above completed within budget.; You are review agent reverse-audit — Reverse audit agen...: none — all checks above completed within budget.; You are review agent reverse-audit — Reverse audit agen...: none — all checks above were completed within budget (~19 tool calls).; This PR makes modern WebUI/WebShell cross-session switchi...: daemon transcript-page record ordering ( page.events newest→oldest vs oldest→newest) not verified — affects only the severity estimate of the third finding.; You are review agent reverse-audit — Reverse audit agen...: none — I finished within budget., and 5 more.
中文说明
未探索到全部深度(达到工具调用预算):You are review agent reverse-audit — Reverse audit agen...:none — all checks above completed within budget.;You are review agent reverse-audit — Reverse audit agen...:none — all checks above completed within budget.;You are review agent reverse-audit — Reverse audit agen...:none — all checks above were completed within budget (~19 tool calls).;This PR makes modern WebUI/WebShell cross-session switchi...:daemon transcript-page record ordering ( page.events newest→oldest vs oldest→newest) not verified — affects only the severity estimate of the third finding.;You are review agent reverse-audit — Reverse audit agen...:none — I finished within budget.,另有 5 条。
— qwen3.8-max via Qwen Code /review (v0.21.9)
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Review follow-up
Verification on
|
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Not explored to full depth (tool budget reached): This PR makes modern WebUI/WebShell cross-session load/re...: did not run build/unit tests — findings rest on static tracing of the code paths (every link in the two Critical chains was verified in source, including all re…; This PR makes modern WebUI/WebShell cross-session load/re...: did not enumerate every consumer of connection.commands / connection.skills beyond App's slash-completion usage when assessing the fourth finding.; chunk 22: could not verify from this chunk whether the provider's staged-transition lifecycle arbitration aborts a commit when the staged target is closed/released mid-st…; chunk 2: none (I did not execute the test file — it's a 15.6k-line suite in a review worktree without installed deps, and static verification covered the failure modes a…; chunk 19: none — all checks I intended completed within budget., and 2 more.
中文说明
未探索到全部深度(达到工具调用预算):This PR makes modern WebUI/WebShell cross-session load/re...:did not run build/unit tests — findings rest on static tracing of the code paths (every link in the two Critical chains was verified in source, including all re…;This PR makes modern WebUI/WebShell cross-session load/re...:did not enumerate every consumer of connection.commands / connection.skills beyond App's slash-completion usage when assessing the fourth finding.;chunk 22:could not verify from this chunk whether the provider's staged-transition lifecycle arbitration aborts a commit when the staged target is closed/released mid-st…;chunk 2:none (I did not execute the test file — it's a 15.6k-line suite in a review worktree without installed deps, and static verification covered the failure modes a…;chunk 19:none — all checks I intended completed within budget.,另有 2 条。
— qwen3.8-max via Qwen Code /review (v0.21.9)
|
Handled the second review round on head e3e0825.\n\n| Item | Disposition |\n| --- | --- |\n| R2-1 | Fixed: plan preparation uses an operation token; same-ID and A→B→A regressions covered. |\n| R2-2 | Fixed: model select/delete share an operation token; same-ID and ABA regressions covered. |\n| R2-3 | Fixed: blocked turn-error retry no longer consumes its latch and remains usable after unblock. |\n| R2-4 | Fixed: same-logical legacy loads cannot restart the runner while a transactional target is pending. |\n| R2-7, R2-8, R2-10, R2-11, R2-12, R2-13 | Deferred as Suggestions under the repository policy for mature PRs after roughly five review rounds; each thread records the focused follow-up scope. |\n\nVerification:\n- WebUI actions + Provider: 291 tests passed.\n- WebShell App + WorkspaceSessionProvider: 380 tests passed.\n- Six focused same-ID/ABA/write-block regressions passed.\n- Independent Provider probe confirmed A stays connected, B stays preparing, and only B restore runs.\n- WebUI and WebShell typecheck passed.\n- WebUI build, affected ESLint, formatting, and diff checks passed.\n- Two consecutive clean audits found no remaining actionable correctness issue. |
yiliang114
left a comment
There was a problem hiding this comment.
LGTM. The transactional core holds up under an adversarial pass: commitCrossSession is a fully synchronous ownership swap (microtask-batched store notification, one React batch — no observer-visible intermediate state), the arbitration (intent identity, lifecycle, env generation, deadline, source logical identity) re-runs inside the commit with no await between staging and commit, discard paths only retire the candidate without touching the current session's store/refs/stream, and the coordinator serializes with latest-queued-only and identical-target coalescing. No sessionId-only ownership is reintroduced, double-commit and commit-after-discard are structurally impossible, and all prior rounds' Criticals (round-2's seven, round-3's four, plus round-1's 89 broken unit tests) are verifiably fixed at head with 96 new cases and a real-daemon E2E. CI green on head.
Two P2 hardening items for fast-follow, not blockers: (1) the pump accepts a candidate attachment whose clientId differs from the requested id (DaemonSessionProvider.tsx:3440-3448 never compares candidate.clientId to requestClientId, and persistStableClientId persists the echoed one) — that weakens the #8833 exact-attachment fencing to 'some attachment identity' if a daemon ever echoes a different id; reject or persist the requested id and pin with a test. (2) 'bounded staging' only bounds side queues: the staging store is created with maxBlocks MAX_SAFE_INTEGER and the replay is synchronous, so an incident-class 76 MiB target transiently holds ~3x block arrays and blocks the main thread; deliberate and pinned by tests, not a regression vs legacy, but cap staging at maxBlocks or chunk across macrotasks and document the peak cost. Plus the known-deferred P3s (silent pump stall when client_identity capability is missing at pump time until the watchdog fires; releaseSession only cancels a pending transition when the current session matches). Ship it.
ytahdn
left a comment
There was a problem hiding this comment.
✅ Approved
Approved after the review discussion resolved on the four inline threads: three suggestions were withdrawn (the branch in-flight interlock, the mid-turn admission retention, and the commit-observer boundary are all intentional and correctly reasoned), and the remaining ChatPane writeBlocked follow-up is accepted as a tracked deferral per the review-round policy. No blockers remain.
Note: Test (macos/windows) and Integration Tests (CLI, No Sandbox) are skipped on this head (the existing repo-wide pattern); the jobs that ran — Test (ubuntu), Desktop Shell (ubuntu/windows), web-shell E2E Smoke, visuals — are green.
中文说明
审查通过。4 条行内评论线程已闭环:3 条撤回(branch in-flight 互锁、mid-turn admission 保留、commit observer 边界均为有意设计且论证成立),剩余 ChatPane writeBlocked 一条作为延后项记录(符合审查轮次策略)。无遗留 blocker。说明:head 上 macos/windows 测试与 Integration Tests 被跳过(仓库既有模式),实际运行的 ubuntu Test、Desktop Shell、web-shell E2E 与 visuals 均绿。
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
5651663 to
b700a4c
Compare
|
Conflict resolution update:
The PR is mergeable with no unresolved current review threads. Checks for the rebased SHA are still finishing; the zero-duration red entries belong to a superseded workflow run that GitHub marked |
ytahdn
left a comment
There was a problem hiding this comment.
✅ Approved (re-approved after rebase)
Re-reviewed the updated head b700a4cef (rebase onto the newer main + one new commit):
- The rebase is content-clean — every PR-specific file (
DaemonSessionProvider,actions,types,useQueuedPrompts,WorkspaceSessionProvider,useBackgroundTasks,useSessionArtifacts,midTurnDedup, the daemon side channels, integration test, design doc) is byte-identical to the previously approved head; the diff on the sharedApp.tsx/ChatPanefiles is entirely the newer base's own progress (#8891/#8914), not conflict-resolution churn. - The new commit
b700a4cefis sound — it moves theowner.isCurrent()gate in the rename flow to run after the catalog reconciliation and before the local status notice / error report, so a confirmed server-side rename still reconciles into the catalog after its source attachment was replaced, with a dedicated regression test (reconciles a confirmed rename after its source attachment is replaced). Matches its stated purpose. - Prior discussion conclusions are unchanged: three suggestions withdrawn (branch in-flight interlock, mid-turn admission retention, commit-observer boundary), one accepted as a tracked deferral (
ChatPanewriteBlocked).
CI on the new head: no failures (checks re-running after the rebase). The Test (macos/windows) / Integration Tests (CLI, No Sandbox) skip pattern remains the pre-existing repo-wide one; Test (ubuntu), Desktop Shell, web-shell E2E Smoke, and visuals were green.
中文说明
已针对更新后的 head b700a4cef(rebase 到新 main + 一个新提交)重新审查后再次通过:
- rebase 内容干净——本 PR 专属文件(DaemonSessionProvider、actions、types、useQueuedPrompts、WorkspaceSessionProvider、useBackgroundTasks、useSessionArtifacts、midTurnDedup、daemon 侧通道、集成测试、设计文档)与此前 approved 的 head 逐字节一致;共享文件(App.tsx/ChatPane)的差异全部来自新 base 自身的进度(#8891/#8914),不是 rebase 冲突改动。
- 新提交 b700a4c 合理——把 rename 流程中的
owner.isCurrent()门控移到 catalog reconcile 之后、本地状态通知/错误上报之前:确认过的服务端 rename 在 source attachment 被替换后仍会 reconcile 进 catalog,并有专属回归测试。与提交目的一致。 - 此前的讨论结论不变:3 条撤回(branch in-flight 互锁、mid-turn admission 保留、commit observer 边界),1 条接受为延后项(ChatPane
writeBlocked)。
新 head 的 CI 无失败(rebase 后检查正在重跑);macos/windows 与 Integration Tests 的跳过仍是仓库既有模式,实际运行的 ubuntu Test、Desktop Shell、web-shell E2E 与 visuals 此前均绿。
|
@qwen-code /triage |
|
Sandboxed verification: Skipped because the PR is not open for verification (state=MERGED, draft=false). 中文 — 判定:
|
|
Triage re-run completed without a new review.
The stage comments above were updated with the latest result. View workflow run. 上方各阶段评论已更新为最新结果。查看工作流运行。 |
|
Released in v0.21.10. |
…he loading-skeleton model (QwenLM#9129) The transactional cross-session switching from QwenLM#8882 staged a handoff and kept the old attachment live until the target load committed. It added a large transition state machine (intent staging, same-session capture, watchdog deadlines, controlled rebind) across the daemon session layer and the web-shell provider, and left the UI pinned to the previous session while a switch prepared. Restore the loading-skeleton model: switching a session clears the transcript, shows the loading skeleton, and waits for the load result. - Remove sessionTransition state, onSessionTransitionCommit and the transactional target logic from WorkspaceSessionProvider. - Strip the transition state machine from DaemonSessionProvider and restore single-session restores: restore_in_progress retries stay bounded by the existing watchdog, and the skeleton UI keys on loadingTranscript. - Move useDaemonSessionOwnerGuard back under the daemon index export. - Delete the transactional design docs and both daemon integration tests; the restored behavior is covered by unit tests. - Drop the dead desiredSessionTargetPending prop (write gating now keys on loadingTranscript alone) and stop a failed switch's target workspace from leaking into the next workspace-less load. Co-authored-by: 钉萁 <dingqi.jww@alibaba-inc.com> Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>






What this PR does
This PR makes modern WebUI load/resume switches to a different logical session transactional. The current session remains the visible owner while the target restores and is replayed into an isolated, bounded staging store; only a fully staged target that still wins the lifecycle/deadline arbitration is committed. Failed, timed-out, superseded, malformed, or stale targets are discarded and detached best-effort without clearing the current transcript, stopping its event stream, or replacing its connection state.
The restore coordinator permits one ordinary restore RPC at a time, coalesces identical targets, retains only the latest queued target, and fences late results by exact attachment and environment identity. Commit installs the target transcript, session/client/workspace references, connection state, staged notices and side channels in one synchronous ownership handoff before the public load promise resolves, then starts the prepared target runner without issuing a second restore.
The main WebShell provider now stays mounted across modern controlled session/workspace changes. Navigation paths share transactional ownership fences and write gates, preserve source metadata while a target is pending or fails, hide stale metadata on the first committed target frame, and delay the scheduled-run catch-up timeout until restore has committed. Daemons that explicitly lack
client_identitykeep the existing keyed, detach-first compatibility behavior; unknown capabilities and malformed modern ownership fail closed.Why it's needed
Before this change, selecting another session immediately detached the current session, aborted its event stream, cleared its transcript, and published the target as loading before the target restore had succeeded. A large-session timeout or other restore failure therefore left the user on an empty/error target and stopped the conversation that had been usable. PR #8691 made restore deadlines safe and observable, and PR #8833 fenced late attachment work; this PR adds the missing client-side transaction boundary for ordinary and controlled cross-session load/resume.
Reviewer Test Plan
How to verify
Start with session A connected and containing a visible transcript, then delay the completed response for loading session B. Confirm that A stays connected, retains its transcript, continues receiving live events, and still accepts existing control operations while B is pending. Release B and confirm that the first committed state consistently contains B's session, client, workspace, and replay, with A detached only after commit.
Repeat with B returning a structured HTTP 504 and with B being superseded by later targets. Confirm that A remains usable after failure, only one ordinary restore is in flight, an intermediate queued target is never sent, and a late result cannot replace the latest owner. For a controlled workspace target, confirm that unresolved/failed workspace resolution keeps A mounted and rolls the host back once without a retry loop.
The focused regression suites cover WebUI restore arbitration, pure staging, attachment cleanup, controlled transitions, WebShell owner fences, navigation, queued prompts, background tasks, and artifacts. The real-daemon integration test exercises delayed-success and structured-504 scenarios through
qwen serve.Evidence (Before & After)
Before: deterministic baseline runs on pre-change
mainshowed action-driven and controlled switches detach A, abort A's stream, clear its transcript, and expose B/loading before B settled; a rejected B left an empty B/error state. A same-workspace controlled target also remounted the session provider.After: the real-daemon integration test completed B's restore but withheld the response for about five seconds. During that gate A remained connected, accepted a control request, and received a new live event; releasing the response atomically installed B. A structured B restore 504 preserved A and surfaced
session_restore_timeoutwith HTTP status 504. Focused verification passed 279 WebUI action/provider tests and 418 affected WebShell tests; repository build, typecheck, bundle, and focused ESLint also passed.Tested on
Environment (optional)
macOS Darwin 25.4.0 arm64, Node.js v22.22.3, npm 10.9.8. Real-daemon integration used
QWEN_SANDBOX=falsewith the builtqwen servebundle and a mock ACP child.Risk & Scope
client_identityretain the prior destructive switching behavior.Linked Issues
Refs #8678
中文说明
本 PR 做了什么
本 PR 将现代 WebUI 中切换到不同逻辑会话的 load/resume 改为事务化。目标会话恢复并在隔离、有界的 staging store 中重放期间,当前会话仍然是可见 owner;只有完成全部 staging 且仍通过生命周期/截止时间仲裁的目标才会提交。失败、超时、被替换、格式错误或过期的目标会被丢弃并尽力 detach,不会清空当前 transcript、停止其事件流或替换其连接状态。
restore coordinator 同时只允许一个普通 restore RPC,合并相同目标,只保留最新排队目标,并使用精确 attachment 与环境 identity 隔离迟到结果。commit 在公开 load promise resolve 前,通过一次同步 ownership handoff 安装目标 transcript、session/client/workspace 引用、connection state、已 staging 的 notices 和 side channels,然后直接启动准备好的目标 runner,不会再次发起 restore。
现代受控 session/workspace 变化期间,主 WebShell provider 现在保持挂载。各导航入口共享事务化 ownership fence 和写入 gate,目标 pending 或失败时保留源会话 metadata,目标提交的第一帧隐藏过期 metadata,并将 scheduled-run 的 catch-up timeout 延后到 restore commit 之后。明确缺少
client_identity的 daemon 继续使用现有 keyed、detach-first 兼容行为;capability 未知和现代 ownership 格式错误则 fail-closed。为什么需要
变更前,选择另一个会话会在目标 restore 成功之前立即 detach 当前会话、终止其事件流、清空 transcript,并把目标发布为 loading。因此大型会话超时或其他 restore 失败会让用户停留在空白/错误目标,同时停止原本可用的会话。PR #8691 已使 restore deadline 安全且可观测,PR #8833 已隔离迟到 attachment 工作;本 PR 补上普通及受控跨会话 load/resume 所缺少的客户端事务边界。
Reviewer 测试计划
如何验证
先连接 session A 并确保存在可见 transcript,然后延迟 session B 已完成 load 的响应。确认 B pending 期间 A 仍保持 connected、保留 transcript、继续接收实时事件,并且现有控制操作仍能使用。释放 B 后,确认第一个 committed 状态中的 session、client、workspace 和 replay 全部一致属于 B,并且 A 只在 commit 后才 detach。
再让 B 返回结构化 HTTP 504,并让 B 被后续目标替换。确认失败后 A 仍可用、同时只有一个普通 restore 在运行、中间排队目标不会发送、迟到结果不能替换最新 owner。对于受控 workspace 目标,确认 workspace 解析未完成或失败时 A 保持挂载,host 只回滚一次且不会形成重试循环。
focused regression suites 覆盖 WebUI restore 仲裁、pure staging、attachment 清理、受控切换,以及 WebShell owner fence、导航、queued prompts、background tasks 和 artifacts。真实 daemon integration test 通过
qwen serve覆盖 delayed-success 与结构化 504 场景。证据(变更前后)
变更前:在变更前
main上的确定性 baseline 运行表明,action-driven 和 controlled 切换会在 B settle 前 detach A、终止 A 的 stream、清空 transcript 并显示 B/loading;B reject 后停留在空白 B/error 状态。同 workspace 的受控目标还会 remount session provider。变更后:真实 daemon integration test 完成了 B restore,但将 response 暂停约五秒。在 gate 期间 A 保持 connected、接受 control request 并收到新的 live event;释放 response 后原子安装 B。B 的结构化 restore 504 保留 A,并显示
session_restore_timeout与 HTTP 504。focused verification 通过 279 个 WebUI action/provider 测试和 418 个受影响 WebShell 测试;仓库 build、typecheck、bundle 与 focused ESLint 也全部通过。测试平台
环境(可选)
macOS Darwin 25.4.0 arm64,Node.js v22.22.3,npm 10.9.8。真实 daemon integration 使用
QWEN_SANDBOX=false、已构建的qwen servebundle 和 mock ACP child。风险与范围
client_identity的 daemon 保留原有 destructive switching 行为。关联 Issue
Refs #8678