cc-haha/tests/manual/v0.4.10-to-head-ui-errors.md
2026-07-22 20:46:34 +08:00

30 KiB
Raw Blame History

v0.4.10 之后人工界面测试缺陷与修复记录

测试范围:v0.4.10..91829e91

平台Windows 11 x64隔离 CLAUDE_CONFIG_DIR 与 Electron user-data-dir

状态本轮执行已收口。DeepSeek、MiniMax 真实编程任务、附件恢复、多模态、SubAgent、Task 并发与 Windows 长空闲恢复均有真实 UI 证据BUG-001BUG-011 已修复并验证。未执行或仅部分执行的硬件、故障注入、CLI/TUI 用例仍按限制保留,不冒充 passed。

BUG-001React StrictMode 下内置终端首次打开为空白

  • 严重程度P0
  • 状态fixed / verified
  • 对应用例WIN-03、终端基础冒烟
  • 测试场景:开发构建中打开顶部内置终端标签。
  • 实际结果:终端区域为空白且没有可用会话;刷新设置页不能恢复。
  • 期望结果:终端只创建一个 runtime显示 Running、shell、cwd 和可交互提示符。
  • 根因React StrictMode 首次挂载会重放 effect。第一次 cleanup 立即销毁共享 terminal runtime第二次 effect 继续持有已经失效的对象,因而无法重新启动。
  • 修复:为组件 effect 增加生命周期版本;普通真实卸载仍在 microtask 中销毁 runtimeStrictMode replay 的过期 cleanup 则不再销毁当前 runtime。
  • 变更文件:
    • desktop/src/pages/TerminalSettings.tsx
    • desktop/src/pages/TerminalSettings.test.tsx
  • 验证证据:
    • 聚焦 Vitest17/17 passed。
    • TypeScript tsc --noEmit passed。
    • Computer Use 复验:顶部终端显示 RunningC:\WINDOWS\system32\cmd.exe 和隔离配置目录提示符Restart 后仍为 Running
    • 完整 bun run check:desktop2430 passed、2 skipped、0 failedproduction build passed。

BUG-002切换语言后 Settings 顶部标签仍保留旧中文标题

  • 严重程度P1
  • 状态fixed / verified
  • 对应用例I18N-01
  • 测试场景:应用最初为简体中文,打开设置标签后切换到 English。
  • 实际结果:设置页正文已经变为英文,但顶部标签仍显示持久化的“设置”。
  • 期望结果:顶部标签与当前 locale 同步显示 Settings,关闭按钮的无障碍名称也同步更新。
  • 根因:设置标签直接渲染创建标签时保存的 tab.title,没有根据当前 locale 重新读取 settings.title
  • 修复:设置类型标签动态渲染当前 t('settings.title'),同时用于 close button 的 aria-label普通会话标签仍保留原标题。
  • 变更文件:
    • desktop/src/components/layout/TabBar.tsx
    • desktop/src/components/layout/TabBar.test.tsx
  • 验证证据:
    • 聚焦 Vitest40/40 passed。
    • TypeScript tsc --noEmit passed。
    • Computer Use 复验:切换 English 后顶部显示 Settings,关闭按钮为 Close Settings
    • 完整 bun run check:desktoppassed。

QA-001Windows 完整桌面门禁的跨平台测试夹具失败

  • 严重程度:测试基础设施
  • 状态fixed / verified
  • 首次结果:bun run check:desktop 为 12 failed、2418 passed因测试失败未进入最终 build。
  • 分类:
    • 7 个稳定失败来自测试夹具把 POSIX/macOS 路径、权限位或 PATH 大小写写死到 Windows。
    • 2 个 petWindow 失败来自源码字符串断言写死 LF不能处理 Windows CRLF。
    • 3 个 Workspace 测试在全量并发下渲染约 5001、1996、2300 个 DOM 行,触发 5/20 秒超时;聚焦运行均通过。
  • 修复原则:没有发现对应生产逻辑错误,因此只修正测试的跨平台构造和无必要的大规模 DOM 夹具,没有改生产代码,也没有简单扩大超时。
  • 变更文件:
    • desktop/scripts/electron-output-guard.test.ts
    • desktop/electron/services/pets.test.ts
    • desktop/electron/services/sidecarManager.test.ts
    • desktop/electron/services/terminal.test.ts
    • desktop/electron/services/petWindow.test.ts
    • desktop/src/components/workspace/WorkspaceDiffSurface.test.tsx
    • desktop/src/components/workspace/WorkspacePanel.test.tsx
  • 验证证据:
    • 路径/权限聚焦测试98 passed、1 macOS-only skipped。
    • petWindow/Workspace 聚焦测试95/95 passed同组 coverage 运行 95/95 passed。
    • 修复后完整 check:desktop2430 passed、2 skipped、0 failed最终 tsc -b 与 Vite production build passed。
    • 紧接着的全量 JSON 复跑524/524 suites passed2430 passed、2 skipped。

排除的环境误报

ENV-001旧 Sidecar 导致 Pets 无法加载

  • 初始现象:设置页显示“无法加载宠物”。
  • 结论不是候选代码缺陷。Electron 主进程使用当前源码,但启动时加载的是 2026-07-18 的旧 claude-sidecar 二进制,早于测试范围内的服务端改动。
  • 处置:备份旧二进制后执行 bun run build:sidecars,仅在隔离测试实例中换入当前 Sidecar。
  • 复验4 个内置宠物 Dada、Huhu、Bubu、Huihui 正常出现;桌面宠物窗口可打开。

ENV-002旧 Sidecar 导致 Agent 保存后前端读取 agentType 报错

  • 初始现象:创建 Agent 后弹出 Cannot read properties of undefined (reading 'agentType')
  • 结论:不是候选代码缺陷。旧 Sidecar 的 POST /api/agents 返回 {ok:true},当前桌面端期望 {agent: ...}
  • 处置:同 ENV-001重建当前 Sidecar。
  • 复验:用户 Agent manual_reviewer 可创建、查看、编辑回继承;内置 Agent 保持只读。

BUG-003权限模式控制请求被拒绝后遗留 pending confirmation

  • 严重程度P1
  • 状态fixed / verified
  • 对应用例DENY-01、DENY-02、权限模式切换
  • 发现方式Windows check:coverage 在连续执行“确认成功 → CLI 拒绝 → 确认超时”三个权限模式测试时稳定不退出。
  • 根因:ConversationService.setPermissionMode() 在创建 confirmation Promise 后调用 requestControl()CLI 拒绝 control request 时catch 只清理 timer/callback没有 settle 已创建的 confirmation Promise。在 coverage 异步跟踪下,该 pending Promise 会让后续计时测试进入持续 CPU 状态。
  • 修复:保存 confirmation reject 句柄,引入 settled guard 和显式 cancelConfirmation(reason)control request 失败时清理 callback/timer、拒绝 confirmation并原样重新抛出原始 CLI 错误。确认超时计时器只在 control request 成功后按总预算剩余时间启动。
  • 变更文件:
    • src/server/services/conversationService.ts
    • src/server/__tests__/conversations.test.ts
  • 验证证据:
    • 三个权限模式顺序回归3 passed、0 failed。
    • 同组三用例 coverage3 passed、0 failed不再挂起。
    • 完整 conversations.test.ts coverage96 个具名测试全部完成并通过Windows afterAll 临时目录清理另有一次 EBUSY,不属于行为断言失败。
    • 回归额外断言 CLI 拒绝后 outputCallbacks 为空、pendingPermissionModeChanges 为空。

QA-002Windows check:coverage 的 root-server 阶段异常慢

  • 严重程度:测试基础设施
  • 状态fixed / verified
  • 实际结果:单次 bun run check:coverage 在第一个 root-server 覆盖率套件持续 22 分钟,没有生成 coverage.log 或 lcov 产物Bun 进程保持约单核满载、约 500 MB working set 且响应正常。
  • 历史对照:同机历史 coverage 报告中 root-server 阶段约为 135、151、190 秒。
  • runner 限制:scripts/quality-gate/coverage.ts 会把整个子进程 stdout/stderr 缓冲到退出后再写日志,且没有套件级 timeout所以执行中没有可用于定位最后用例的进度产物。
  • 处置:确认 PID、父子关系和完整 command line 后,仅终止本次 check:coverage 的三个 Bun 进程;没有启动重复运行,也没有影响 Vite、Electron 或其他测试。
  • 根因定位:连续权限模式用例会触发 BUG-003 的 pending confirmation 泄漏;定向 coverage 修复后不再挂起。
  • 结论:首次覆盖率门禁记为 blocked/timeout修复后完整重跑在 130.2 秒内完成5/5 suites passedchanged lines 95.56%43/45

BUG-004Bun 下销毁 CONNECTING WebSocket 会永久停在 CLOSING

  • 严重程度P1
  • 状态fixed / verified
  • 对应用例WIN-05
  • 发现方式:修复 BUG-003 后,完整 coverage 的 adapters 阶段为 405 passed、1 failedWsBridge > destroy cleans up all sessions without leaking connecting-socket errors 在 20ms 后仍保留一个 error listener。
  • 根因Bun 1.3.11 会把 bare ws 导入替换为 BunWebSocket 兼容层。对仍为 CONNECTING 的不可达连接立即调用 close()terminate()socket 会永久停在 CLOSING且不再触发 error/close原临时 error sink 和 close listener 因而永久保留。
  • 修复CONNECTING 状态不再调用会毒化状态的 close/terminate。移除业务 listener 后只挂 teardown listener自然 error 被消费并清理;若 open 先发生,则再正常 close并在 close/error 时清理。OPEN/CLOSING/CLOSED 的原关闭路径保持不变;生产代码没有新增任意超时。
  • 变更文件:
    • adapters/common/ws-bridge.ts
    • adapters/common/__tests__/ws-bridge.test.ts
  • 验证证据:
    • 聚焦测试13 passed、0 failed。
    • 聚焦 coverage13 passed、0 failedws-bridge.ts lines 85.59%、functions 73.68%。
    • 回归按条件等待 CLOSED并断言 open/error/close listeners 全部为 0。
    • bun run check:adapters406 passed、0 failed。
    • 修复后完整 bun run check:coverage5/5 suites passed。

BUG-005Trace abort backstop timer 被 unref 后在 Bun/Windows 单核自旋

  • 严重程度P1
  • 状态fixed / verified
  • 对应用例Trace/诊断稳定性、server 质量门禁
  • 发现方式:check:server 卡在 trace-capture.test.ts;拆分单文件后,在任何测试结果输出前持续占满一个 CPU 核心。
  • 根因:captureResponseTraceSnapshot 对无法被 cancel 唤醒的永久 pending reader.read() 使用 grace backstop timer但该 timer 随即 unref()。Bun 1.3.11 Windows 在 Promise.race 只剩 pending read 与 unref timer 时会同步忙循环timer 不触发。
  • 修复:保留 backstop timer 的 event-loop 引用,并注释说明它是当前函数正在等待的正确性兜底,不能 unref。
  • 变更文件:src/services/api/traceCapture.ts
  • 验证证据:
    • 原挂起用例1/1 passed63ms。
    • 完整 trace-capture.test.ts61/61 passed、281 assertionsBun 2.67 秒,自然退出。
    • bun run check:server219 files、2248 passed、0 failed。
    • bun run check:chat-contract5 files、299 passed、0 failed。

QA-003Reconciliation safety sweep 测试等待 unref interval 时忙循环

  • 严重程度:测试基础设施
  • 状态fixed / verified
  • 实际结果:前 5 个测试显示 passed 后进程持续单核满载,没有最终汇总;定位到第 6 个 low-frequency safety sweep 用例。
  • 根因:测试 await 的 Promise 只能由 production 中已 unref() 的 safety interval resolvepending Promise 不保持事件循环活跃,在没有 referenced timer 时 Bun runner 忙等,测试也无法走到 watcher.stop()
  • 修复:用已有带 referenced Bun.sleepwaitFor 等待首个 batch并用 try/finally 始终释放被阻塞的首批次、停止 watcher。
  • 变更文件:src/server/services/localIndex/reconciliationWatcher.test.ts
  • 验证证据:单用例 1/1 passed、191ms完整文件 7/7 passed、570ms自然输出汇总并退出。

BUG-006Windows 下停止系统代理时 CONNECT 连接使 Electron 测试超时

  • 严重程度P1 / Windows 资源生命周期
  • 状态fixed / verified
  • 触发用例WIN-04check:native 内的 SystemProxyBridge > closes active CONNECT clients and outbound routes during stop
  • 实际结果Vitest 单文件通过,但 native 使用的 Bun test runner 中 bridge.stop() 稳定超过 500ms。
  • 根因Bun/Windows 对已升级的 CONNECT socket仅销毁桥接层跟踪的 socket 不足以让 http.Server.close() callback 完成。
  • 修复:先销毁已跟踪的 client/outbound sockets仅在 server 仍处于 listening 时调用 closeAllConnections(),然后调用并等待 server.close()。保留 listening guard避免破坏 startup/stop 竞态。
  • 变更文件:desktop/electron/services/systemProxyBridge.ts
  • 验证证据Bun 聚焦测试 18/18 passedElectron TypeScript passed完整 check:native 中 Electron 310 passed、1 skipped、0 failed目录打包与 current package smoke passed。

QA-004Tray 测试与 Menu 测试共享 Electron 模块 mock

  • 严重程度:测试基础设施
  • 状态fixed / verified
  • 触发用例:check:nativetray.test.ts 的未处理错误 Electron tray mocks were not initialized for this test
  • 实际结果tray 单文件 4/4 passed与 menu 测试联跑时稳定失败,证明是测试加载顺序相关污染。
  • 根因Bun 整套 Electron 测试共享 electron 模块 mock 注册表,menu.test.tstray.test.ts 会互相覆盖模块级 mock。
  • 修复:installTray 接受可选且类型受限的 Electron runtime 注入,生产默认仍动态导入 Electrontray 测试改为注入本地 mocks不再注册全局 vi.mock('electron')
  • 变更文件:desktop/electron/services/tray.tsdesktop/electron/services/tray.test.ts
  • 验证证据tray 4/4 passedmenu + tray 15/15 passedElectron TypeScript passed完整 check:native passed。

BUG-007项目 Agent 保存被可选热重载阻塞 120 秒

  • 严重程度P1 / Agent 管理可用性
  • 状态fixed / verified
  • 触发用例AGT-03、AGT-08。
  • 实际结果Project Agent 的文件和列表刷新已完成,但 Create Agent 对话框仍保持 Save/Cancel disabled 与 loading120 秒后才关闭并显示 The change was saved, but the latest agent configuration could not be fully applied. Request timed out after 120s
  • 现场证据:首次隔离工作区位于外层 Git 仓库内,服务端按既有 Git-root 规则将文件写到仓库 .claude/agents/project_reviewer.md;该测试文件及本轮创建的空 agents 目录已精确清理。随后在 artifacts/manual-ui-91829e91/workspace 内初始化独立 Git 根,后续复测不会写入产品仓库。
  • 根因:desktop/src/stores/agentStore.ts 在已成功 create/list 后仍等待 agentsApi.reload()reload 请求使用 120 秒 timeout并在结束前保持全局 isMutating=true。热重载本应是保存后的非阻塞增强,失败只需 warning + Retry。
  • 修复create/update/delete 在持久化和列表刷新成功后立即结束 mutationsession reload 改为后台 warning并用 request id 隔离项目切换后的迟到结果。
  • 验证证据AgentManager + agentStore 44/44 passeddesktop lint passedComputer Use 复测点击 Save 后约 1.2 秒进入 Agent 详情页提示“active CLI session is not running”但 Save/Cancel 不再阻塞。

BUG-008Agent Git 根缓存未感知运行中新增的嵌套仓库

  • 严重程度P1 / 项目隔离与数据安全
  • 状态fixed / verified
  • 触发用例AGT-03。
  • 实际结果Create Agent 表单显示目标为 artifacts/manual-ui-91829e91/workspace,且该目录已通过 git init 成为独立 Git 根;保存后文件仍被写入外层产品仓库 .claude/agents/project_reviewer_fixed.md
  • 现场证据:git -C artifacts/manual-ui-91829e91/workspace rev-parse --show-toplevel 返回隔离工作区;隔离目录无 Agent 文件,外层文件的创建时间与本轮保存一致。已读取并核对内容后精确删除该测试文件。
  • 根因Agent 服务首次解析隔离目录时它尚未初始化为仓库,findGitRoot(realCwd) 的全局缓存记录了外层仓库;运行中 git init 后 Agent CRUD 仍复用旧缓存,且 clearAgentDefinitionsCache() 不会清理 Git-root 缓存。
  • 修复:项目 Agent 路径解析前按 realCwd 刷新 Git-root 缓存;新增“先预热父仓库、再创建嵌套 .git”的 API 回归测试。
  • 验证证据:新增用例在临时撤掉修复时按预期失败,恢复后 agents-api.test.ts 17/17 passed、260 assertions。重建 Sidecar 并重启隔离 Electron 后Computer Use 创建 project_reviewer_fixed2,约 1.5 秒进入详情页且目标显示隔离工作区Shell 确认文件只存在于 artifacts/manual-ui-91829e91/workspace/.claude/agents/,外层产品仓库同名文件不存在。

BUG-009Windows 本地半关闭连接堆积并拖垮 Session 列表

  • 严重程度P0 / Windows 桌面核心可用性
  • 状态fixed / focused + live Windows verified
  • 触发用例WIN-06、CTX-01、会话列表与 Scheduled 冒烟。
  • 实际结果:左侧短暂显示 Session list failed to load / Request timed out after 120s,稍后刷新又自行消失。同期并非只有 Session16:59:19 的 Task list 与 turn-checkpoints 同时 120 秒超时17:04:01 的 /api/sessions?limit=400/api/scheduled-tasks 同时 120 秒超时,之前分别有两次 context inspection 20 秒超时。
  • Windows 现场证据Sidecar 和 CLI 进程始终存活,故障窗口无 Electron/Bun crash端口 51529 残留 9 对异常连接Electron 侧为 FinWait2、Sidecar 侧为 CloseWait。Session 目录只有 3 个小 JSONL本地 SQLite 也很小不支持“400 条 Session 扫描过慢”的解释。
  • 首轮根因假设:ContextUsageIndicator 的 HTTP deadline 与服务端 get_context_usage control budget 同为 20,000 ms客户端 abort 与服务端 timeout 同刻竞速,使 localhost keep-alive socket 未及时收尾。该假设只能解释早期相关性,不是最终根因。
  • 最终根因Electron/Chromium 会长期池化 HTTP/1.1 本地连接,而 Bun.serve 配置 idleTimeout: 60。Chromium netlog 证明失败的 source 4974 在 socket #1319 空闲约 104 秒后复用:此前该 socket 多次正常收发,复用时客户端成功写入 684 bytes服务端却不再返回响应头120,011 ms 后 Chromium 取消。Windows 上 Bun 超时后的 socket 没有被客户端识别为已关闭,形成 stale keep-alive任务、turn-checkpoints、workspace-status 等任意复用该连接的 REST 都会受影响。
  • 修复:保留客户端/abort/health 的正确生命周期修复,并将本地 Bun.serve HTTP idleTimeout 设为 0,让 Chromium 客户端拥有池化连接生命周期,避免 server 先静默失效而 client 继续复用。曾尝试给所有 REST 响应加 Connection: close,但 12 次导航制造 403 个 TIME_WAIT,已撤回该全局策略。
  • 变更文件:
    • desktop/src/components/chat/ContextUsageIndicator.tsx
    • desktop/src/components/chat/ContextUsageIndicator.test.tsx
    • desktop/src/api/client.ts
    • desktop/src/api/client.test.ts
    • desktop/src/stores/cliTaskStore.ts
    • desktop/src/stores/cliTaskStore.test.ts
    • desktop/electron/services/sidecarManager.ts
    • desktop/electron/services/sidecarManager.test.ts
    • src/server/index.ts
    • src/server/__tests__/server-options.test.ts
    • src/server/requestLifecycle.ts
    • src/server/api/sessions.ts
    • src/server/services/conversationService.ts
    • src/server/__tests__/conversations.test.ts
  • 验证证据:
    • 服务端 abort callback 清理1/1 passed服务端 timeout listener 清理1/1 passed。
    • ContextUsageIndicator 聚焦 Vitest7/7 passed。
    • 重建 Sidecar、重启同一隔离 Electron 后,真实 DeepSeek 返回 WINDOWS_TIMEOUT_FIX_ACTIVE,会话列表与 context 2% 正常。
    • 修复版基线为 0 CloseWait / 0 FinWait2Computer Use 连续手动刷新 context 10 次后仍为 0 / 0仅有正常 Established 和短期 TimeWait
    • 随后会话列表手动刷新约 1.3 秒Scheduled 页面约 1.3 秒打开,均无 timeout这只证明了短时场景。
    • 最终定位前的重启复现中,真实 MiniMax 多模态会话跨过 120 秒后再次出现 CloseWait/FinWait2,并在稍后明确写入 3 条新的 120 秒诊断task-list、turn-checkpoints、workspace-status这批证据用于否定“只是 context 计算慢”。
    • server-options.test.ts、request-lifecycle 与 tasks 聚焦回归合计 14 passed / 0 failed / 27 expectsSidecar 重新编译成功。
    • 修复版真实 Electron 启动后先空闲 85 秒,随后 MiniMax 在同一轮并发执行 2 个 TaskCreate、TaskList + 2 个 TaskGet、2 个 TaskUpdate 和最终 TaskListUI 两项均为绿色 completed模型返回 TASK_PARALLEL_IDLE0_OK
    • 修复版 netlog 中同一路径最慢 235 ms所有 localhost API 最慢 578 ms运行 137 秒后 sidecar 仍只有正常 Established0 CloseWait / 0 FinWait2,诊断日志无新增 timeout。WIN-06 改为 passed。
    • 使用官方 @oven/bun-windows-x64-baseline@1.3.14 binary 重编译 sidecar真实 Electron 空闲 106 秒后 MiniMax 返回 IDLE0_BUN1314_OK,运行 131 秒仍为 0 CloseWait / 0 FinWait2 且无新增 timeout排除仅在系统 Bun 1.3.11 上偶然通过。
    • cliTaskStore 新增同一 session 重叠轮询合并;聚焦 12/12 passed避免 React/轮询重入放大本地连接压力,但它不是 stale socket 根因的替代修复。
  • 剩余风险H5 开启时 sidecar 监听 0.0.0.0idleTimeout: 0 也会允许尚未发送完整 HTTP headers 的裸 TCP 连接长期占用资源。当前 H5 token 鉴权只发生在形成 HTTP 请求之后;若要彻底收敛 slowloris/资源占用风险,应将桌面 loopback 与 LAN H5 listener 拆分,或增加 pre-header 连接级 deadline。此架构项不影响本轮 localhost timeout 修复结论,但发布时需要风险接受或后续整改。

BUG-010Windows 宠物窗口重启后失去置顶层级

  • 严重程度P1 / Windows 桌面宠物可见性
  • 状态fixed / focused + live Windows verified
  • 触发用例PET-01、PET-02。
  • 实际结果:完整重启隔离 Electron 后,宠物窗口存在且 shaped region 正确,但被 ChatGPT 等普通窗口遮住;用户只能偶尔看到很小的光标/透明边缘,容易误判为宠物图片资源缺失。
  • 排除项:当前配置选择的是仓库内置 dada-code4 个内置宠物资源均存在且与 HEAD 一致。另一台电脑导入的猫/狗宠物位于 ${CLAUDE_CONFIG_DIR}/cc-haha/pets,属于本地用户状态,不会通过 Git 自动同步;本次故障不是资源丢失或 fallback。
  • Windows 现场证据:修复前宠物 Win32 z-rank 285ChatGPT 为 39窗口样式 topmost=false;宠物 mascot region 为 96,116,288,322,任务卡 region 为 12,322,372,388,证明渲染区域存在但层级错误。
  • 根因:BrowserWindow 构造时的 alwaysOnTop: true 在 Windows showInactive() 后未保持;代码只在 macOS 分支重新调用 setAlwaysOnTop
  • 修复:showInactive()macOS 继续使用 setAlwaysOnTop(true, 'floating')Windows 等其他平台显式调用 setAlwaysOnTop(true)
  • 变更文件:
    • desktop/electron/services/petWindow.ts
    • desktop/electron/services/petWindow.test.ts
  • 验证证据:
    • bun run test -- --run electron/services/petWindow.test.ts24/24 passed连续两次
    • bun run build:electronpassed重启隔离 Electron 两次。
    • 修复后宠物 topmost=True、z-rank 13高于主窗口 30 与 ChatGPT 43截图/可访问性树可见 192px Dada 和“暂无进行中的任务 / 收起 0 个任务”。
    • 后续 BUG-011 修复原生 shape 与前端层级后Computer Use 已能真实鼠标命中任务圆点和关闭按钮宠物本体拖动与多显示器位置恢复仍未完成PET-02 继续保持 partial。

BUG-011宠物任务卡顶部被原生 shape 裁切,关闭按钮被宠物透明命中区截获

  • 严重程度P1 / Windows 宠物任务面板可用性
  • 状态fixed / focused + live Windows verified
  • 触发用例PET-02、PET-04用户截图显示卡片顶部圆角/阴影缺失,点击卡片下方箭头没有反应。
  • 实际结果:任务卡 DOM 矩形紧贴 Windows BrowserWindow.setShape() 边界,圆角抗锯齿与阴影越界部分被原生窗口裁切;关闭按钮绝对定位在卡片 DOM 矩形外,最初既不在原生命中 shape 内,又处在 z-index: 5 的卡片 stacking context 中,低于 z-index: 10 的宠物透明按钮区域。鼠标点箭头实际聚焦宠物按钮,因此卡片不关闭。
  • 排查证据:
    • 修复前真实鼠标点击箭头后 UI 无变化,隔离配置 showTaskPanel 仍为 true
    • 同一界面用 Tab 将焦点移到关闭按钮并按 Enter卡片立即隐藏且 showTaskPanel 变为 false,排除 React handler 和偏好持久化故障。
    • 修复层级前鼠标点击箭头后,下一次 Tab 焦点从宠物按钮移到任务行,证明点击被宠物透明命中区截获。
  • 修复:
    • Windows/Linux 原生交互 shape 对每个渲染区域增加 12px 安全边距并钳制在 384×400 窗口内,保留圆角、边框抗锯齿和阴影。
    • 将独立关闭按钮注册为原生命中区域,并纳入 renderer 的交互点/透传判断。
    • 将任务卡 stacking context 提升到 z-index: 15,高于宠物按钮的 z-index: 10,让画在宠物上方的关闭按钮也实际接收鼠标事件。
  • 变更文件:
    • desktop/electron/services/petWindow.ts
    • desktop/electron/services/petWindow.test.ts
    • desktop/src/features/pets/PetApp.tsx
    • desktop/src/features/pets/PetApp.test.tsx
    • desktop/src/theme/globals.css
    • desktop/src/theme/globals.test.ts
  • 验证证据:
    • 原生 shape 回归 24/24 passedPetApp + globals 聚焦回归 24/24 passed。
    • 真实 Windows Electron + DeepSeek 编程任务中,卡片四角、顶部边框和阴影完整可见。
    • Computer Use 真实鼠标完成“数字圆点展开 → 箭头关闭 → 数字圆点恢复”两轮;第二轮无键盘辅助或 DOM 注入。
    • 隔离配置最终为 showTaskPanel: false,证明关闭状态已真实落盘。

当前测试限制

  • LIVE-001closed用户明确授权真实 Provider 额度并提供专用测试配置。隔离 Electron 中 DeepSeek 连接测试 179 ms 成功,deepseek-v4-pro 已设为默认;真实回复 LIVE_DEEPSEEK_OK、拒绝权限后的 CHAT_CONTINUES 和修复后重启的 WINDOWS_TIMEOUT_FIX_ACTIVE 均通过。配置与证据只保留在隔离测试目录,本文不记录密钥。
  • PROVIDER-001closed / false negativeMiniMax-M3 的 Anthropic 兼容接口确实支持 image block。此前出现 [Unsupported Image] 的会话复用了由 DeepSeek 产生该文本的历史 assistant 消息,并把同一图片重复附加,不能作为 MiniMax 不支持图片的证据。使用首轮即选 MiniMax-M3 的全新会话、只附一张 canary.png 后,真实模型准确返回 PDF_CANARY_91829E91trace 为 /anthropic/v1/messages、1 个 image block、HTTP 200prompt 仅出现 1 次,请求和响应均无 [Unsupported Image]。离线附件序列化回归 conversation-attachments.test.ts 为 3 passed / 0 failed / 22 expects。MiniMax 连接测试为 1,349 ms本文不记录密钥。
  • LIVE-002closed真实 MiniMax-M3 编程流程调用 TaskCreate/List/Get/Update、SubAgent、Read/Bash 并运行 bun test3 个任务全部完成、测试 2 passed / 0 failed最终返回 REAL_TASK_AGENT_FLOW_OK。真实 DeepSeek 流程同样完成 3 个 Task V2、真实编辑和 bun test,最终返回 DEEPSEEK_TASK_V2_OK 2 pass, 0 fail。这两条均为隔离 Git 工作区的实际 Provider 流程,不是 mock。
  • PLAT-001项目声明的 Electron 42.4 本地二进制不可用,本轮交互暂用已缓存的 Electron 42.3。最终构建与源码门禁不受此回退影响,但 Electron 版本特异风险会在最终结论中单独保留。
  • NATIVE-001closedcheck:native 首次执行在替换 Windows sidecar 时因隔离 Electron 遗留进程持有 exe 而 EPERM。核实进程链为隔离测试的 bun 39396 → electron 29132 → sidecar 44260 后仅结束该实例;清理后门禁进入 Electron 套件并暴露 BUG-006 / QA-004修复后完整重跑 passed。

最终门禁汇总

  • bun run check:impactpolicy blocked正确识别 adapters、cli-core、desktop、server并要求 desktop、server、provider-contract、chat-contract、adapters、native、coverage。唯一 blocker 是 CLI core 变更需要 PR 标签与维护者批准,不是测试失败。
  • bun run check:desktoppassed完整 Vitest、lint 与 production Vite build 均成功。首轮仅因旧断言仍期待 20 秒 context timeout 而失败;更新为当前 30 秒契约后聚焦 30/30 passed完整门禁重跑通过。
  • bun run check:serverpassed221 files、2254 passed、0 failed。首次与其他大门禁并行时 conversations.test.ts 单例触发 10 秒资源竞争超时;单例 203 ms 通过,随后完整串行重跑通过。
  • bun run check:provider-contractpassed18 个 deterministic suites 全部通过。
  • bun run check:chat-contractpassed。
  • bun run check:adapterspassed406 passed、0 failed、1091 assertions。
  • bun run check:nativepassedsidecar compiled smoke 8/8Electron 311 passed、1 个 macOS-only skipped、0 failedElectron production build、Windows x64 目录打包及 current package smoke 均通过。一次 1 秒命令超时是执行器主动中止,不是代码失败,完整重跑 84 秒成功。
  • bun run check:coveragepassed5/5 groups、0 failed报告位于 artifacts/coverage/2026-07-22T11-11-42-208Z/coverage-report.md
  • 最终工作区核对:git diff --check passedgit diff --stat 为 53 个已跟踪文件、931 insertions / 301 deletions另有本轮新增测试与两份人工文档git status --short 已复核。未执行 bun run verify,因为本轮按 check:impact 选择的最小完整门禁交付,未声明 PR-ready/push-ready。