N.03 · 开发 · 2026.05.07 · 约 2 分钟

第一次给 OpenClaw 提 PR:别直接相信localStorage 里的 JSON

QA Lab 的保存视图把浏览器存储里的 JSON 直接当成界面状态。修复本身不大,难的是用真实环境证明它修好了。

5 月初,我给 OpenClaw 提了一个修复。问题出在 QA Lab 的 Capture 页面:它允许把一组筛选和展示设置保存成「saved view」,存进浏览器的 localStorage;下次打开时,再把这份 JSON 读出来,直接复制进界面状态。

问题在「直接」

读取时,代码把解析出来的对象直接当成 CaptureSavedView[] 用,没有任何校验,就把必填字段套进了界面。平时这没什么问题,因为写进去的都是自己生成的数据。可浏览器存储并不可信:旧版本留下的结构、手动改坏的值、或者别的代码写进来的东西,都会原样流进筛选条件和详情面板,让 QA Lab 出现莫名其妙的状态。

修复的思路很朴素:加一个 saved view 的规范化函数,在读取、保存、应用三个时机都过一遍。没有名字的条目、不是对象的条目直接丢掉;字段值不合法的,退回安全的默认值;数量设上限。再补上回归测试,覆盖非法条目、默认值和上限三种情况,并在 Unreleased 的变更记录里写一条。

我在 PR 里专门写了「这次没有改什么」:不重新设计保存视图的界面,不改 API,不碰抓取后端。外部贡献者最容易犯的错,是顺手做得太多,让维护者没法放心合并。

证明比修复更花时间

OpenClaw 要求外部 PR 提供真实行为的证明,单元测试通过还不够。于是我写了一段脚本:在 Windows 上启动真实的 QA Lab 服务,用 Playwright 驱动本机的 Chrome,先往 localStorage 里塞进几条坏掉的保存视图,再打开 Capture 页面、展开控件、应用保存视图,最后读出页面的实际状态。

结果和预期一致:没有名字和不是对象的条目被丢掉了,只剩下那条有名字的「Corrupt saved view」;它里面不合法的字段被安全地退回默认值,视图模式、分组、详情位置都落在默认档,只保留了一个有效的 provider 筛选。证据、截图和 JSON 都留在本地的产物目录里。

我也写明了没有测到的部分:完整的产品测试套件,以及这条本地路径之外的人工浏览器检查。

学到的事

后来这个修复合进了 OpenClaw 的主线,提交里也保留了我的署名。回头看,代码只有几十行,真正教会我的是两件事:边界上的数据都要当成不可信的输入来处理,哪怕它是「自己写进去的」;而说服别人合并你的代码,靠的是范围清楚、证据可复现,不是改动有多大。