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

5.3 KiB
Raw Blame History

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);
  • 完成中间任务前后状态保持:对象 identityis)、展开态、实时输出文本、代码框水平滚动值(先强制非 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 已全量覆盖)。