# Agent Note: 浏览器 GIF 保留单一证据链

Status: implemented

[English](2026-08-08-browser-gif-evidence-chain.md) | 中文

## 问题

浏览器演示的分镜可以由每张都真实的截图组成，却无法证明这些截图来自同一次真实执行。复用应用全局状态可能引入旧设置或旧会话；录制自动化可能误将不同模型运行的画面合并；聊天 transcript（文本记录）可能显示降级处理成功，却没有揭示触发降级的工具拒绝。按无障碍名称进行模糊匹配，还可能误把提示词回显或后代文本当成预期结果。

无头模式下的生产环境录制还有两道边界。产品默认配置可能打开自动化无法操控的原生操作系统界面，而用 mock 或测试钩子替换该界面，就意味着 GIF 不再展示生产路径。发布之后，git 推送成功也不能证明私有仓库中的 GIF 可以获取，或 GitHub 能将 PR（Pull Request）的 Markdown 识别为图片。

## 决策

[`record-browser-gif`](../../../skills/record-browser-gif/SKILL.md) 工作流将一套分镜作为同一次执行的完整证据，并关联到精确的 PR head。构建之前，工作流要求 worktree 干净并记录其 commit SHA。每次运行都使用全新的 `DSH_HOME`、`DSH_AGENTS_HOME`、工作区、会话和隔离浏览器状态，所有发布帧均来自同一个服务器及同一次由模型驱动的场景执行。无法创建全新浏览器上下文时，应在导航之前清除该 origin 的 cookie 和站点存储。只有用户提出要求或确有必要时才能使用用户已有的浏览器状态；必须在 GIF 旁说明使用了该状态，并不得以此证明客户端状态全新。录制失败时，丢弃该次运行并从全新的状态根目录重新执行，不与另一次运行合并。

浏览器自动化会等待唯一且精确的语义状态。如果需要证明工具调用、拒绝或恢复，分镜就必须包含详情帧或轨迹帧：标明工具、显示其状态或稳定错误码，并展示后续结果。最终编码出的 GIF 始终是验证对象；如果查看器无法播放动画，应从该 GIF 中解码出代表性帧，而不能将源截图视为等效证据。

仍应优先使用已有的浏览器控制工作流。如果该工作流不可用，录制程序应在隔离的无头浏览器中使用仓库已声明的 Playwright 依赖，而不是安装其他驱动或打开用户的浏览器。只有通过正常应用配置选用官方且可由浏览器操作的生产后端，才能替换原生生产界面，并且必须在 GIF 旁注明这一覆盖。fixture（测试前置数据）、mock 传输层、合成事件和测试专用钩子均不能支撑真实生产实现的主张。

发布环节会再次验证边界。资产分支只包含媒体文件，暂存和发布的字节必须与已验证产物一致；对于私有仓库中的资产，应通过经身份验证的 API 或原始内容请求，检查其路径、字节大小、校验和、响应状态和媒体类型。这只能证明仓库成员的评审访问路径；[文档站点图片决策](2026-08-06-doc-site-carries-its-images.md)解释了公共站点为何不能依赖私有的原始内容 URL。修改 PR 正文之前，必须再次确认在线 head 仍与录制时的 head 相同。编辑后还要再次检查在线 head，且它必须保持为该记录值；GitHub 的 Markdown 渲染器则须单独生成预期图片。

## 曾考虑的替代方案

**只要可见状态看起来等价，就允许使用不同运行的画面。**视觉相似不能证明各画面共享同一状态、具有因果顺序或来自同一次场景执行。重新录制需要再执行一次真实模型轮次，但能维持整套分镜所表达的主张。

**将聊天 transcript 视为工具恢复的充分证据。**最终答案能证明任务已经完成，却可能隐藏调用了哪个工具、失败是否为结构化失败，以及模型是否从该失败中恢复。轨迹帧或详情帧可以直接承载这些事实。

**使用 fixture 或测试钩子替换无法访问的原生 UI。**这种做法通过改变被观察的产品路径来简化自动化。通过正常配置选用官方生产后端，既能保持受测实现真实，也能明确表述所采用的较窄运行模式。

**相信资产分支推送成功，或依赖匿名请求。**推送只能证明 git 接受了相应字节，而私有仓库会有意拒绝未经身份验证的原始内容请求。经身份验证的字节校验与 GitHub Markdown 渲染验证，覆盖了评审者实际使用的两道发布边界。

## 后果

GUI 证据现在能证明一次具有因果关系的执行，而不会把不同执行中的可信画面当作同一次执行的证据；评审者既可以检查结构化的工具失败，也可以检查最终完成的结果。在 PR 正文被视为完成之前，发布验证可以发现陈旧的 PR head、损坏或位置错误的媒体文件，以及无效的图片 Markdown。

该工作流会占用额外的临时状态；录制失败后，可能需要再运行一次由真实模型驱动的场景；通常还会增加一张详情帧和经身份验证的发布检查。相比交互式桌面，无头录制可使用的生产后端更少；每个所选后端都会在 GIF 旁说明。
