Repository navigation
v2.4.0 — canvas 应用终于可验证了;窗口显示的自述不再撒谎
v2.4.0 — canvas 应用终于可验证了;窗口显示的自述不再撒谎
这一版解决的是同一类问题的两个面:工具说了假话。一处是把"没看见"说成"没变",
另一处是把"我等到了页面"说成事实而其实等到的只是我们自己的占位页。
1. 纯 canvas 应用的写入,现在能被证明(也终于能被证伪)
用 Excalidraw(无需登录、全球最典型的 canvas 白板)实测:拖出一个矩形,
ui.act 之所以报 page_changed:true,靠的是"选中图元后右侧属性面板出现"(DOM +48 节点)。
这是运气 —— 动作只要不产生面板副作用(移动已有图元、空白处涂色、连续调参),
DOM 就零字节变化,回执会说 page_changed:false + "payload most likely never landed",
把一次成功的写入说成失败。而 ui.diff 的差异条目里,一条来自画布的都没有。
现在注入页面的绘制记录器会累积两个值:
| 量 | 它回答什么 | 受采样相位影响 |
|---|---|---|
fp(自上次清屏以来的绘制序列哈希) |
画到什么程度了 | 是(落在帧中间就是前缀) |
last(最近一个完整帧的哈希) |
上一帧长什么样 | 否 |
ui.act 的回执因此新增三个字段:
| 页面形态 | canvas_changed |
canvas_idle |
canvas_repeat |
|---|---|---|---|
| 静止(空闲期没画) | true / false | true | false |
| 在重绘,但每帧内容相同 | true / false | false | true |
| 每帧都不一样(时钟/光标/直播) | null(判不了) |
false | false |
| 证据不足(无完整帧 / 后台被节流) | null |
null |
false |
请这样子读:false 是"有证据的没变",null 是"这一页判不了"。
把 null 当成 false 是最常见的误读 —— 它会让你重复执行一个其实已经成功的写入。
实测证据(夹具:每 16ms 重绘相同内容、只在第一次指针按下时多画一个方块):
第一次拖 → canvas_changed:true repeat:true 页面自述图元 1 → 2
第二次拖 → canvas_changed:false repeat:true 页面自述仍是 2 ← 以前这里只能是 null
也就是说,在一直动的画布上,工具现在能说出"你这一手真的没反应"。
2. ui.window_shown 不再把"我的占位页"说成"目标页面"
新标签页会先加载 loading.html 占位页(把白屏换成「正在打开 」),
而占位页自己也会发 dom-ready。于是记录里写着 show_reason:"dom-ready" +
waited_for_dom:true,而此刻目标文档一个字节都没到(外网不通时实测 body 恒为 578 字符)。
现在 show_reason 会如实给出 placeholder,waited_for_dom 只在目标文档就绪时为 true,
并新增 show_url(那一刻 webContents 上是哪一页 —— 占位页 URL 里带着目标地址,
正是最有用的那一半)。另外 fail-load 不再被算成"等到了 DOM"。
显示时机没有改变:占位页一就绪就显示是 2026-10-24 的决定(人先看到
「正在打开 」比看白屏好)。这次只让记录说真话。
3. 顺手修掉的两个缺陷
ui.capabilities的 endpoints 混进了别的标签页的请求({tabId}传给只读
filter.tab的函数,过滤静默失效)。实测:只打开 excalidraw 的实例里出现了
百度的/ztbox、/sugrec。agent 会照着这份清单去 fetch 与本页无关的接口。- 一个只在特定环境下才暴露的测试误报:
smoke用url.includes("/a")找标签页,
会命中占位页的file:///.../projects/ai-browser/...(路径里恰好含/a),
于是它切到占位页、读到「正在打开…」,红信息却指向"set_active_tab 坏了"。
验收
- 单测 1114 / 80 文件
- e2e 23 套件 789 项全绿(canvas 41、capabilities 54、nav 21、smoke 31)
仍然做不到(写在这里,免得被上面的好消息盖过)
- 读不出画了什么。帧指纹只回答"这一帧和上一帧一样不一样"。Excalidraw 实测是 2D
且一次fillText都没有(整帧clearRect+Path2D+ 离屏合成),所以
"2D canvas 就能读文字"不成立,ui.canvas_read对这类渲染器的texts[]是空的 ——
空不代表画布是空的。 - Figma / Miro / Notion 这类站点仍未真正测到(只拿到落地页或登录墙),
它们的唯一出路是应用数据模型层(React fiber / Yjs 运行时),需要可复现样本才动手。 - 浏览器内的远程桌面/VM 控制台(帧流 + 坐标点击)没有可验证路径,本版不含。