Files
Haocode/docs/agent-handoff/EXECUTION_STATE.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

9.4 KiB
Raw Blame History

全量修复执行状态

状态:ACTIVE 总目标:完成 REPAIR_BACKLOG.md 中所有待实施任务

调试铁律(跨压缩持久,每次恢复后必须遵守)

  • 所有调试命令、测试与诊断脚本执行都必须设置显式的最长耗时预算(timeout)
  • 若中途因超时跳出,先定位卡点,再允许延长预算重跑;严禁不设超时让它无限卡死

当前任务:全部完成(P0-01 → P2-04) 当前阶段:COMPLETE(自动化部分;Windows 真机双渲染路径已验证;Linux 真机平台验证项见各任务 evidence) 最后完成动作:Windows 真机验证 —— ① core/webview2.py 加 byte[] 加载回落(本机 D: 卷 .NET “网络位置”怪癖),真桌面 WebView2 启动成功(Runtime 153.0.4234.32、controller ready、NavigationCompleted、截图像素证实聊天区真实 DOM 渲染);② HAOCODE_FORCE_QTWEBENGINE=1 真桌面回落验证(独立 per-instance profile、无 taskkill、渲染正常);③ P2-02 真机截图(diag_panel_scrollbar 真桌面 ALL PASS,三图已更新);④ T0 守卫真机交叉验证(diag 实例被锁自动回落,未误杀主程序 WebView2);证据更新 evidence/P1-03.md、evidence/P2-02.md、evidence/P2-03.md 下一步唯一动作:P2-03 人工清单 1–5 可在本机真实 WebView2 模式下走查(app 现可正常以 WV2 启动,当前前台实例为强制 QtWebEngine 模式,重开即默认 WV2);其余为 Linux 真机验证(P1-03/P1-04),需 Ubuntu 桌面主机 当前修改文件:core/webview2.pybyte[] 加载回落 + BaseException 防护)、docs/agent-handoff/evidence/{P1-03,P2-02,P2-03}.md、evidence/win_real_*_mainwindow.png(新) 最近测试结果:test_wv2_guard 10/10(修复后无回归);diag_panel_scrollbar 真桌面 ALL PASSrun_all 25/25(前次终态) 尚未验证的平台:Linux X11、Linux WaylandP1-03 启动链、P1-04 X11 XGrabKey 真实注册/命中、Wayland portal 三态均需真机);Windows 真机双渲染路径(WebView2 + QtWebEngine 回落)已于 2026-09-17 验证,仅剩 P2-03 人工遮罩走查(1–5,可本机执行) 阻塞项:无 观察项:

  • 【P1-01 教训·offscreen QtWebEngine 诊断】未 window.resize()+show()innerHeight=0,锚点/滚动几何全废;诊断必须先 resize+show、等待 innerHeight>0、再显式 load_messages_to_web 重载
  • 【P1-01 教训】runJavaScript 回调不能返回 DOM 元素(转换失败);wait_until 条件一律返回原语(cond ? 1 : 0
  • 【P1-01 教训】批次渲染守卫(__rwPageRendering)必须在调度时刻捕获,延迟回调(rAF+setTimeout)触发时批次已结束、标志已复位,届时再读会漏放 scrollIntoView 触发 'newer' 振荡
  • 【P1-01 设计】页 = 半窗(size//2),非整窗:整窗页会使向上换页锚点必被裁出窗口,≤2px 锚点恢复不可达
  • 【P1-02 教训】Windows 下 argv 列表形态 Popen 会被 list2cmdline 转义内部引号(\"),cmd.exe 不认 → 显式 cmd 契约必须用字符串命令行 cmd.exe /d /s /c "<cmd>"
  • 【P1-02 发现】旧 shell=True 对带引号程序名实为直接 CreateProcessW(不经 cmd);显式 cmd 后行为统一且可预测
  • 【P1-03 教训】QTimer.singleShot 单位是毫秒(25 = 25ms),兜底预算要写 30000;事件循环启动前不触发
  • 【P1-03 教训】QtWebEngine 顺序硬约束:QtWebEngineWidgets 必须先于 QApplication 导入;QWebEngineProfile 必须先于使用它的 page/view 创建,且 setPersistentStoragePath/setCachePath 要在 profile 使用前调
  • 【P1-03 发现】PyQt6-WebEngine 6.10 未暴露 QWebEnginePage.errorOccurred(Qt 6.5+ API),加载失败诊断用 loadFinished(ok) + processEvents 循环
  • 【P1-03 教训】改构造函数签名必须保旧式位置调用:CustomWebPage(browser) 的 view 会被新首形参误当 profile,按 isinstance(QWebEngineProfile) 分派
  • 【P1-04 教训】PyQt6QThread.run() 内任何未处理异常 = abort 整个进程(退出码 127、无 traceback、stdout 缓冲丢失,极难诊断)→ QThread.run() 必须顶层 try/except 全捕获 + 日志
  • 【P1-04 教训】ctypes.byref(x) 返回 CArgObject:真实 CDLL 调用正常,传给测试替身(普通可调用对象)会 TypeError —— 替身端 getattr(arg, "_obj", arg) 还原原对象
  • 【P1-04 教训】Windows 上 os.pipe() 的 fd 不能可靠用于 select()10093/10038)——跨平台可 select 假 fd 用 socket.socketpair();且 a.send() 的数据在 b 的接收缓冲(方向别写反)
  • 【P1-04 发现】file:// URI 解析用剥前缀+unquote 而非 urlparse().pathfile://D%3A%5Cx(无第三斜杠)会被当 netlocgdbus portal 的 FilePicked/Finished 信号都发在 request 对象上
  • 【P2-01 教训】Qt:对刚展开、布局尚未 flush 的 QPlainTextEdit 立即设水平滚动值,随后的挂起 resize flush 会把滚动清零——真实用户无法在未渲染框上滚动,属测试时序伪影;测试设滚动前必须先 settle(N1×N2 探针矩阵证实 N2≥1 即稳定)
  • 【P2-01 教训】offscreen harness 收尾用 os._exitsys.exit 后 QtWebEngine 渲染/GPU 子进程可能不回收 → 解释器挂起至 timeout;管道执行时只看输出会误判通过(必须验 EXIT 码)
  • 【P2-02 教训】offscreen 下 QPlainTextEdit 的 grab() 文档区不填充(黑图)但 panel.grab() 正常;像素断言一律走 widget.render(painter)(渲染到透明 QPixmap),且先做健全性检查(文本色/handle 色像素计数>0)防黑图假通过
  • 【P2-02 教训】PyQt6Qt.VerticalQt.Orientation.VerticalQStyleOptionSlider() 无参构造(不接受 widget);subControlRect(cc, opt, sc, widget) 参数序 + 滚动条箭头子控件枚举名是 SC_ScrollBarSubLine/AddLineCC_ScrollBar 属于 QStyle.ComplexControl
  • 【P2-02 发现】裸控件(无样式表祖先)style() 是基础风格,空 option 下 subControlRect 返回 0 矩形——「原生参照」只能靠 sizeHint/实际几何对照(原生横条 14px vs 面板 8px
  • 【P2-03 发现】offscreen/无真实事件循环时 processEvents() 不处理 DeferredDeletedeleteLater() 后必须显式 QCoreApplication.sendPostedEvents(None, QEvent.Type.DeferredDelete) 才会真正删除(offscreen 测试断言"已删除"前必须冲刷;生产事件循环常驻不受影响)
  • 【P2-03 教训】PyQt6 setGeometry(QPoint, QSize) 重载→构造 QRect(tl,size)QTest.mouseClick(widget, button, modifier, pos) 第 3 参是 modifierQTest 在独立模块 PyQt6.QtTest
  • 【P2-03 发现】core/webview2.py get_environment()taskkill /F /IM msedgewebview2.exe + 共享默认 profile 不可重定向 → 无人值守自动化不得走真实 WebView2 启动路径;真机验收走人工清单(拥有者顶层 Tool 窗 z 序上必盖 WebView2 原生子 HWND,机制与生产已验证的 AttachmentPreviewOverlay 同构)
  • 【P2-03 结构判据】顶层窗可带 owner parentsetWindowFlags(Tool|Frameless)parentWidget() 仍可非 None;判据是 isWindow() / window() is self,不是 parentWidget() is None
  • 本机无系统级 Python 3.10;已用 uv 安装 CPython 3.10.21(用户目录托管)并重建项目内 .venvPython 3.10.21),与文档基线对齐
  • WSL 存在 Ubuntu-22.04(当前 Stoppedpython3.12.3,未装 PyQt6);未检测到 X11/Wayland 桌面会话
  • tests/diag_live_agent.py:19tests/tune_model_popup.py:155 直接引用真实配置路径;属 live/tune 脚本,默认聚合排除,不属 P0-01 允许范围
  • readme.md 提及的 haocode.spec/pyi_rth_trace.py 不在本快照内(打包属后续阶段,不影响源码运行)

环境探测(只读):

  • OSWindows 11 10.0.26200 x64
  • Python:默认 3.13 / 3.12.10,无 3.10.venv = 3.10.21uv 重建,P0-01+ PyQt6 6.10.2 + PyQt6-WebEngine 6.10.0 + openai 2.26.0 + pythonnet 3.1.0 + PyMuPDF 1.28.0
  • WebView2 Runtime153.0.4234.32 存在
  • WSLUbuntu-22.04Stopped)、docker-desktopRunning

任务状态表:

  • P0-01: COMPLETE
  • P0-02: COMPLETE
  • P0-03: COMPLETE2026-09-16 复核通过,文档一致性修订已固化)
  • P1-01: COMPLETE
  • P1-02: COMPLETEWindows 侧自动化全绿;Linux 进程组用例 C3 待 Linux 环境运行生效)
  • P1-03: COMPLETEWindows 侧自动化 + offscreen 真实启动链全绿;Linux 真机与 root/容器 --no-sandbox 接受路径待对应环境验证)
  • P1-04: COMPLETEWindows 侧自动化全绿:路由矩阵/X11 替身/portal 替身/offscreen 真实启动链;Linux X11 XGrabKey 真实注册与 Wayland portal 授权/取消/无 portal 三态待真实 Linux 宿主手动验证,见 evidence/P1-04.md
  • P2-01: COMPLETE(两栏启动倒序 + 状态保持,offscreen 全量覆盖,无平台相关项;见 evidence/P2-01.md
  • P2-02: COMPLETEoffscreen 全量覆盖 + 无泄漏断言;Windows/Linux 真机截图待对应环境运行 diag_panel_scrollbar.py;见 evidence/P2-02.md
  • P2-03: COMPLETEoffscreen 结构+行为全量覆盖 34/34;审计确认唯一受影响遮罩;Windows 真机 WebView2 人工验收清单见 evidence/P2-03.md
  • P2-04: COMPLETE(聚合入口 tests/run_all.pyWindows 25/25 PASSWSL/3.12 FAIL 0 + 21 有理由 SKIP;夹具演示非零退出码;独立/聚合输出一致;暴露并修复 T9 陈旧断言与 compaction.py 3.11+ dataclass 缺陷;见 evidence/P2-04.md