DSH / Atlas
2026-08-08implementedprocessarchived 2026-09-30

Browser GIFs preserve one evidence chain

浏览器 GIF 保留单一证据链

A browser-demo storyboard can contain individually truthful screenshots without proving one truthful execution. Reusing global application state can admit old settings or sessions, capture automation can accidentally combine frames from separate model runs, and a chat transcript can show a successful fallback without exposing the tool rejection that caused it. Fuzzy accessible-name matching can also accept prompt ech

English

Problem

A browser-demo storyboard can contain individually truthful screenshots without proving one truthful execution. Reusing global application state can admit old settings or sessions, capture automation can accidentally combine frames from separate model runs, and a chat transcript can show a successful fallback without exposing the tool rejection that caused it. Fuzzy accessible-name matching can also accept prompt echoes or descendant text instead of the intended result.

Headless production recording has two further boundaries. A product default may open a native operating-system surface that automation cannot drive, while replacing that surface with a mock or test hook would mean the GIF no longer shows the production path. After publication, a successful upload or push does not prove that the uploaded asset is reachable and intact on the review path, or that GitHub recognizes the pull-request Markdown as an image.

Decision

The record-browser-gif workflow treats one storyboard as one evidence chain pinned to an exact pull-request head. Before building, it requires a clean worktree and records that commit SHA. Each run uses fresh DSH_HOME, DSH_AGENTS_HOME, workspace, session, and isolated browser state, and every published frame comes from the same server and model-backed scenario run. When a fresh browser context is unavailable, the exact origin's cookies and site storage are cleared before navigation. Existing user browser state is used only when requested or required, is stated next to the GIF, and does not substantiate fresh client state. A failed capture run is discarded and repeated from fresh roots rather than combined with another run.

Browser automation waits for unique, exact semantic states. When the claim concerns a tool call, rejection, or recovery, the storyboard includes a detail or trajectory frame that identifies the tool, shows its status or stable error code, and shows the downstream result. The final encoded GIF remains the verification subject; when a viewer cannot animate it, representative frames are decoded from that GIF instead of treating source screenshots as equivalent evidence.

The available browser-control workflow remains preferred. When it is unavailable, the recorder uses the repository-declared Playwright dependency in an isolated headless browser rather than installing another driver or opening the user's browser. A native production surface may be replaced only through normal application configuration with an official browser-operable production backend, and that override is stated next to the GIF. Fixtures, mock transports, synthetic events, and test-only hooks do not substantiate a real-production claim.

Publication verifies the boundary again. The preferred path attaches with gh --attach (v2.99.0 or later; github.com only; at most 10 MB): the body file references the local GIF path, the command uploads the verified artifact and rewrites that reference in place, and the live body must then show the rewritten uploaded URL, which must respond with 200 and image/gif. When attach cannot apply — the GIF exceeds 10 MB, gh is older, or the repository is GitHub Enterprise Server — the assets-branch path remains: the branch contains media only, the staged and published bytes match the verified artifact, and a private-repository asset is checked through authenticated API or raw requests for its path, byte size, checksum, response status, and media type, proving only the repository-member review path (the documentation-site image decision owns why a public site cannot depend on a private raw URL). Immediately before the pull-request body changes, the live head must still equal the recorded head. After the edit, the live head is checked again and must remain at that recorded value; GitHub's Markdown renderer separately must produce the expected image.

Alternatives considered

Allow frames from separate runs when their visible states look equivalent. Visual similarity does not establish shared state, causal order, or one scenario execution. Re-recording costs another real round but preserves the claim the storyboard makes.

Use the chat transcript as sufficient proof of tool recovery. A final answer proves that the task completed, but it can hide which tool ran, whether the failure was structured, and whether the model recovered from that failure. A trajectory or detail frame carries those facts directly.

Replace inaccessible native UI with a fixture or test hook. That makes automation easier by changing the product path under observation. Selecting an official production backend through normal configuration keeps the exercised implementation real and makes the narrower mode explicit.

Trust a successful upload or push. An upload or push proves only that GitHub accepted the bytes, not that the body reference points at the uploaded asset or that the Markdown renders the image. Re-reading the live body and rendering it through GitHub's Markdown API test the two publication boundaries reviewers use.

Consequences

GUI evidence now establishes one causal execution rather than a collage of plausible states, and reviewers can inspect both a structured tool failure and the completed result. Publication detects stale pull-request heads, corrupted or misplaced media, and invalid image Markdown before the body is treated as finished.

The workflow spends additional scratch state, may repeat a real model round after a capture failure, and usually adds a detail frame plus publication checks — live head and body re-reads, Markdown rendering, and an uploaded-URL fetch; the assets-branch path adds its authenticated asset checks. Headless recordings can use fewer production backends than an interactive desktop, and every selected backend is stated next to the GIF.

中文

问题

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

无头模式下的生产环境录制还有两道边界。产品默认配置可能打开自动化无法操控的原生操作系统界面,而用 mock 或测试钩子替换该界面,就意味着 GIF 不再展示生产路径。发布之后,上传或推送成功也不能证明上传的资产在评审路径上可达且完好,或 GitHub 能将 PR(Pull Request)的 Markdown 识别为图片。

决策

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

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

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

发布环节会再次验证边界。首选路径使用 gh --attach 上传(v2.99.0 或更高版本;仅限 github.com;不超过 10 MB):正文文件引用本地 GIF 路径,命令上传已验证的产物并把该引用就地改写,之后在线正文必须显示改写后的上传 URL,且该 URL 必须返回 200 与 image/gif。当 attach 无法使用时——GIF 超过 10 MB、gh 版本过旧或仓库位于 GitHub Enterprise Server——仍保留资产分支路径:该分支只包含媒体文件,暂存和发布的字节必须与已验证产物一致,私有仓库中的资产须通过经身份验证的 API 或原始内容请求检查其路径、字节大小、校验和、响应状态和媒体类型,这只能证明仓库成员的评审访问路径(文档站点图片决策解释了公共站点为何不能依赖私有的原始内容 URL)。修改 PR 正文之前,必须再次确认在线 head 仍与录制时的 head 相同。编辑后还要再次检查在线 head,且它必须保持为该记录值;GitHub 的 Markdown 渲染器则须单独生成预期图片。

曾考虑的替代方案

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

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

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

**相信上传成功,或相信推送成功。**上传或推送只能证明 GitHub 接受了相应字节,不能证明正文引用指向已上传的资产,或 Markdown 能把图片渲染出来。重新读取在线正文并经 GitHub 的 Markdown API 渲染,覆盖了评审者实际使用的两道发布边界。

后果

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

该工作流会占用额外的临时状态;录制失败后,可能需要再运行一次由真实模型驱动的场景;通常还会增加一张详情帧以及发布检查——在线 head 与正文的复读、Markdown 渲染和上传 URL 请求;资产分支路径还会增加其经身份验证的资产检查。相比交互式桌面,无头录制可使用的生产后端更少;每个所选后端都会在 GIF 旁说明。