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
+48
View File
@@ -0,0 +1,48 @@
# P2-02 证据:右侧 Bash 面板滚动条与横纵交汇角
完成日期:2026-07-21(无人值守轮次)
结论:**完成**。右侧任务面板的代码框(`#bl_code`)与两栏 section 滚动区(`#bl_scroll`)滚动条统一为 8px、无箭头、handle 可见且 hover;横纵交汇角用 `QPlainTextEdit::corner` 子控件染成代码框背景 `#fbfcfe`,原生亮色 corner 方块消除。所有选择器均限定在 `#bl_code`/`#bl_scroll`,未添加任何无作用域的 `QScrollBar`/`QAbstractScrollArea` 规则。
## 交付物
| 文件 | 改动 |
|---|---|
| `ui/views/main_window.py` | 主窗口全局 QSS 中 `#bl_code` 规则后插入一段**完全限定作用域**的滚动条 + corner 规则(`QPlainTextEdit#bl_code QScrollBar:*``QPlainTextEdit#bl_code::corner``QScrollArea#bl_scroll QScrollBar:*``QScrollArea#bl_scroll::corner`);`#bl_code` 原有背景/边框/圆角/文本样式一字未动 |
| `tests/diag_panel_scrollbar.py` | 新建:离屏测量 + 断言 + 局部截图(面板全貌、代码框 render 图、角落 4x 放大) |
截图(`docs/agent-handoff/evidence/`):`p2-02-panel.png``p2-02-outbox-render.png``p2-02-codebox-corner-4x.png`
## 关键设计决策
1. **作用域 = objectName 限定,零全局规则。** 主窗口全局 QSS 此前没有任何 `QScrollBar` 规则(各弹窗/附件区各自 `setStyleSheet`),右侧面板因此落到原生 Windows 滚动条(带箭头、17px、亮色 corner 方块)。新增规则全部写成 `QPlainTextEdit#bl_code …` / `QScrollArea#bl_scroll …` 形式,只可能匹配右面板内的对象名,结构上不可能泄漏到其他控件。
2. **corner 用 `QAbstractScrollArea::corner` 子控件语法**`QPlainTextEdit#bl_code::corner { background-color: #fbfcfe; }`)——Qt 文档支持的子控件,与代码框背景同色,即 backlog「corner 与代码框背景一致」;未使用不存在的 `QScrollBar::corner`。section 滚动区 `::corner` 置透明(其横向滚动条恒关,corner 本不显示,属保险)。
3. **口径与仓库既有风格一致**8px 厚、`add-line/sub-line` 置 0 隐藏箭头、`#d0d0d0` handle + `#a0a0a0` hover、圆角 4px——与 `modern_scrollbar_qss` 及附件预览区风格同源,只是作用域不同。
## 验证(全部显式 timeout
| 套件 | 结果 | 预算 |
|---|---|---|
| `tests/diag_panel_scrollbar.py`(新) | **18 项 ALL PASS EXIT=0** | 180s |
| `tests/smoke_bash_panel.py` | **140 项 ALL PASS EXIT=0** | 240s |
| 回归 `tests/smoke_offscreen.py` | ALL PASS 8/8 EXIT=0 | 240s |
| 回归 `tests/run_tests.py` | 41/41 EXIT=0 | 300s |
| 回归 `smoke_timeline` / `smoke_midswitch` / `test_main_window_event_filter` | 11/11、7/7、ALL PASS,均 EXIT=0 | 各 ≤300s |
诊断脚本断言要点(对应 backlog「完成证据」):
- **厚度**:代码框横/纵滚动条实际几何 = 8px 且 `sizeHint` = 8pxS1/S1b/S2/S2b);section 竖滚动条实际 = 8pxS3);
- **箭头 extent**`subControlRect(CC_ScrollBar, SC_ScrollBarSubLine)` 在样式代理下 = 0(S4 三项)——即箭头子控件零尺寸;
- **corner**:代码框 `render()` 图中,右下角 8×8 交汇块渲染出 `#fbfcfe`9 px)、无 `(255,255,255)` 亮白像素(S5c/S5d);
- **无泄漏**:未命名 `QPlainTextEdit` 横滚动条仍为原生口径(14px,S6);附件预览滚动条保持自身 6px `sizeHint`S7);
- 截图三张落盘 evidence 目录,含角落 4x 放大图。
Windows 真机截图(backlog「完成证据」第二条):**已完成(2026-09-17Windows 11 真桌面,非 offscreen**`diag_panel_scrollbar.py` 直接运行 → EXIT=0、ALL PASS;实测代码框 H=8px V=8px、section V=8px、corner #fbfcfe 9 像素(与 offscreen 测量一致);三张截图已用真机渲染覆盖:`p2-02-panel.png``p2-02-outbox-render.png``p2-02-codebox-corner-4x.png`(07:20 时间戳)。运行期间生产 app 以 WebView2 在前台,diag 实例经 instance-lock 守卫自动回落 QtWebEngine,未误杀对方 WebView2 进程(T0 守卫真机验证)。Linux 真机截图仍待对应环境。
## 测试中发现的问题与教训
1. **offscreen 下 `widget.grab()` 对 `QPlainTextEdit` 的文档区不填充(黑图)**`out_box.grab()` 整块 (0,0,0),但 `panel.grab()` 正常。改用 `ob.render(painter)`(渲染到透明 QPixmap)后:文本色 `#243043`、边框 `#e6eaf2`、handle `#d0d0d0`、corner `#fbfcfe` 全部出现——**样式子控件在 offscreen 下正常渲染,只有文档区背景填充缺失**(离屏渲染怪癖,非产品 bug)。像素断言一律走 `render()`,且必须先做健全性检查(文本色/handle 色像素计数 > 0)防黑图假通过。
2. **PyQt6 API 坑(三连)**
- `Qt.Vertical`/`Qt.Horizontal` 短名已移除 → `Qt.Orientation.*`
- `QStyleOptionSlider(widget)` 构造器未绑定(只收无参/拷贝)→ 用 `QStyleOptionSlider()`
- `subControlRect` 参数序是 `(ComplexControl, QStyleOption, SubControl, widget)`,且滚动条箭头子控件在 PyQt6 枚举里叫 `SC_ScrollBarSubLine`/`SC_ScrollBarAddLine`(不是 C++ 文档里的 `SC_DownArrowButton`);`CC_ScrollBar` 属于 `QStyle.ComplexControl` 而非 `ControlElement`
- 裸控件(无样式表祖先)的 `style()` 是基础风格且空 option 下 `subControlRect` 返回 0 矩形——「原生参照」只能靠 `sizeHint`/实际几何(如原生横条 14px)对照,不能靠 subControlRect。
3. **测试数据**`out_box` 要同时出横纵滚动条,必须「超宽单行(NoWrap 触发横条)+ 足够行数(触发纵条)」,只给长单行时纵条不可见。