# Agent Note: GUI PR 的 GIF 证据与 assets 分支发布

Status: implemented
Archived: 2026-07-27

[English](2026-07-26-gui-pr-gif-evidence-and-assets-branch.md) | 中文

## 问题

改变产品用户在 GUI 中所见行为的 PR（Pull Request），此前只能通过文字描述和测试名称接受评审，两者都无法展示渲染结果。[浏览器演示 GIF 录制](../../../skills/record-browser-gif/SKILL.md)对应的 skill（技能）能生成真实可信的本地 GIF，但刻意止步于本地产物，于是每个想展示 GIF 的 PR 都得各自重新摸索发布方式；而把 GIF 提交到 PR 分支从来不可接受：进入历史的二进制媒体会永久增大之后每一次克隆的体积。

录制流程本身也在靠一次次失败反复重新学习：截图写到浏览器工具允许的根目录之外或写入不存在的目录，会在截取时直接失败；跨多次工具调用轮询的瞬态 UI 状态会丢失，因为调用之间轮次已经结算；用子串匹配做完成判定会命中用户自己提示词的回显；在编码器命令上内联赋值环境变量则因参数先于赋值展开而不生效。

## 决策

每个改变产品用户可见 GUI 行为的 PR 都包含一个用 [record-browser-gif skill](../../../skills/record-browser-gif/SKILL.md) 录制的演示 GIF，其来源必须真实：从该 PR 自身分支树启动的真实服务器、真实 API 密钥、真实的模型轮次，并在嵌入处注明来源。只有当用户明确要求 fixture（测试前置数据）来源时才可使用 fixture。

GIF 发布到专用的孤儿（orphan）assets 分支上：该分支没有父提交、只含媒体，GIF 绝不进入 PR 自己的分支；一个 assets 分支服务整个 PR 系列（现有分支：`code-mode-ui-assets`、`pr-613-assets`）。发布在浅层单分支的临时克隆中进行，提交信息形如 `assets: <what it shows> gif (#<pr>)`，PR 正文用带必需 `?raw=true` 后缀的 blob URL 嵌入。assets 分支只允许追加：已合并的 PR 正文会永远引用其 URL，因此 assets 分支绝不重写或删除。

录制本身保持无副作用；发布是一个有边界的收尾步骤，仅当任务包含把 GIF 附到 PR 时才由该 skill 执行。[record-browser-gif skill](../../../skills/record-browser-gif/SKILL.md) 仍是录制部分的现行契约。

该 skill 还吸收了录制实践换来的操作经验：帧文件放在仓库 `.gitignore` 忽略的 `.playwright-mcp/` 目录下并在截取前先创建，因为浏览器工具只能写入其允许的根目录，相对文件名也相对仓库根目录解析；每个 PR 从自己构建的分支树启动服务，配以全新的临时工作区目录，每个录制场景新开会话，停止服务器时按 PID 精确匹配而不是用宽泛的进程名模式；瞬态状态靠驱动一个缓慢的前台操作、并在同一次浏览器脚本调用内轮询具体的 DOM 标记来截取；完成判定匹配精确文本元素而非子串；编码器在单独一行 export `GIF_SKILL_DIR` 之后运行，逐帧时长让最终稳定状态停留最久，并同时核对 JSON 摘要与目视检查编码后的 GIF。

## 曾考虑的替代方案

**把 GIF 提交到 PR 分支。**合入默认分支的二进制媒体会留在历史中，影响之后的每一次克隆和拉取；演示 GIF 的价值止于评审，代价却永不消失。

**作为 GitHub 附件上传。**拖拽产生的 `user-attachments` 上传对命令行工作流不可用，无法从仓库重建或审计，媒体的生命周期也脱离仓库的控制。

**用 Git LFS 存储 GIF。**LFS 仍把媒体耦合进代码分支的历史，给每次克隆和 CI 拉取增加一项基础设施依赖，相比普通 git 即可支持的隔离分支没有任何额外收益。

**每个 PR 一个 assets 分支。**按 PR 建分支会让 ref 命名空间蔓延，并在一个系列内成倍增加临时克隆；每个系列一个分支让发布只需一次推送，同时仍与代码历史隔离。

**把发布留在录制 skill 之外。**这是此前的状态；它保住了干净的边界，却让每个 PR 重新摸索同一套流程。这个边界如今以显式条件的形式保留：仅当任务包含把 GIF 附到 PR 时才执行发布，而不是靠省略来体现。

**让 GIF 在每个 PR 中保持可选。**可选的证据恰恰会在最需要它的进度压力下消失；没有录制的 GUI 变更评审，等于要求评审人自行想象渲染结果或重新构建分支。

## 后果

每个 GUI PR 都携带注明来源的可视证据，评审人无需重新构建分支即可看到变更。仓库历史保持不含媒体；代价转移到只追加的 assets 分支上：它们会持续增长、可以低成本地浅克隆、且永远不能删除。强制的真实来源录制给每个 GUI PR 的工作流增加一次真实密钥、真实模型轮次的运行，这是有意为之，因为这次运行本身就是证据。录制部分仍然在本地可撤销；任务不包含附到 PR 的 GIF 请求，仍以已验证的本地产物结束。
