AutoUI MCP 测试夹具协议
状态与范围
本设计服务 PLAN-623,定义 AutoUI MCP 的测试专用运行时状态夹具。 它只服务 VM 轨的确定性测试,不是应用功能,也不改变 Vue HTTP 业务链路或 Rust 组件事件模型。
夹具的唯一启用条件是进程环境中的 `AUTOUI_TEST_FIXTURES=1)。默认关闭时, 工具请求在 MCP 线程被拒绝并且不会进入动作队列。
设计目标
- 测试可以注入当前 AutoUI 组件已经声明的状态字段,包括 VM 数组字段。
- 注入结果在 iced/VM 更新线程完成后才返回
applied。 - 可选的
trigger在状态写入成功后、同一个更新周期内进入普通 VM handler 入口,避免用固定 sleep 猜测时序。 - 同一请求在 VM merged 与 no-merge 启动方式下使用相同语义。
- Rust MCP 明确返回不支持,普通 action/keyboard/state 工具零回归。
- 框架不包含任何 Tetris 字段名;业务夹具由调用方按
autoui_state提供。
请求契约
{
"schema_version": 1,
"state": {
"board": [0, 0, 0],
"piece": 0,
"rotation": 1,
"px": 7,
"py": 16,
"pending_lock": true,
"phase": "playing"
},
"trigger": {
"widget": "TetrisStore",
"event": "Tick",
"input": null
}
}schema_version必须为整数 1。state必须为非空 JSON object。- 字段名必须存在于当前 MCP session 的 state snapshot。
- JSON 值递归支持 null、bool、整数、浮点、字符串、数组和 object。 数组写回使用字段现有的 VM 数组载体,不把 heap array id 当普通整数写入。
- 输入值的 JSON 类型必须与当前字段兼容;整数不能静默截断超出 i32 的数值。
trigger可省略。存在时只含 widget、event、可选 input 字符串;它只能 调用已有 handler,不提供代码或表达式执行能力。- 请求体大小、字段数量、递归深度和数组元素数量受固定上限约束。
响应:
{
"status": "applied",
"request_id": 17,
"changed": ["board", "piece", "rotation", "px", "py", "pending_lock", "phase"],
"trigger": "TetrisStore.Tick"
}失败响应使用 MCP 的 isError=true,文本中包含稳定错误类别: fixtures_disabled、backend_unsupported、invalid_schema、 unknown_field、type_mismatch、write_failed、trigger_failed、 ack_timeout。
线程与消息模型
AutoUI MCP 线程分配单调递增 request id,构造:
ActionTarget::Fixture { request_id }ActionMessage.value = Some(serialized_fixture_payload)
VM 的 poll_mcp_actions 将 Fixture 转成保留事件 __mcp_fixture|<request_id>|<payload>。该事件在 update_inner 的普通 on_with_input_for 之前消费。
消费顺序:
- 解析并校验整个 payload。
- 读取当前字段形态,确认所有字段可写;校验失败不触发 handler。
- 按字段写入:数组字段走
read_state_as_vec/write_state_vec,其他字段走write_state。 - 设置 per-App
view_dirty。 - 如存在 trigger,使用现有
on_with_input_for或 timer 入口派发。 - 通过该 App 的
mcp_shared写入 request-id ack。 - MCP 工具在有界期限内轮询 ack;收到 ack 才返回 applied/error。
ack 表只保留未完成请求及最近有限数量的结果,消费后删除;超时请求不会 阻塞后续 MCP 操作。renderer 不直接持有 HTTP/MCP 锁等待工具线程,避免死锁。
Rust 的 devtools_subscription 对 Fixture 目标丢弃并记录不支持;MCP 工具 在提交前依据 SharedState backend capability 返回 backend_unsupported, 因此正常情况下不会进入 Rust DevTools 队列。
安全边界
AUTOUI_TEST_FIXTURES=1缺失时不发送任何 ActionMessage。- capability 由 renderer 启动时写入 SharedState(VM 或 Rust),不依赖调用方 自行声明的环境变量。
- 夹具只写当前运行时状态,不触发 storage/persistence API。
- HTTP server 仍使用现有本机监听配置;本设计不开放远程 fixture 端口。
- fixture 工具不出现在应用 VTree、action 列表或任何可见 UI 中。
VM 后端兼容性
merged 和 no-merge 共用同一个 VM renderer 消费臂。no-merge 的业务 handler 仍可通过既有 HTTP backend 执行;fixture 写入本地 VM state 后再触发 handler, 因此测试可以分别验证状态注入与后端调用,不把 HTTP 结果伪装成 fixture ack。
Tetris 移交
Plan 005 在本协议落地后提供一份 case 数据,至少覆盖 opening/lock、7×4 旋转、1–4 行消除。每个 case:
- 用
autoui_fixture写入 board、piece、rotation、px、py、pending_lock、 phase; - 等待 applied ack;
- 用 trigger Tick 或现有键盘/动作入口推进;
- 用
autoui_state读取 board、score、lines、phase、feedback; - 与 Rust rules golden 的同 case 结果逐项比较。
这一步留在 auto-os Plan 005,不把业务字段写入框架协议。