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.
This commit is contained in:
2026-09-17 16:40:06 +08:00
parent 75b2ec4123
commit bc0b92bcdc
25 changed files with 2347 additions and 0 deletions
+110
View File
@@ -0,0 +1,110 @@
# 当前代码状态与结构审计
> 用途:处理结构、命名、模块边界或技术债任务前读取。本文只记录已经由源码确认的现状;精确实现仍以当前源码为准。修复顺序和验收要求见 [REPAIR_BACKLOG.md](REPAIR_BACKLOG.md) 与 [VERIFICATION.md](VERIFICATION.md)。
## 结论
项目的目录分层和文件命名总体符合 Python、JavaScript 与 Qt 项目的常见习惯,不需要为了“看起来规范”而批量改名或搬目录。当前主要风险不在命名,而在以下位置:
- `ui/views/main_window.py` 承担窗口组装、浏览器选择、会话、附件、截图、弹层和大量事件处理,已经形成高耦合中心。
- `ui/web/app.js` 同时负责渲染、流式更新、历史、分支和交互状态,Python 与 JavaScript 之间没有显式协议定义。
- Windows 专用的 WebView2、全局热键、进程终止和路径假设尚未被完整隔离,Linux 不能仅凭“Python 跨平台”获得支持。
- 测试入口聚合不完整(P2-04 待实施);配置重定向与运行时数据隔离已由 P0-01 统一(见 [REPAIR_BACKLOG.md](REPAIR_BACKLOG.md) P0-01 与 evidence/P0-01.md)。
- 根目录旧文档混有过时描述;它们不能继续作为实现依据。
当前阶段允许修复错误、添加测试和添加小型平台适配器,但不移动或拆分现有模块。超大文件是已记录技术债,不是本轮重构授权。
## 目录职责
| 路径 | 当前职责 | 审计判断 |
| --- | --- | --- |
| `main.py` | 进程入口、标准输出保护、QtWebEngine 启动参数、`QApplication` 和主窗口创建 | 入口职责基本合理;渲染参数需要区分平台 |
| `core/` | 数据库、LLM 工作线程、日志和 WebView2 后端 | 名称规范;仍含 Windows 专用实现和配置路径旁路 |
| `core/agent/` | 与 pi 对齐的 agent 循环、上下文、压缩、恢复和内置工具 | 应继续保持 GUI-free、可离线测试 |
| `ui/views/` | PyQt6 窗口、桥接层和浏览器包装 | 边界最薄弱;`main_window.py` 是主要风险点 |
| `ui/views/system_tools/` | 文件读取、全局热键、屏幕截图 | 适合作为平台适配落点;当前实现以 Windows 为中心 |
| `ui/web/` | 离线 HTML/CSS/JavaScript 聊天界面和 vendored 前端库 | 无需构建步骤;历史窗口状态机尚未独立 |
| `tools/builtin_tools/` | 面向 agent 的独立实用工具 | 当前仅有 PDF 读取器;与其他两类“工具”需用全路径区分 |
| `tests/` | 纯逻辑测试、offscreen smoke、诊断与人工验证脚本 | 命名前缀有约定,但聚合入口没有覆盖全部自动化测试 |
| `data/` | 源码运行时的配置、数据库和附件 | 本阶段保留项目内路径;凭据处理遵循 [README.md](README.md) 的硬性边界 |
| `vendor/webview2/``WebView2Loader.dll` | Windows WebView2 运行依赖 | 只允许 Windows 路径加载,不能成为 Linux 启动前置条件 |
| `svg/` | UI 图标 | 目录职责清晰 |
## 命名规范审计
| 范围 | 现状 | 结论 |
| --- | --- | --- |
| Python 文件、函数、变量 | 基本使用 `snake_case` | 符合 PEP 8 常规写法 |
| Python 类 | 基本使用 `PascalCase` | 符合惯例 |
| Qt 覆盖方法 | 使用 `eventFilter``closeEvent` 等 Qt 固定名称 | 正确例外,不应改成 `snake_case` |
| QWebChannel/JS 可调用接口 | 存在 camelCase 名称 | 跨语言协议名称可保留,但必须集中记录 |
| JavaScript | 主要使用 `camelCase` | 符合惯例 |
| CSS | 选择器和属性使用 Web 常规形式 | 符合惯例 |
| 测试文件 | `test_*``smoke_*``diag_*``verify_*``tune_*` | 前缀表达运行性质,约定合理 |
以下名称有可读性或发布规范问题,但不应在当前修复阶段批量改名:
- `Frame.md` 语义过宽,且与 `readme.md``ARCHITECTURE.md` 的职责重叠。旧文档只作历史资料。
- `readme.md` 的大小写不影响源码运行;是否改成 `README.md` 留到仓库整理阶段。
- `db_manager.py``llm_engine.py` 等名称合规,但 “manager/engine” 隐藏了较宽职责;先通过边界文档约束新增代码。
- `core/agent` 的版本字符串不是标准 PEP 440 形式;打包阶段再统一。
- “工具”同时指 agent 的 `read/bash/write/edit``tools/builtin_tools/` 实用工具和 `ui/views/system_tools/` 桌面集成。任务与文档必须使用完整路径或明确类别,不能只写“tool”。
## 已确认的结构与行为缺陷
### 配置和测试隔离
- 已解决(P0-01):所有运行时配置读取统一经 `core/config_paths``HAOCODE_CONFIG_FILE` 优先);`tests/test_config_isolation.py` 用打开路径拦截器证明真实配置从未被打开。
- 新测试必须在导入 `MainWindow` 及相关模块前同时重定向数据库和配置(统一用 `tests/_test_env.py``isolate()`),并检查被测模块是否缓存了路径常量。
- 少数 GUI 测试(`smoke_offscreen.py``smoke_mode.py``smoke_copy_session.py`)自身只重定向数据库、未设置 `HAOCODE_CONFIG_FILE`;独立运行时由环境注入临时配置,P2-04 聚合入口将按子进程强制注入。
- `tests/run_tests.py` 当前不是全套测试聚合器,不能把一次成功运行等同于整个 `tests/` 目录通过。
### UI 和事件处理
- 已解决(P0-02):`MainWindow` 重复定义的 `eventFilter` 已合并为一份;发送规则收进 `send_message(from_enter=...)` 单一实现(见 evidence/P0-02.md)。
- UI 层存在直接 SQL 和跨模块私有成员访问,导致数据库、窗口和渲染状态相互渗透。当前只修复会造成实际错误的调用,不展开分层重构。
- 原生窗口型 WebView2 与 Qt 弹层的遮挡关系需要逐个验证;重命名弹层是已确认案例,不能假定所有 QWidget 弹层都会自然显示在 WebView2 之上。
### Python 与 JavaScript 边界
- 当前通过 `ui/views/chat_bridge.py`、直接 JavaScript 执行以及硬编码函数名传递状态,没有协议版本、载荷 schema 或统一错误回传。
- 当前没有“按边界消息 ID + 方向”请求历史页的 JS→Python 协议。现有消息缓冲也不足以重建附件、时间线、工具输出和分支关系完整的历史项。
- 建立历史滑动窗口时,必须传递完整消息描述符,并用会话/分支 generation 丢弃过期响应;不能让前端自行拼接不完整历史。
- 跨语言公开名称一旦落地即视为协议。实现 Agent 应把请求、响应、错误和重置事件集中列在同一处,并用契约测试锁定。
### 平台边界
- `core/webview2.py``ui/views/wv2_view.py` 和相关进程处理是 Windows 专用路径;Linux 只能选择 QtWebEngine。
- `ui/views/system_tools/global_hotkey.py` 使用 Windows 原生 API,Linux 导入和运行路径尚未隔离。
- agent 的 bash 工具使用隐式 shell 选择:Windows 通常落到 `cmd.exe`Linux 通常落到 `/bin/sh`,不满足既定的 `/bin/bash -lc` 契约。
- Windows 使用进程树终止手段;POSIX 侧尚无对完整进程组的等价取消/超时保证。
- 项目中的 Windows 路径、动态库和 WebView2 探测不能在 Linux 启动阶段被无条件访问。
### 文档和仓库状态
- `ARCHITECTURE.md` 仍含旧产品名和失效目录;误拼接的外部修复文档已经移除,文件顶部已明确标记为历史资料。
- 第三方修复要求提到的 `haocode.spec``pyi_rth_trace.py``tests/diag_render_scale.py``tests/diag_panel_scrollbar.py``tests/diag_rename_overlay.py` 当前不存在。上述三个 `tests/diag_*` 脚本可按任务新建;两个打包文件属于后续阶段。
- 工作区没有可用 Git 历史,不能引用不存在的基线提交,也不应擅自初始化仓库。任务清单仍按可独立提交的粒度书写,供未来接入版本控制。
- 源码树存在 `__pycache__`、数据库、日志和锁等运行产物。当前不做清理工程;测试必须使用临时位置,避免继续污染生产数据。
## 应保持的边界
1. `core/agent/` 保持 GUI-free;纯 agent 行为可不创建 `QApplication` 直接测试。
2. 浏览器差异留在 WebView2/QtWebEngine 适配层,不把后端判断散落到业务逻辑。
3. 系统热键、截图和 shell 通过最小平台适配接口选择实现;Windows 模块与 Linux 模块只在对应平台延迟导入。
4. 数据库存取继续由 `core/db_manager.py` 承担;新的 UI 功能不要增加直接 SQL。
5. Python↔JavaScript 载荷使用完整、可测试的描述符;DOM 只保存当前窗口,不承担持久化或完整会话真相。
6. 运行时秘密边界、任务范围和验证要求分别以本目录的 `README.md``REPAIR_BACKLOG.md``VERIFICATION.md` 为准。
## 本阶段明确延后
- 拆分 `main_window.py``app.js` 或迁移现有模块。
- 批量重命名文件、类或公开跨语言接口。
- PyInstaller/其他打包配置、安装器、AppData/XDG 数据目录迁移。
- WebKitGTK 或其 Qt 封装。
- 通用键盘钩子框架;Linux 只实现现有截图快捷键需要的能力。
- agent shell 沙盒、命令审批、路径权限边界。
- 新工具注册系统、参考其他 harness 增加功能或改变 pi 对齐目标。
- Ubuntu 以外 Linux 发行版的支持承诺。
结构或命名任务只有在“发现的问题已逐项归类为确定缺陷、已接受技术债或明确延后,并且没有借机移动/拆分模块”时才算审计完成。