# 验证与取证规范 本文定义修复任务的统一验证口径。任务范围和完成条件见 [REPAIR_BACKLOG.md](REPAIR_BACKLOG.md)。平台行为契约见 [PLATFORM_PLAN.md](PLATFORM_PLAN.md)。 ## 测试前置条件 ### 凭据与运行数据隔离 `data/config.json` 是不透明秘密。执行测试的 Agent 不得打开、读取、搜索、打印、复制或修改它,也不得用散列或快照方式“验证未变化”。采用以下正向隔离: 1. 为每个测试进程创建独立临时目录和最小临时配置。 2. 在 import 任意可能间接加载 `MainWindow` 的模块前设置 `HAOCODE_CONFIG_FILE`。 3. 在 import `MainWindow` 前把 `core.db_manager._DEFAULT_DB` 指向临时数据库。 4. 写入、迁移、附件和截图产物只落到临时目录。 5. 用文件打开拦截器或替身断言禁止路径从未被访问,不读取禁止路径本身。 需要真实 API key 的 `diag_live_*`、`smoke_live_*` 由用户在受控环境手工决定是否运行;默认测试和工作 Agent 均不运行它们。 ### GUI 环境 离屏测试只验证结构和一般 Qt 行为,不算真机视觉证据。 Windows PowerShell: ```powershell $env:PYTHONIOENCODING = 'utf-8' $env:QT_QPA_PLATFORM = 'offscreen' python tests/smoke_offscreen.py ``` Linux: ```bash PYTHONIOENCODING=utf-8 QT_QPA_PLATFORM=offscreen python tests/smoke_offscreen.py ``` 真实桌面检查前移除 `QT_QPA_PLATFORM=offscreen`。不得用离屏截图替代 WebView2、X11、Wayland、portal、DPI 或滚动条真机检查。 ### 结果记录 每个任务至少记录: - 操作系统、桌面会话类型、Python、PyQt6/Qt 版本; - 精确命令、退出码和测试摘要; - 失败或跳过项及理由; - 真机项的截图/录屏路径和复现步骤; - 是否使用临时配置、临时数据库和离屏模式。 不要写固定“应通过 N 项”的文案;用退出码和当前测试自己报告的数量为准,避免测试增删后文档失真。 ## 定向测试矩阵 每个任务先跑自己的定向测试。定向通过后才跑所在阶段的完整回归。 | 任务 | 必跑命令 | 额外人工证据 | |---|---|---| | P0-01 配置隔离 | `python tests/test_config_isolation.py`;`python tests/test_error_persist.py`;`python tests/smoke_bash_panel.py`;test_agent_core(经 `python tests/run_tests.py` 运行) | 打开路径拦截记录只含临时目录 | | P0-02 `eventFilter` | `python tests/test_main_window_event_filter.py`;`python tests/smoke_offscreen.py`;`python tests/smoke_mode.py` | Enter/Shift+Enter 行为记录 | | P0-03 文档 | 文档链接检查与 `rg` 检查 | 从 `AGENTS.md` 演练一次读取路径 | | P1-01 渲染窗口 | `node tests/test_render_window.js`;`python tests/diag_render_scale.py 400`;相关 Qt smoke | 400 条固定夹具、锚点误差、帧时间报告 | | P1-02 shell | `python tests/test_cross_platform_shell.py`;`python tests/test_bash_stream.py`;`python tests/test_tool_params.py` | 两平台进程树消失证明 | | P1-03 渲染器 | `python tests/test_wv2_guard.py`;`python tests/smoke_offscreen.py`;`node tests/test_math_extract.js` | Windows 两后端、Linux X11/Wayland 启动 | | P1-04 热键/截图 | 平台适配单元测试、`python tests/test_file_attach.py` | Windows、X11、Wayland 各自真机行为 | | P2-01 Bash 排序 | `python tests/smoke_bash_panel.py`;`python tests/test_bash_stream.py` | 重排前后状态与滚动位置 | | P2-02 滚动条 | `python tests/diag_panel_scrollbar.py`;`python tests/smoke_bash_panel.py` | Windows/Linux 局部截图和尺寸 | | P2-03 遮罩 | `python tests/diag_rename_overlay.py`;`python tests/smoke_offscreen.py` | Windows WebView2 遮罩截图/移动缩放录屏 | | P2-04 聚合入口 | `python tests/run_all.py --group logic`;`--group offscreen`;`--group all` | Windows/Linux 汇总各一份 | 表中尚不存在的脚本属于对应任务的交付物,不得在创建前声称已经通过。 ## P1-01 渲染窗口专项 ### DOM 无关状态机 `tests/test_render_window.js` 直接加载纯状态机,不依赖浏览器、JSDOM 或 npm。至少覆盖: - `auto`、`manual` 两种模式; - `size` 为 10、40、200; - 缺失、`true`/`false`、字符串、0、负数、9、201 等值都回落 40; - 初始最新页、连续向上、连续向下、首尾边界; - 加一端时裁另一端,窗口始终不超过上限; - 活动流计入上限,且不会被裁; - 新 token 到来回到底部; - `clearChat` 清游标/缓存/未决请求但保留配置; - 会话/代次变化后丢弃旧响应; - 分支目标保留和目标缺失回底。 ### Qt/DOM 集成 Qt smoke 使用临时会话生成完整描述,至少包含普通消息、附件、reasoning、工具时间线、工具结果和多分支消息。用 QWebChannel 完成多轮双向换页后,逐项比较重建结果。 通用硬指标:任意时刻 `.message-wrapper <= render_window_size`。这条对所有夹具、所有窗口大小和流式状态都成立。 固定 400 条夹具的附加指标: | 指标 | 门槛 | |---|---| | `.message-wrapper` | `<= render_window_size`,默认 `<= 40` | | DOM 总节点 | `<= 4000` | | 页面总高度 | `<= 30000 px` | | 向上换页锚点误差 | `<= 2 px` | 总节点数和页面高度只对版本化的固定 400 条夹具验收。修改夹具必须在结果中说明,不得把这些数字套到任意内容长度。 ### 帧时间 帧时间属于人工基准报告,不是自动化通过门槛。相同机器、相同窗口尺寸、相同 400 条夹具分别记录修复前/后: - 流式追加一段固定文本期间的采样次数; - frame duration 的 median、p95 和最大值; - 是否发生肉眼可见停顿; - 浏览器后端和 Qt 版本。 报告原始数值和测量方法,不把环境波动包装成确定性断言。 ## 当前独立回归命令 在 P2-04 聚合入口完成前,按影响范围选择下列现有命令。每项任务不要求机械运行所有命令;一个阶段结束时运行完整集合。 ```text python tests/run_tests.py python tests/test_config_isolation.py python tests/test_main_window_event_filter.py python tests/test_tool_params.py python tests/test_compaction_persist.py python tests/test_copy_session.py python tests/test_bash_stream.py python tests/test_error_persist.py python tests/test_wv2_guard.py python tests/test_debug_window.py python tests/test_think_code_neutral.py python tests/test_file_attach.py python tests/test_pdf_reader.py python tests/smoke_offscreen.py python tests/smoke_mode.py python tests/smoke_copy_session.py python tests/smoke_bash_panel.py node tests/test_math_extract.js ``` 平台专属测试在不适用的平台明确 `SKIP`。任何共同逻辑测试失败都不能以平台差异豁免。 `tests/run_tests.py` 当前只覆盖其显式加载内容;在 P2-04 完成前,不能把它单独称为“全套测试”。 ## 分阶段完整回归 ### P0 完成后 运行全部纯逻辑测试和所有受影响的离屏 GUI 测试。重点证明测试不会访问真实配置/数据库,并且 `MainWindow` 输入行为没有回归。 ### P1 完成后 运行当前独立回归命令全集,加上: ```text node tests/test_render_window.js python tests/test_cross_platform_shell.py python tests/test_global_hotkey_platforms.py python tests/test_screen_capture_platforms.py ``` 随后完成 Windows/Linux 真实桌面矩阵。平台适配任务没有真实桌面证据时不能标记完成。 ### P2 完成后 优先运行新聚合入口: ```text python tests/run_all.py --group all ``` 再单独运行三个诊断脚本;它们属于人工/半自动取证,不应混入默认聚合: ```text python tests/diag_render_scale.py 400 python tests/diag_panel_scrollbar.py python tests/diag_rename_overlay.py ``` ## 真实桌面矩阵 ### Windows 10/11 x64 至少覆盖以下路径: 1. WebView2 首选路径:启动、发一轮对话、流式输出、附件、分支、切会话。 2. QtWebEngine 强制回落:使用临时配置启动同一套基本流程。 3. 同时启动两个 QtWebEngine 实例,证明 profile 不争用。 4. WebView2 下打开改名遮罩,验证整个客户区覆盖;拖动、缩放、最大化和还原。 5. Bash 面板三项以上任务,验证最新任务在顶部、状态保持和滚动条视觉。 6. 截图全局热键在应用失焦时仍能捕获并进入附件流程。 证据必须标注实际后端。QtWebEngine 截图不能替代 WebView2 原生遮挡验收。 ### Ubuntu 22.04/24.04 x64 + X11 至少使用 Python 3.10--3.12 范围内一个受支持版本完成: 1. `python main.py` 启动 QtWebEngine,渲染 Markdown、KaTeX、代码块和工具时间线。 2. 发一轮对话并执行 shell 工具,实际命令由 `/bin/bash -lc` 执行。 3. 超时和主动中止后检查父/孙进程均不存在。 4. 双开应用,两个 QtWebEngine profile 不冲突。 5. X11 原生全局截图热键在应用失焦时触发,截图进入附件流程。 6. 消息窗口、Bash 排序与滚动条完成一次真机检查。 ### Ubuntu 22.04/24.04 x64 + Wayland 至少完成: 1. QtWebEngine 正常启动并完成基本对话与渲染。 2. portal/桌面协议请求有清晰的用户授权流程。 3. 全局快捷键和截图通过 portal/桌面协议完成;若当前桌面协议不支持,界面明确报错,应用其余功能继续可用。 4. 拒绝授权、portal 服务缺失和协议版本不足各记录一次结果。 5. 普通用户启动保持 Chromium sandbox。 Wayland 下不得用 X11 私有 API 或静默降级成“仅窗口内快捷键”并声称全局热键通过。 ### 其他发行版 可以记录探索结果,但统一标记“未验证”,不能扩大官方支持矩阵。 ## 人工 UI 检查 ### Bash 排序与状态 按 A、B、C 顺序启动,按 B、A、C 或其他不同顺序结束。运行中栏和已完成栏始终按 C、B、A 的启动顺序显示。操作前先: - 展开其中一个 layer; - 在输出框分别设置水平和垂直滚动位置; - 滚动运行中栏和已完成栏。 任务状态迁移后,上述展开状态、输出、代码框滚动和两个 section 滚动均保持。 ### Bash 滚动条 同时制造横向与纵向溢出,记录: - 横纵滚动条实际厚度; - 箭头区域是否消失; - handle 是否可拖动并有 hover; - 横纵交汇处是否与代码框背景一致; - 模型弹窗、会话列表、附件预览和调试窗口是否未受影响。 ### 改名遮罩 Windows WebView2 下记录打开、移动、缩放、最大化、还原、提交和取消。截图必须包含整个主窗口,能比较聊天区与 Qt 控件区的遮罩亮度。结构性离屏断言只是补充。 ## 聚合入口契约 P2-04 完成后的聚合入口必须: - 使用 Python 子进程执行现有独立测试,不把所有测试 import 到同一进程; - 为每个子进程建立独立临时环境; - 支持至少 `logic`、`offscreen`、`all` 三组; - 汇总命令、退出码、耗时和 PASS/FAIL/SKIP; - 默认排除 live、diag、verify、tune、网络和凭据测试; - 一个子进程失败后继续收集其余结果,最终返回非零; - 在 Windows 和 Linux 使用同一 Python 接口,不嵌入 `.bat` 或 Bash 专属命令串。 ## 最终判定 一项修复只有在以下内容齐全时才算完成:定向测试通过、阶段完整回归通过、该平台需要的真实桌面证据齐全、所有跳过项有理由、真实配置和数据库从未被测试访问。任何一项缺失都应标记为“未完成”而不是“基本完成”。