14 KiB
N13 UIA Selector Catalog Design
日期:2026-07-09
1. 目标
N13 的目标是基于已 ACCEPT 的 N12R live UIA 证据,设计一套只读 selector catalog 和定位验证流程。
本阶段只做设计,不新增 helper op,不新增 MCP tool,不点击、不输入、不打开会话、不发送消息、不传输文件。
N13 完成后,下一步才可以写独立实现计划,考虑是否新增只读定位验证能力。
2. 输入证据
N12R 返回包已通过外网 validator:
runs/internal-sandbox-live-capture-reports/2026-07-09-retry-2/2026-07-08-internal-sandbox-a-validation.md
Decision: ACCEPT
PASS: 36
WARN: 1
FAIL: 0
使用的 UIA dump:
runs/internal-sandbox-live-capture-intake/2026-07-09-retry-2/2026-07-08-internal-sandbox-a/uia/dump-uia-main.json
关键事实:
root control_type: Window
root automation_id: frmMain
root class_name: WindowsForms10.Window.8.app.0.d3a00f_r29_ad1
framework_id: WinForm
UIA node count: 66
max_depth: 7
本设计只引用结构性字段,不依赖敏感可见文本。
3. 非目标
N13 不做以下事项:
自动登录
搜索联系人
打开会话
点击控件
输入文本
发送消息
发送文件
接收文件
读取或导出聊天内容
注入进程
hook
读取目标进程内存
绕过终端安全/安防
N13 也不把 search_contacts、open_conversation、read_latest_messages 作为当前实现目标。这些只能在 selector catalog 稳定、只读定位验证通过、并形成新的审批设计后再讨论。
4. 推荐方案
采用“selector catalog + 只读定位验证”方案。
核心思想:
- 用 N12R UIA dump 建立一份 selector catalog。
- 每个 selector 都只描述如何识别一个 UIA 节点。
- selector 的初始用途只允许 read-only locate。
- 后续如果实现
locate_uia,也只能返回匹配节点摘要,不执行任何 UI 动作。 - 任何真实动作类能力必须另写设计、计划和审批边界。
5. Selector 数据模型
建议 selector 条目使用以下字段:
{
"id": "main_window",
"description": "主窗口",
"allowed_use": "read_only_locate",
"required": {
"automation_id": "frmMain",
"control_type": "Window",
"framework_id": "WinForm"
},
"preferred": {
"class_name_prefix": "WindowsForms10.Window.8.app.0",
"path_hint": "root"
},
"fallback": [
{
"control_type": "Window",
"class_name_prefix": "WindowsForms10.Window.8.app.0",
"child_automation_id_contains": ["panelLeft", "ucPluginTabControl1"]
}
],
"stability_score": 95,
"evidence": {
"capture_id": "2026-07-08-internal-sandbox-a",
"uia_path": "root"
}
}
字段含义:
id:稳定、短小、英文蛇形命名。description:中文说明。allowed_use:N13 固定为read_only_locate。required:必须同时满足的字段。preferred:加分项,用于减少误匹配。fallback:主 selector 失效时的只读匹配策略。stability_score:0 到 100,越高越稳定。evidence:来源证据路径和 UIA 路径。
6. 初始 selector catalog
6.1 主窗口:main_window
{
"id": "main_window",
"description": "iSphere / IMPlatformClient 主窗口",
"allowed_use": "read_only_locate",
"required": {
"automation_id": "frmMain",
"control_type": "Window",
"framework_id": "WinForm"
},
"preferred": {
"class_name_prefix": "WindowsForms10.Window.8.app.0",
"path_hint": "root"
},
"fallback": [
{
"control_type": "Window",
"class_name_prefix": "WindowsForms10.Window.8.app.0",
"child_automation_id_contains": ["panelLeft", "ucPluginTabControl1"]
}
],
"stability_score": 95,
"evidence": {
"uia_path": "root"
}
}
理由:automation_id=frmMain 出现在根节点;root 是 N12R 已确认主窗口,稳定性最高。
6.2 主 tab 容器:main_plugin_tab
{
"id": "main_plugin_tab",
"description": "主功能 tab 容器",
"allowed_use": "read_only_locate",
"required": {
"automation_id": "ucPluginTabControl1",
"control_type": "Pane",
"framework_id": "WinForm"
},
"preferred": {
"path_hint": "root/3",
"ancestor_selector": "main_window"
},
"fallback": [
{
"ancestor_selector": "main_window",
"control_type": "Pane",
"child_automation_id_contains": ["FrmHomePage", "ucTabPage"]
}
],
"stability_score": 90,
"evidence": {
"uia_path": "root/3"
}
}
理由:该节点直接挂在主窗口下,automation_id 明确,子结构包含首页和 tab 内容区。
6.3 首页窗口:home_page_window
{
"id": "home_page_window",
"description": "首页内容窗口",
"allowed_use": "read_only_locate",
"required": {
"automation_id": "FrmHomePage",
"control_type": "Window",
"framework_id": "WinForm"
},
"preferred": {
"path_hint": "root/3/0/0",
"ancestor_selector": "main_plugin_tab"
},
"fallback": [
{
"ancestor_selector": "main_plugin_tab",
"control_type": "Window",
"class_name_prefix": "WindowsForms10.Window.8.app.0"
}
],
"stability_score": 82,
"evidence": {
"uia_path": "root/3/0/0"
}
}
理由:该节点可用于确认当前主 UI 内容区存在,但不用于动作。
6.4 tab 内容窗口:tab_page_content
{
"id": "tab_page_content",
"description": "tab 页内容窗口",
"allowed_use": "read_only_locate",
"required": {
"automation_id": "FrmTabPageContent",
"control_type": "Window",
"framework_id": "WinForm"
},
"preferred": {
"path_hint": "root/3/1/0",
"ancestor_selector": "main_plugin_tab"
},
"fallback": [
{
"ancestor_selector": "main_plugin_tab",
"control_type": "Window",
"child_control_type_contains": ["TitleBar"]
}
],
"stability_score": 82,
"evidence": {
"uia_path": "root/3/1/0"
}
}
理由:可作为后续只读结构检查的内容区域锚点。
6.5 左侧面板:left_panel
{
"id": "left_panel",
"description": "左侧主面板",
"allowed_use": "read_only_locate",
"required": {
"automation_id": "panelLeft",
"control_type": "Pane",
"framework_id": "WinForm"
},
"preferred": {
"path_hint": "root/4",
"ancestor_selector": "main_window"
},
"fallback": [
{
"ancestor_selector": "main_window",
"control_type": "Pane",
"child_automation_id_contains": ["ucPnlRoster1", "ucFuzzyQuery1"]
}
],
"stability_score": 92,
"evidence": {
"uia_path": "root/4"
}
}
理由:该节点是联系人/搜索相关区域的稳定父节点。
6.6 组织/联系人容器:roster_panel
{
"id": "roster_panel",
"description": "组织/联系人容器外层",
"allowed_use": "read_only_locate",
"required": {
"automation_id": "ucPnlRoster1",
"control_type": "Pane",
"framework_id": "WinForm"
},
"preferred": {
"path_hint": "root/4/0/0",
"ancestor_selector": "left_panel"
},
"fallback": [
{
"ancestor_selector": "left_panel",
"control_type": "Pane",
"child_automation_id_contains": ["ucRoster1"]
}
],
"stability_score": 88,
"evidence": {
"uia_path": "root/4/0/0"
}
}
理由:该节点是 roster 结构外层,可以只读验证联系人区域是否存在。
6.7 组织/联系人列表:roster_view
{
"id": "roster_view",
"description": "组织/联系人列表区域",
"allowed_use": "read_only_locate",
"required": {
"automation_id": "ucRoster1",
"control_type": "Pane",
"framework_id": "WinForm"
},
"preferred": {
"path_hint": "root/4/0/0/0",
"ancestor_selector": "roster_panel"
},
"fallback": [
{
"ancestor_selector": "roster_panel",
"control_type": "Pane",
"class_name_prefix": "WindowsForms10.Window.8.app.0"
}
],
"stability_score": 86,
"evidence": {
"uia_path": "root/4/0/0/0"
}
}
理由:该节点本次 child_count 为 0,不能证明列表项结构;只能作为区域存在性 selector。
6.8 搜索组件外层:fuzzy_query_panel
{
"id": "fuzzy_query_panel",
"description": "模糊搜索组件外层",
"allowed_use": "read_only_locate",
"required": {
"automation_id": "ucFuzzyQuery1",
"control_type": "Pane",
"framework_id": "WinForm"
},
"preferred": {
"path_hint": "root/4/1/0",
"ancestor_selector": "left_panel"
},
"fallback": [
{
"ancestor_selector": "left_panel",
"control_type": "Pane",
"child_automation_id_contains": ["FrmFuzzyQuery"]
}
],
"stability_score": 90,
"evidence": {
"uia_path": "root/4/1/0"
}
}
理由:该组件是搜索输入框的稳定父级。
6.9 搜索窗口:fuzzy_query_window
{
"id": "fuzzy_query_window",
"description": "模糊搜索内部窗口",
"allowed_use": "read_only_locate",
"required": {
"automation_id": "FrmFuzzyQuery",
"control_type": "Pane",
"framework_id": "WinForm"
},
"preferred": {
"path_hint": "root/4/1/0/0",
"ancestor_selector": "fuzzy_query_panel"
},
"fallback": [
{
"ancestor_selector": "fuzzy_query_panel",
"control_type": "Pane",
"child_automation_id_contains": ["skinAlphaTxt"]
}
],
"stability_score": 88,
"evidence": {
"uia_path": "root/4/1/0/0"
}
}
理由:该节点包含搜索输入框,是后续只读定位验证中的关键父节点。
6.10 搜索输入框:fuzzy_search_edit
{
"id": "fuzzy_search_edit",
"description": "模糊搜索输入框",
"allowed_use": "read_only_locate",
"required": {
"automation_id": "skinAlphaTxt",
"control_type": "Edit",
"framework_id": "WinForm"
},
"preferred": {
"class_name": "WindowsForms10.EDIT.app.0.d3a00f_r29_ad1",
"path_hint": "root/4/1/0/0/2",
"ancestor_selector": "fuzzy_query_window"
},
"fallback": [
{
"ancestor_selector": "fuzzy_query_window",
"control_type": "Edit",
"class_name_prefix": "WindowsForms10.EDIT.app.0"
}
],
"stability_score": 93,
"evidence": {
"uia_path": "root/4/1/0/0/2"
}
}
理由:该节点 automation_id、control_type 和 class_name 都明确。N13 只允许定位它,不允许输入搜索词。
7. 只读定位验证规则
后续如果实现定位验证,只能做以下事情:
- 接收 selector id。
- 读取当前窗口 UIA 树。
- 按 selector required 字段过滤节点。
- 用 preferred 字段排序或加分。
- 如果主 selector 无匹配,再尝试 fallback。
- 返回节点摘要:
selector_id、matched、match_count、path、control_type、automation_id、class_name、framework_id、is_enabled、is_offscreen、bounds。
禁止返回完整 visible text。可见文本只能返回以下派生信息:
has_name: true/false
name_length: number
禁止执行:
InvokePattern
ValuePattern.SetValue
SelectionItemPattern.Select
ExpandCollapsePattern.Expand
点击
键盘输入
剪贴板操作
窗口激活
焦点切换
8. 稳定性评分规则
建议评分:
95-100: root 或唯一主窗口级 anchor
90-94: automation_id 明确、control_type 明确、父子路径稳定
80-89: automation_id 明确,但可能依赖 tab 或运行状态
70-79: 缺 automation_id,但 class/control/path 组合可用
0-69: 不进入首批 catalog
本次首批 selector 全部要求 automation_id 明确。
9. 错误处理设计
只读定位验证应返回结构化结果,不抛出模糊错误。
建议结果:
{
"ok": true,
"selector_id": "fuzzy_search_edit",
"matched": true,
"match_count": 1,
"matches": [
{
"path": "root/4/1/0/0/2",
"control_type": "Edit",
"automation_id": "skinAlphaTxt",
"class_name": "WindowsForms10.EDIT.app.0.d3a00f_r29_ad1",
"framework_id": "WinForm",
"has_name": true,
"name_length": 0
}
],
"warnings": []
}
未匹配时:
{
"ok": true,
"selector_id": "fuzzy_search_edit",
"matched": false,
"match_count": 0,
"matches": [],
"warnings": ["selector_not_found"]
}
selector 定义非法时:
{
"ok": false,
"selector_id": "fuzzy_search_edit",
"error": {
"code": "INVALID_SELECTOR",
"message": "selector required fields are incomplete"
}
}
10. 测试策略
N13 设计阶段不写实现代码,但后续实现计划必须包含以下测试:
- 从 N12R dump fixture 读取 UIA 树。
- 验证
main_window匹配唯一 root。 - 验证
left_panel匹配root/4。 - 验证
fuzzy_search_edit匹配root/4/1/0/0/2。 - 验证 selector 不返回完整
name文本,只返回has_name和name_length。 - 验证缺失 selector 返回
matched=false,不报崩溃。 - 验证动作模式字段或动作请求被拒绝。
- 验证 catalog 中不包含
send、upload、download、conversation、login等动作词作为工具名。
11. 文件规划
如果后续进入实现计划,建议新增或修改:
internal/uiaselector/catalog.go
internal/uiaselector/catalog_test.go
internal/uiaselector/matcher.go
internal/uiaselector/matcher_test.go
internal/uiaselector/testdata/n12r-2026-07-09-uia-redacted.json
scripts/verify-n13-uia-selectors.ps1
暂不修改:
native/ISphereWinHelper/Program.cs
internal/tools/winhelper.go
cmd/isphere-mcp/main.go
除非新的实现计划明确批准新增只读定位工具,否则 Go MCP 仍只暴露现有四个只读工具。
12. N13 验收条件
N13 设计可接受条件:
- selector catalog 只依赖结构性 UIA 字段。
- 不依赖敏感可见文本。
- 首批 selector 都能追溯到 N12R ACCEPT dump 的路径。
- allowed_use 全部是
read_only_locate。 - 文档明确禁止点击、输入、打开会话、发送和文件操作。
- 后续实现计划必须 TDD,并先使用 fixture 测试 selector matcher。
13. 推荐下一步
下一步不是直接写代码,而是写一份 N13 implementation plan。
该计划应先实现纯离线 selector matcher,对 N12R UIA dump fixture 做只读匹配测试。
只有离线 selector matcher 通过后,才讨论是否新增 live locate_uia helper/MCP 只读工具。