Files
deepseek-harness/.agents/notes/archived/testing/2026-07-18-tui-terminal-state-snapshots.zh.md

6.4 KiB
Raw Blame History

Agent Note: TUI 语义终端状态快照

Status: implemented Archived: 2026-08-04

English | 中文

问题

TUI 是有状态的渲染器。用户最终看到的结果取决于 ANSI 解析、差分帧、换行、回滚缓冲、视口位置、终端宽度、焦点、光标状态,以及各工具的呈现意图。收集 Terminal.write() 片段的单元测试可以验证事件处理,却无法验证终端最终显示的画面。同一画面也可能由不同的写入片段产生,因此固定这些片段会制造误报。

组件行快照止于 ANSI 进入终端之前,无法覆盖光标移动、清屏、样式、浮层组合和重排。栅格截图会带入与 TUI 契约无关的字体和平台渲染噪声。直接追加看似合理的会话事件来构造完整流程还存在另一处盲区:这种测试只能证明渲染器接受这些数据形态,无法证明生产环境的 agent loop智能体循环和工具实现会生成这些事件。

因此,可复用 TUI 需要确定、便于评审的终端状态表示。交付它的产品部署还需要通过组装后的技术栈运行已录制模型流程,并保留一项范围更小、覆盖真实进程与 PTY 边界的测试。

决策

可复用 TUI 的覆盖分为两个互补的包级层次:

  1. packages/ui/tui/tests/tui.spec.ts 直接测试事件映射、输入路由、资源释放和错误行为。
  2. packages/ui/tui/tests/tui.snapshot.ts 将生产 TUI 挂载到无界面终端模拟器,覆盖完整会话日志无法保留的瞬态:进行中的流式输出、待完成工具调用、浮层、展开状态、压缩重排、错误和关闭过程。

显式配置入口决策移除了产品 TUI 组合、已录制应用流程和 PTY 测试套件。交付终端入口的部署负责这些组装应用层;包测试不声称提供产品覆盖。

已移除的应用回放

已删除的应用测试套件为每个场景提供 session.jsonl、可选的子会话日志 session.<n>.jsonl,以及 terminal.expected.txt。主日志提供用户来源的 user/message 提示词和已录制的 assistant/chunk 序列。dsh-llm-replay 为每个会话派生一份模型调用脚本,并且是测试中唯一的 mock 边界agent loop、工具、worker、呈现器和 TUI 都使用生产实现。

如果工具调用顺序不符、预期事件数量不足、工具结果报错、轮次以错误结束、工作流生命周期不完整,或者实时子会话数量与 fixture测试前置数据集合不一致该测试套件都会拒绝流程。这些检查仍是未来任何终端部署的验收模式它们已不再作为 fixture 交付。

已移除的录制工作流使用 DSH_SNAPSHOT=record 录制模型流程,使用 DSH_SNAPSHOT=refresh 更新派生的终端输出。移除产品入口时也从仓库快照通道中移除了这些模式;可复用 TUI 快照直接由包级场景编写。

语义终端投影

包内的 HeadlessTerminal 实现与进程终端相同的 pi-tui Terminal 接口,并把每次 ANSI 写入交给固定版本的 @xterm/headless 解析器。读取状态前,快照代码会等待同步帧稳定。流式输出检查点会冻结 loader 的 interval同时保留跨过一次动画 tick 的真实墙钟等待,从而固定语义状态,而非调度器碰巧渲染出的某个加载动画字形。

每份预期输出把终端尺寸、活动缓冲区和视口坐标、生命周期与光标状态、各行、换行标记以及非默认样式区间投影为文本。滚动内容较多的卡片捕获已使用缓冲区;浮层捕获可见视口。文本和样式相互分离,评审人无需解码 ANSI 字节即可区分内容变化与呈现变化。

每个检查点还会对完整终端状态强制执行主题无关性:禁止 RGB 颜色、禁止 ANSI 015 以外的调色板项,也禁止显式背景色。选择行使用终端默认色进行反显,因此仍然有效。两套测试都拥有封闭清单,会拒绝缺失的场景、缺失的检查点和遗留预期输出文件。

必需场景矩阵

层次 场景 固定的契约
瞬态 流式输出与待完成高级调用 进行中的推理和文本,以及完整日志中不会保留的待完成 Code Mode、工作流和 Cordis 卡片
瞬态 卡片、交互、布局、失败和关闭 折叠与展开的卡片族、问题校验、压缩替换、尺寸重排、帮助与错误、光标恢复和终端停止

曾考虑的替代方案

  • 快照原始终端写入:不予采纳,因为差分渲染可能在画面不变时改变写入边界,而且光标与清屏序列难以评审。
  • 快照进入终端输出之前的组件渲染行:不予采纳,因为它无法测试 ANSI 解析、光标移动、浮层、视口行为,也无法测试独立组件在同一帧中的相互作用。
  • 通过追加会话事件构造所有完整流程:不予采纳,因为人工编写的事件序列可能与 agent loop、工具执行、子会话绑定或 worker 行为发生偏差,但呈现测试仍然保持绿色。直接构造事件只用于渲染器瞬态。
  • 复用 ACP stdout 预期输出作为 TUI 判定依据:不予采纳,因为已录制模型流程与传输方式无关,其呈现方式却并非如此。终端部署拥有自己的预期输出,同时可以复用同一套 JSONL 回放词汇。
  • 提交栅格截图:不予采纳,因为字体、字形度量、抗锯齿和宿主终端主题会使结果依赖平台,也会增加语义样式变更的评审难度。
  • 只使用 PTY 端到端测试:不予采纳,因为原始 PTY 输出是一系列历史绘制操作而不是可查询的最终状态。PTY 测试保留真实 Loader、输入与清理边界模拟器负责广泛的状态覆盖。

后果

  • 当 TUI 事件映射或呈现损坏时,包快照会失败;它们不能代替组装应用的工具路径 transcript。
  • TUI 视觉回归会产生便于阅读的单元格和样式 diff而 JSONL fixture 会保留触发生产路径的确切模型分片。
  • 模拟器使用 xterm 的拟议缓冲区 API。升级 xterm 时必须重新运行并评审语义投影;终端特有行为仍需由交付该终端的部署所拥有的 PTY 冒烟测试覆盖。
  • 预期输出有意固定指定尺寸下的换行与视口行为。预期布局变更会更新并评审包级语义快照。