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:
@@ -0,0 +1,50 @@
|
||||
# P2-01 证据:Bash 任务按启动时间倒序
|
||||
|
||||
完成日期:2026-07-21(无人值守轮次)
|
||||
结论:**完成**。两栏均按启动顺序降序显示(最新启动在第一项);运行中→已完成保持原启动位置;重排复用同一批 `BashLayer` 实例,全部 UI 状态保持。目标测试与回归全绿。
|
||||
|
||||
## 交付物
|
||||
|
||||
| 文件 | 改动 |
|
||||
|---|---|
|
||||
| `ui/views/bash_panel.py` | 模块 docstring 口径更新;`_refresh()` 两栏显示顺序改为启动序号降序;`layer_ids()` 的 running/done 返回真实显示顺序("all" 仍为原始启动正序,调试口径不变) |
|
||||
| `tests/smoke_bash_panel.py` | 新增第 11 节(P11.1–P11.20 共 23 项断言);收尾改 `os._exit`(offscreen 铁律,修复解释器退出挂起) |
|
||||
|
||||
未改动:`main_window.py`(事件转发链已是实时、按启动到达顺序带 `call_id` 转发,面板从到达顺序推导启动序号,无需新增元数据)、数据库 schema、`set_layers`(本就复用实例)。
|
||||
|
||||
## 关键设计决策
|
||||
|
||||
1. **排序键 = `self._order` 中的位置(稳定启动序号),不引入时间戳、不改 schema。**
|
||||
面板的 `_order` 在三个入口按启动先后追加:
|
||||
- `set_session()` DB 重建:消息链顺序 + 时间线内顺序(= backlog 要求的「稳定启动序号」构造方式);
|
||||
- `set_session()` 活动流:时间线内顺序(当前轮次天然晚于历史);
|
||||
- 实时 `on_started()`:事件到达顺序。
|
||||
`_order` 即启动序号本身,`_refresh()` 只需对其取逆即可,无需任何新字段。
|
||||
2. **只在显示层取逆,不改内部数据。** `run_ids`/`done_ids` 仍按 `_order` 正序过滤;`reversed()` 只作用于传给 `set_layers` 的 widget 列表。已完成栏限量窗口 `done_ids[-LAYER_LIMIT:]` 的成员不变(仍是「最近启动的 30 个」),仅窗口内显示顺序反转,提示语文义保持。
|
||||
3. **完成时间从不参与排序。** `on_finished` 对已知层只改状态集合(`_running`→`_done`),绝不移动 `_order` 位置;仅当层完全未知(先收到 finished 事件)才以首次感知时间追加——这是唯一的信息可用时刻。因此「先启动后完成」的任务永远压在「后启动先完成」的任务之下,与结束先后无关(P11.10/P11.13 断言)。
|
||||
4. **状态保持靠「同一对象」。** `set_layers` 逻辑未动:`takeAt → setParent(None) → addWidget → show`,操作的是同一批 `BashLayer` 实例。展开/折叠(`expanded` + `body` 显隐)、实时缓冲(`_live`)、代码框滚动值(`out_box`/`arg_box` 子控件属性)、两栏 section 滚动位置(`QScrollArea` 自身属性,子层重排不触碰)全部天然保持,测试逐项断言(P11.4–P11.8、P11.13b–d)。
|
||||
|
||||
## 验证(全部显式 timeout)
|
||||
|
||||
| 套件 | 结果 | 预算 |
|
||||
|---|---|---|
|
||||
| `tests/smoke_bash_panel.py`(含新增 P11 节) | **ALL PASS(140 项断言)EXIT=0** | 240s |
|
||||
| `tests/test_bash_stream.py` | **30/30 ALL PASS EXIT=0** | 180s |
|
||||
| 回归 `tests/smoke_offscreen.py` | ALL PASS 8/8 EXIT=0 | 240s |
|
||||
| 回归 `tests/run_tests.py` | 41 passed / 0 failed EXIT=0 | 300s |
|
||||
| 回归 `test_main_window_event_filter` / `test_config_isolation` / `test_wv2_guard` | 均 ALL PASS EXIT=0 | 各 120s |
|
||||
|
||||
新增断言要点(对应 backlog「完成证据」三条):
|
||||
- **≥3 项任务以不同启动/完成顺序**:s1/s2/s3/s4/s6 + t0 + t1..t31 共 36 项已完成、交错完成(s2 先完成仍居顶、s3 最后完成插入启动位而非顶格),两栏均断言启动降序(P11.1/P11.2/P11.9–P11.13);
|
||||
- **完成中间任务前后状态保持**:对象 identity(`is`)、展开态、实时输出文本、代码框水平滚动值(先强制非 0)、section 垂直滚动值(用 20 行内容撑出真实滚动范围后设 30)在重排后逐项相等(P11.3–P11.8、P11.13b–d);
|
||||
- **DB 重建与实时一致**:切换会话后 3 条时间线条目按 `db2,db1,db0` 显示(消息链+时间线序的逆),`layer_ids()` 原始正序不变(P11.19/P11.20)。
|
||||
|
||||
## 测试中发现并处理的问题
|
||||
|
||||
1. **Qt 布局 flush 会重置代码框水平滚动(测试时序伪影,非产品 bug)**:展开层与 `setValue` 同 tick 执行时,`out_box` 的终宽布局尚未 flush,随后任何布局事件(如新任务触发的 `set_layers`)应用挂起 resize 会把水平滚动清零。探针矩阵(N1×N2 settle 圈数)证实:`setValue` 前至少一次事件循环(N2≥1)则滚动稳定保持。真实用户不可能在未渲染的框上滚动,故测试在设滚动值前补 `settle(120)` 并在注释中记录该伪影。
|
||||
2. **`smoke_bash_panel.py` 解释器退出挂起**:末行 `sys.exit(0)` 后 QtWebEngine 渲染/GPU 子进程(offscreen)不回收,进程挂到 timeout 124;此前跑该文件若经管道只看输出会误判通过。改为仓库 offscreen harness 惯例 `os._exit(code)`(stdout 已 flush、临时文件已清理),EXIT=0 即时返回。
|
||||
3. **`layer_ids()` 口径**:原返回启动正序;改为 running/done 返回真实显示顺序(便于测试直接断言所见即所得),"all" 保持原始正序。既有断言(单元素/`set()`/`len`)全部不受影响,140 项一次通过。
|
||||
|
||||
## 未验证项
|
||||
|
||||
无平台相关项(纯 UI 排序逻辑,offscreen 已全量覆盖)。
|
||||
Reference in New Issue
Block a user