Files
Haocode/docs/agent-handoff/evidence/P2-01.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

51 lines
5.3 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.
# 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.1P11.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.13bd)。
## 验证(全部显式 timeout
| 套件 | 结果 | 预算 |
|---|---|---|
| `tests/smoke_bash_panel.py`(含新增 P11 节) | **ALL PASS140 项断言)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.9P11.13);
- **完成中间任务前后状态保持**:对象 identity(`is`)、展开态、实时输出文本、代码框水平滚动值(先强制非 0)、section 垂直滚动值(用 20 行内容撑出真实滚动范围后设 30)在重排后逐项相等(P11.3P11.8、P11.13bd);
- **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 已全量覆盖)。