⚠️ 根因已订正:真根因是 observe.ts:1406 嵌套去重(非命名 isContainer),见 订正评论。下方原文保留作审计。
[observe] 嵌套 cursor:pointer 子按钮被去重吞掉,多 CTA 卡片/弹出菜单的子项 observe→act 够不到
Labels: bug, observe, P1
发现来源: N0062 vortex 生产能力评测 V3(班牛预发深度复测,2026-06-11,基线 047f3df)
现象
当一个 cursor:pointer 容器内含多个功能不同的 cursor:pointer 子按钮时,vortex_observe 只暴露最外层一个合并 ref,内部子按钮全部丢失。点击合并 ref 命中容器几何中心,往往是插图/描述等非动作区 → 点击无效。agent 仅靠 observe → act 无法触达子按钮,必须 vortex_evaluate 兜底。
复现(班牛,跨环境 3 次稳定复现)
环境:https://newbeta.bytenew.com/app.html(预发,也在 testc.bytenew.com 复现)
实例 1 — 创建工作表卡片
- 进入空白 applet 首页,observe 中间「创建工作表」卡片
- observe 仅得一个 ref,名为整片拼接文本
创建工作表…创建空白工作表模板中心创建
vortex_act click 该 ref → 命中卡片中心(插图),effect.domMutations≈8,无导航
- 但卡片内
创建空白工作表 / 模板中心 / 创建 是 3 个功能不同的子按钮,均未单独暴露
ground-truth 对照:对 创建空白工作表 span 直接 dispatch click(pointerdown/mousedown/.../click)→ location.hash 从 #/applet/appNew/appEmptyNew/12261/0 跳到 #/workCreate/12261,导航成功。证明子按钮才是正确目标。
实例 2 — 弹出菜单:点 addcube(+) 弹出菜单「模板中心创建 / 新建空白小程序」两项被合并成单一 tooltip ref,无法分别 targeting。
DOM 结构
DIV.create-box-list-item.createBox (cursor:pointer) ← observe 暴露的合并 ref
└ DIV.create-box-list-item-box.box1 (cursor:pointer)
└ SPAN "创建空白工作表" (cursor:pointer) ← 真实点击目标,未暴露
└ (模板中心 / 创建 ...) (cursor:pointer) ← 同样未暴露
根因(推断,待 bench 实证)
packages/extension/src/handlers/observe.ts 命名逻辑(约 717-730 行)的 isContainer 判定:
const isContainer =
el.querySelector(
"a[href],button,input,select,textarea,[tabindex],[contenteditable=true]",
) != null;
if (text && !isContainer) return text; // 非容器 → 用整片 textContent 命名为单一 leaf
...
if (isContainer) return ""; // 容器 → 返空交噪声过滤丢弃,内部交互项另行收集
isContainer 只检查原生交互后代,不含 cursor:pointer 后代。因此"内部只含 cursor:pointer 子按钮"的卡片不被判为容器拆分,而被当作单一 leaf 用整片 textContent 命名,子按钮丢失。
期望
容器内含多个独立 click 行为的 cursor:pointer 子元素时,应分别暴露为可 targeting 的 ref(或将 cursor:pointer 后代纳入 isContainer 判定,让外层卡片被当容器、子按钮单独收集)。
修复注意
- 与
aria-cursor-dedup / 自主发现引擎(子项目 0022)同族,dedup 策略改动易引入噪声回归 → 必须配 bench fixture + 单测(建议新增"多 CTA 卡片"+"弹出菜单多项"两个 fixture)。
- 仅当子
cursor:pointer 元素确有独立 click 行为/导向不同动作时才拆分,避免把"整卡可点"的纯展示卡片拆碎。
复合风险
若该缺陷出现在跨域 iframe 内(如班牛 VOC voc-testc.bytenew.com),vortex_evaluate 兜底不可用(跨域 evaluate 设计禁用),将彻底卡死该路径。
[observe] 嵌套 cursor:pointer 子按钮被去重吞掉,多 CTA 卡片/弹出菜单的子项 observe→act 够不到
现象
当一个
cursor:pointer容器内含多个功能不同的cursor:pointer子按钮时,vortex_observe只暴露最外层一个合并 ref,内部子按钮全部丢失。点击合并 ref 命中容器几何中心,往往是插图/描述等非动作区 → 点击无效。agent 仅靠observe → act无法触达子按钮,必须vortex_evaluate兜底。复现(班牛,跨环境 3 次稳定复现)
环境:
https://newbeta.bytenew.com/app.html(预发,也在testc.bytenew.com复现)实例 1 — 创建工作表卡片
创建工作表…创建空白工作表模板中心创建vortex_act click该 ref → 命中卡片中心(插图),effect.domMutations≈8,无导航创建空白工作表 / 模板中心 / 创建是 3 个功能不同的子按钮,均未单独暴露ground-truth 对照:对
创建空白工作表span 直接 dispatch click(pointerdown/mousedown/.../click)→location.hash从#/applet/appNew/appEmptyNew/12261/0跳到#/workCreate/12261,导航成功。证明子按钮才是正确目标。实例 2 — 弹出菜单:点 addcube(+) 弹出菜单「模板中心创建 / 新建空白小程序」两项被合并成单一
tooltipref,无法分别 targeting。DOM 结构
根因(推断,待 bench 实证)
packages/extension/src/handlers/observe.ts命名逻辑(约 717-730 行)的isContainer判定:isContainer只检查原生交互后代,不含cursor:pointer后代。因此"内部只含 cursor:pointer 子按钮"的卡片不被判为容器拆分,而被当作单一 leaf 用整片 textContent 命名,子按钮丢失。期望
容器内含多个独立 click 行为的
cursor:pointer子元素时,应分别暴露为可 targeting 的 ref(或将cursor:pointer后代纳入isContainer判定,让外层卡片被当容器、子按钮单独收集)。修复注意
aria-cursor-dedup/ 自主发现引擎(子项目 0022)同族,dedup 策略改动易引入噪声回归 → 必须配 bench fixture + 单测(建议新增"多 CTA 卡片"+"弹出菜单多项"两个 fixture)。cursor:pointer元素确有独立 click 行为/导向不同动作时才拆分,避免把"整卡可点"的纯展示卡片拆碎。复合风险
若该缺陷出现在跨域 iframe 内(如班牛 VOC
voc-testc.bytenew.com),vortex_evaluate兜底不可用(跨域 evaluate 设计禁用),将彻底卡死该路径。