Skip to content

v2.4.1 —— 输入路径的三处静默故障

Choose a tag to compare

@Glittering Glittering released this 29 Oct 19:45
· 21 commits to main since this release

v2.4.1 —— 输入路径的三处静默故障

这一版没有新功能。它修的是**"读得到、打不进"**这一类问题:ui.get_tree 明明给出了
一个 id,ui.act 却告诉你"找不到这个元素",或者更糟 —— 动作返回成功,其实什么都没发生。

来源是一次三站点联调(Notion / Miro / Figma)。三个站点各有各的形态,而 Notion 暴露了
输入链路上三个互不相关的缺陷,每一个都把错误推给下一个。

1. 句柄来自元素原生 id,查找却只认 data-ai-id

抽取器在没有 data-ai-id 时用元素自己的 id 当句柄(existingAiId || nativeId)。
而 data-ai-id 只是页面里的一个普通属性 —— React 类应用重渲染那个子树时会把它一起抹掉,
元素本身还在。

实测(Notion 空段落):id=":r6:",data-ai-id 刚写就被抹空。于是 ui.get_tree 报
:r6:,ui.act 报 Target not found for ref: :r6:。

修法:属性查不到时按 getElementById 兜底,放在"穿透 shadow 的同一递归"里
(ShadowRoot 也有这个方法)。它不会把"不存在"变成"乱命中" —— 有阴性对照钉住。

2. focus() 不等于"可输入"

contenteditable 调 focus() 之后 document.activeElement 确实等于它 ——
所以"焦点坐上没有"这个判据看不出任何问题 —— 但 Notion 的块编辑器没进入编辑态,
随后所有受信按键全部落空,校验读到空,报 Input not verified。
真人点一下之后,activeElement 会交给编辑器自己的容器,按键才生效。

修法:contenteditable 一律先来一次真实指针点击。input/textarea 不加这一步 ——
原生控件 focus 就够,多点一下反而会把光标挪到中段,破坏 type 的 at:'end' 语义。

3. 校验读错对象 → 假阴性

清空 Notion 的空段落之后,它把焦点交还给页面(activeElement 变成 BODY),
校验读到的是整页文本,于是明明成功却报失败。

这个方向最危险:agent 看到失败会重试,对 type 就是写入两份重复内容。
修法:失败时再按"解析出来的那个可编辑元素"复核一次,命中就如实给成功并标
verified_by: 'target-element'。它不掩盖真错位 —— 文字若落进别的输入框,
目标元素里就没有它。

顺带修掉的(同一轮)

  • GPU 画布上 canvas_changed:false 是假阴性。Figma 的可见画布是 WebGPU,
    DOM 里 2D 画布 0 张,而绘制钩子照样记到帧 —— 那些来自页面自己建的离屏 2D 画布。
    一次真实的"宽度 100→200"改动,指纹一动不动,回执却说"证明没变"。
    现在钩子自述 g=1,上层把 canvas_changed / canvas_idle 一律降级成 null(不可判)。
    null 意味着"无法判断",不是"什么都没发生" —— 这句话现在也写进了
    ui.capabilities 的说明里。
  • data-ai-id 优先级:元素已有 data-ai-id 时必须优先沿用,不能被元素自己的 id
    改写。两条路径(AX 与 DOM 抽取)轮流改写同一个属性时,各自报出的 ref 都会被对方作废。

验证

  • 单测 1128 / 81 文件
  • e2e 23 套件 789 项全绿(richtext 117、readcov 99、capabilities 54、canvas 41…)
  • 真站点:Notion 写入→回读→还原;Miro create → get → sync → remove;
    Figma 属性写入 → Mirror DOM 自述 "Dimensions 150 100" → 还原

全部写入都是可逆的,且已还原到原状。