Files
Haocode/docs/agent-handoff/VERIFICATION.md
T
sorrow404null bc0b92bcdc docs: add agent handoff docs, verification guide, and repair evidence
Add docs/agent-handoff (backlog, execution state, verification, platform plan, per-task evidence), repo AGENTS.md, and architecture notes updated for the dual-renderer design.
2026-09-17 16:40:06 +08:00

263 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 验证与取证规范
本文定义修复任务的统一验证口径。任务范围和完成条件见 [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 专属命令串。
## 最终判定
一项修复只有在以下内容齐全时才算完成:定向测试通过、阶段完整回归通过、该平台需要的真实桌面证据齐全、所有跳过项有理由、真实配置和数据库从未被测试访问。任何一项缺失都应标记为“未完成”而不是“基本完成”。