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.
5.3 KiB
5.3 KiB
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(本就复用实例)。
关键设计决策
- 排序键 =
self._order中的位置(稳定启动序号),不引入时间戳、不改 schema。 面板的_order在三个入口按启动先后追加:set_session()DB 重建:消息链顺序 + 时间线内顺序(= backlog 要求的「稳定启动序号」构造方式);set_session()活动流:时间线内顺序(当前轮次天然晚于历史);- 实时
on_started():事件到达顺序。_order即启动序号本身,_refresh()只需对其取逆即可,无需任何新字段。
- 只在显示层取逆,不改内部数据。
run_ids/done_ids仍按_order正序过滤;reversed()只作用于传给set_layers的 widget 列表。已完成栏限量窗口done_ids[-LAYER_LIMIT:]的成员不变(仍是「最近启动的 30 个」),仅窗口内显示顺序反转,提示语文义保持。 - 完成时间从不参与排序。
on_finished对已知层只改状态集合(_running→_done),绝不移动_order位置;仅当层完全未知(先收到 finished 事件)才以首次感知时间追加——这是唯一的信息可用时刻。因此「先启动后完成」的任务永远压在「后启动先完成」的任务之下,与结束先后无关(P11.10/P11.13 断言)。 - 状态保持靠「同一对象」。
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)。
测试中发现并处理的问题
- Qt 布局 flush 会重置代码框水平滚动(测试时序伪影,非产品 bug):展开层与
setValue同 tick 执行时,out_box的终宽布局尚未 flush,随后任何布局事件(如新任务触发的set_layers)应用挂起 resize 会把水平滚动清零。探针矩阵(N1×N2 settle 圈数)证实:setValue前至少一次事件循环(N2≥1)则滚动稳定保持。真实用户不可能在未渲染的框上滚动,故测试在设滚动值前补settle(120)并在注释中记录该伪影。 smoke_bash_panel.py解释器退出挂起:末行sys.exit(0)后 QtWebEngine 渲染/GPU 子进程(offscreen)不回收,进程挂到 timeout 124;此前跑该文件若经管道只看输出会误判通过。改为仓库 offscreen harness 惯例os._exit(code)(stdout 已 flush、临时文件已清理),EXIT=0 即时返回。layer_ids()口径:原返回启动正序;改为 running/done 返回真实显示顺序(便于测试直接断言所见即所得),"all" 保持原始正序。既有断言(单元素/set()/len)全部不受影响,140 项一次通过。
未验证项
无平台相关项(纯 UI 排序逻辑,offscreen 已全量覆盖)。