docs(ui): 新增 board-ui-nav 唯一入口技能并在 AGENTS 布防(#69)
板端交互看图/注键/开页一律走 scripts/board_ui_nav.py,禁止另写 一次性注键脚本:#38 调试中因临时脚本盲注 d*9 走错页复犯(#69), 盲走事故当时已立"不猜步数"铁律但入口没布防。技能写明 --where/ --to/--goto/--selftest-quick 用法、STATUS/GOTO 语义与拒绝码、 恢复配方、台架锁边界与 GOTO 权限边界。 UI_自动化测试流程.md:§7.1 记 #69 复犯案例与像素路径存量误判基线 (记录查询 6 叶在 selftest 闭环里恒红是存量,勿当 #69 回归); §7.3 补 --where/--goto;§7.4 记 #69 收口(剪贴弹窗依赖已由 STATUS depth 顶掉,KNOWN_UNREACHABLE 销项待台架复核); 新增 §7.6 STATUS/GOTO 契约、判稳改造与门控说明。
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
---
|
||||
name: board-ui-nav
|
||||
description: 板端 UI 交互的唯一正确入口:先问固件"我在哪"(STATUS 身份查询),再决定按键;到页用闭环 --to 或 bench 直开 --goto。附 #69 实证的四类走错页根因与恢复配方。
|
||||
whenToUse: 需要上真机/台架进某页面看图(如故障录波、回放、定值)、在板端做 UI 取证、或从错误页面/待机态/未知屏恢复时。**写任何注键/取帧代码之前先读本技能**。
|
||||
---
|
||||
|
||||
# 板端 UI 导航(唯一入口 = scripts/board_ui_nav.py)
|
||||
|
||||
一句话纪律:**一切"进页面看图"都走 `scripts/board_ui_nav.py`,禁止另写一次性注键脚本。**
|
||||
2026-11-02 #38 调试里"总是进错误页面浪费大量时间"的直接原因,就是临时手搓
|
||||
`board_walk*.py` 盲按 `d*9`——而闭环导航器 2026-10-25 起就已存在(10-25 盲走事故
|
||||
9 个目标只有 3 个落对,`docs/UI设计/UI_自动化测试流程.md` §7.1)。
|
||||
|
||||
## 为什么不能自己搓(#69 复盘四类根因,全部有实证)
|
||||
|
||||
1. **协议旧版零身份反馈**:KEY 的 ACK 是空帧,"发了 5 个键"≠"到了第 5 层"。(已修:
|
||||
7003 新增 STATUS 命令,固件直读 `s_depth/s_path/s_sel` + 当前内容页 id,见下)
|
||||
2. **N−1 屏坑**:KEY ACK 与 LCDMEM 推流共用同一条 TCP,`sleep(0.30)` 就抓帧拿到的是
|
||||
上一屏(规则①:排空到帧流静默 ≥900 ms;现在 `key()` 代码已真正执行排空+双帧比对)。
|
||||
3. **物理陷阱**:待机态按 `e` 是**重开最近页**不是进菜单;级联列光标记忆上次行不归零;
|
||||
根列最后两行的子列弹框被 160×160 屏裁掉(selftest/runlog 因此"读不到选带")。
|
||||
4. **认屏误判**:菜单子列标签与页标题同字(记录查询子列里的 事故记录/操作记录…),
|
||||
像素分类器会把级联菜单判成 PAGE——**有 STATUS 时以 STATUS 为准**,trace 留痕不一致。
|
||||
|
||||
## 命令(python 一律 .venv;真机动作必须已持 bench 锁并加 --i-hold-bench-lock)
|
||||
|
||||
```powershell
|
||||
# 我在哪?(固件身份 + 像素双口径,不一致会留痕打印)
|
||||
.venv\Scripts\python.exe scripts\board_ui_nav.py --where --i-hold-bench-lock
|
||||
|
||||
# 到页:闭环步行(像素态设备/老固件也能用;每键重认屏,绝不猜步数)
|
||||
.venv\Scripts\python.exe scripts\board_ui_nav.py --board --to wave_play --grab C:\temp\wx --i-hold-bench-lock
|
||||
|
||||
# 到页:bench 固件直开页(一次往返直达,不注键;见下"直开页的边界")
|
||||
.venv\Scripts\python.exe scripts\board_ui_nav.py --goto wave_play --grab C:\temp\wx --i-hold-bench-lock
|
||||
|
||||
# 提交门禁快检(无台架、无模拟器产物也要绿)
|
||||
.venv\Scripts\python.exe scripts\board_ui_nav.py --selftest-quick
|
||||
```
|
||||
|
||||
`--list` 列出全部合法页 id 与菜单路径;`--trace 路径` 落步迹 jsonl(排错先看它)。
|
||||
退出码:0 成功 / 1 分类或导航失败 / 2 环境错误 / 3 拒动(未持锁确认位等)。
|
||||
|
||||
## 身份回读与直开页(#69 新增,两端共享 ui_net_sink.h 契约)
|
||||
|
||||
- **STATUS(命令 4)**:应答 `[ver][kind][depth][n][id_len][path][sel][page id]`;
|
||||
kind = MENU/PAGE/STANDBY(待机优先判)。老固件不应答 → 主机打印一次后自动退回纯像素。
|
||||
生产固件也支持 STATUS(只读、零画面副作用)。
|
||||
- **GOTO(命令 5)**:**编译期双闸** `DTU_BENCH`(临时 bench 固件)或模拟器宏
|
||||
`UI_REMO_ALLOW_GOTO`;生产固件恒拒 `status=4`。拒绝码:1 无此页 id / 2 执行类页 /
|
||||
3 开页失败 / 5 待机态(先按键唤醒再来)。直开按查看权限 `UI_PERM_VIEW` 进入,
|
||||
**不弹密码**——所以它只用于调试取证,不能当作"过密码"的旁路写路径。
|
||||
- 执行类页面 `clear`/`reset`(第二次 ENTER 即真执行)主机与固件**双侧**默认拒绝,
|
||||
`--allow-exec-pages` 才放行,放行 = 接受后果。
|
||||
|
||||
## 走错页 / 未知屏恢复配方(按序,不跳步)
|
||||
|
||||
1. `--where` 先看 STATUS:`PAGE` → 按 `s` 关页(导航器 `--to` 自动做);
|
||||
`STANDBY` → 按 `e` 唤醒(注意规则②:home 上 `e` 可能重开最近页);
|
||||
`MENU depth>0` → `l` 收列,别按 `s`(菜单态 `s` 不收列)。
|
||||
2. STATUS 无应答(老固件)才吃退避键序(默认 `esl`,`--backoff-keys sl` 可去 ENTER);
|
||||
ENTER 上限 1 次是硬闸(BACKOFF_MAX_E),报停机就 dump 帧人眼看,不许连按。
|
||||
3. 反复落错页且 trace 里出现"像素与 STATUS 不一致" → 分类器或固件有账要记,
|
||||
把留痕帧 `--dump-fail` 存下交 Lead,**不要**改判据迁就现状。
|
||||
|
||||
## 边界
|
||||
|
||||
- 本脚本不申请锁、不碰串口与烧录;锁的取还见 task-worktree 技能
|
||||
(`lock acquire bench --task <ID>`)。
|
||||
- 台架证据只进 `ci-artifacts/`(`--walk` 默认 `ci-artifacts/uinav/walk/`,与 BOARD_TRUTH
|
||||
读取目录已并一),不进工作树。
|
||||
- UI 源码改动的前后回归是 ui-verify 技能(5 门禁),本技能只管"人到板上去看"。
|
||||
@@ -185,6 +185,7 @@
|
||||
| 烧录与复位语义 | `docs/测试说明/测试工具/ST-LINK_CLI_复位使用说明.md` |
|
||||
| 串口助手 | **`serial-assistant` skill**(命令/判据/陷阱,用到自动加载)、`docs/测试说明/测试工具/串口助手使用指南.md`、`串口助手设计说明.md` |
|
||||
| UI 架构 / 模拟器 / UI 自动化回归 | **`lvgl-simulator` skill**(构建/自检/报错速查,用到自动加载)、`docs/UI设计/UI_设计架构.md`、`LVGL模拟器部署与使用说明.md`、`UI_自动化测试流程.md`;UI 改动回归走 **`ui-verify` skill** |
|
||||
| 板端进页看图 / 注键 / 认屏 / 直开页(真机 UI 交互) | **`board-ui-nav` skill**(唯一入口,**写任何注键脚本之前先读**)、`scripts/board_ui_nav.py`(STATUS 身份回读 + `--where`/`--goto`),`UI_自动化测试流程.md` §7 |
|
||||
| 待办与审计发现登记簿 | `docs/任务规划/README.md` |
|
||||
| 多任务并行开发(开空间 / 合并回收 / 台架与构建排队);**DSH worktree 插件的仓内树怎么接上**(`.dsh-worktrees/` 缺 `.venv`、`plugin adopt`、锁归属 `pw:<name>`) | **`task-worktree` skill**(`@task` 仅为文档别名非可执行命令,显式调用 `/task-worktree`,用到自动加载;插件桥 → 其 F 节)、`docs/环境与部署/并行任务工作树方案.md` §3.4 |
|
||||
| 换机 / 工具路径环境变量 | `docs/环境与部署/` |
|
||||
|
||||
@@ -130,6 +130,12 @@ cmake --build simulator/build --config Debug # 0) 构建模拟器(须 0 警
|
||||
——写路径判据(批 5)因此必须把「过密码」当显式状态处理,口径见 §7.5。
|
||||
- 结论:判据脚本只能信画面。脚本因此**每按一键重新认屏**再决定下一个键,且「到达」只由
|
||||
**页面身份**裁定;中途任何假设都写进轨迹,绝不当成结论。
|
||||
- **2026-11-02 #69 复犯与收口**:修 #38(回放页枚举恒空)的会话里又走了弯路——当时没有走
|
||||
本脚本,而是临时手搓 `board_walk*.py` 盲按,落错页后反复重来,浪费大量调试时间。四条根因
|
||||
(协议无身份回读 / `sleep(0.30)` 抓帧拿到 N−1 屏 / 待机·光标·被裁弹框三个物理陷阱 / 技能
|
||||
路由缺位)与成熟项目对照(accessibility 树优先于截图、auto-wait 断言、可复用工作流)见
|
||||
issue #69 评论区;前两条已在代码里收口(§7.6 的 STATUS 与排空双帧),后两条靠
|
||||
**`board-ui-nav` skill** 的「唯一入口」纪律兜住。
|
||||
|
||||
### 7.2 认屏的三条判据(精确字形匹配,复用同一份 `ui_font_cn_12`)
|
||||
|
||||
@@ -158,6 +164,10 @@ cmake --build simulator/build --config Debug # 0) 构建模拟器(须 0 警
|
||||
# 只走一页并抓图;--trace 落步迹、--dump-fail 落「认错的那一屏」,--outdir 改存证目录
|
||||
& '.venv\Scripts\python.exe' scripts/board_ui_nav.py --board --to yx --grab D:/tmp/yx \
|
||||
--i-hold-bench-lock --trace D:/tmp/uinav_trace.json
|
||||
# 我在哪(固件 STATUS 身份 + 像素双口径)/ bench 固件直开页(#69,见 §7.6)
|
||||
& '.venv\Scripts\python.exe' scripts/board_ui_nav.py --where --i-hold-bench-lock
|
||||
& '.venv\Scripts\python.exe' scripts/board_ui_nav.py --goto wave_play --grab D:/tmp/wx \
|
||||
--i-hold-bench-lock
|
||||
```
|
||||
|
||||
- 提交钩子 `uinav-selftest` 跑的是**快检档**(`--selftest-quick`)。为什么不挂完整档:闭环
|
||||
@@ -187,11 +197,20 @@ cmake --build simulator/build --config Debug # 0) 构建模拟器(须 0 警
|
||||
上 5 次枚举内没吃到,现场帧见
|
||||
[popup_clipped](../测试说明/测试数据/boot_log_data/20261025_uinav_popup_clipped.png);
|
||||
**真机上那层弹框究竟画在哪,留台架窗口取证后再定修法**——这是取证题,不是编码题。
|
||||
#69 之后:真机(新固件)侧该漏计已被 STATUS 的 `depth` 事实顶掉——"回根"直接认
|
||||
`depth==0`,不再依赖数得到列数;`KNOWN_UNREACHABLE` 两条按对称设计留待台架走到后销项。
|
||||
2. 同一标题的多个显示态(网口设置的 只读 / 编辑 / 保存)在分类里都是同一个页面 id
|
||||
`net_cfg`;要区分得看行内文本,写路径判据需要时再加。
|
||||
3. 认屏复用黄金参考的文案:改了页面文案而没同步 `simulator/tests/` 的文本断言表,本节脚本
|
||||
会一起红。那是**有意的耦合**(两处必须同时改),不是脚本脆弱。
|
||||
4. 快检档只证「认屏认得对」,不证「导航走得对」;后者只有完整档的闭环那一段会响。
|
||||
5. **纯像素路径对"子列标签 ≡ 页标题"的级联会误判**:记录查询子列里的 事故记录 / 操作记录 /
|
||||
报警记录 / 启动记录 / 遥控记录 / 运行报告 等标签与对应页标题同字,开子列那一屏会被判成
|
||||
PAGE——`--selftest` 闭环因此对 记录查询 下 6 叶(五本记录 + 录波回放)恒报「进入 记录查询
|
||||
后不是菜单态而是 PAGE」(2026-11-02 对 master 基线复跑确认为**存量**,非 #69 引入;
|
||||
`clear`/`reset` 两页的"失败"是执行类硬闸的刻意拒绝,另计)。真机新固件侧 STATUS 会把它
|
||||
纠成 MENU(trace 里留"像素与 STATUS 不一致"痕);模拟器侧无 STATUS,这 8 项维持红灯直至
|
||||
像素判据补上级联上下文——**别把它们当 #69 的回归**。
|
||||
|
||||
### 7.5 过密码的口径(与黄金回归同源,只有一套走法)
|
||||
|
||||
@@ -200,3 +219,29 @@ cmake --build simulator/build --config Debug # 0) 构建模拟器(须 0 警
|
||||
(两套走法迟早分叉,而分叉的那一边往往是真机)。导航器**默认只过查看密码**:判据需要写
|
||||
路径权限时必须显式传 `modify=True`,**不因「能进去」就自动升格成可写**——只读判据偷偷拿到
|
||||
修改权限,等于把判据的边界让给了实现。
|
||||
|
||||
### 7.6 身份回读 STATUS 与直开页 GOTO(#69,2026-11-02)
|
||||
|
||||
旧协议四个命令(KEEP/INIT/KEY/LCDMEM)里没有一个是"我是谁",闭环只能靠像素反推——本节
|
||||
判据的全部不确定性都源于此。#69 在 7003(RemoDispBus)上补了两条,两端共享同一份契约头
|
||||
`Drivers/BSP/UI/ui_net_sink.h`(**布局以该文件注释为唯一权威**,此处只记语义):
|
||||
|
||||
| 命令 | 语义 | 生产固件 | bench 固件 / 模拟器 |
|
||||
|---|---|---|---|
|
||||
| STATUS(4) | 直读固件导航态:kind(MENU/PAGE/STANDBY,待机先判)+ `depth/path/sel`(`ui_menu.c` 的 `s_*` 快照,经 `ui_menu_get_nav_state()`)+ 当前内容页 id(`ui_content_page_current_desc()`) | ✅ 支持(只读、零画面副作用) | ✅ |
|
||||
| GOTO(5) | 按页 id 直开页:查 `g_ui_page_map`,以查看权限 `UI_PERM_VIEW` 开页并回节点号 | ❌ 编译期闸外,恒回 status=4(不支持) | ✅ 受理(闸 = `DTU_BENCH` 或 `UI_REMO_ALLOW_GOTO`) |
|
||||
|
||||
- **主机侧优先问、像素兜底**:`Navigator` 每次认屏先 STATUS、后像素,两边打架以 STATUS 为准
|
||||
并在 trace 留痕;老固件不回 STATUS 时打印一次并永久退回纯像素路径。`--where` 现场打印双
|
||||
口径;`--goto <页 id>` 直开后仍走与 `--to` 相同的终点双验(STATUS + 像素),拒绝码 1 无此
|
||||
页 / 2 执行类页 / 3 开页失败 / 5 待机态。
|
||||
- **KEY 后稳帧已代码化**(规则①不再是纸面纪律):`key()` = 读掉 ACK → 排空到帧流静默
|
||||
≥900 ms(上限 5 s)→ 连取两帧比对,不等重试至多 8 次并在 trace 标 `stable=false`
|
||||
(时钟页秒针恒在走,属预期)。
|
||||
- **GOTO 的边界**:只用于调试取证——它按查看权限直达,**不弹密码**,因此不是"过密码"的旁路
|
||||
写路径;`clear`/`reset` 主机与固件双侧默认拒绝(直开即到达可执行态,没有第二段确认的
|
||||
余地)。MCU 侧要拿到 bench 能力须临时给 `MDK-ARM/STM32F407-Demo.uvprojx` 加 `DTU_BENCH`
|
||||
宏烧录,测完**必须还原宏并重烧产品构建**(uvprojx 抖动不入库,同构建节律)。
|
||||
- **留档帧目录已并一**:`WALK_DIR` 与 `--walk` 存证目录同指 `ci-artifacts/uinav/walk/`
|
||||
(#69 前指 `ci-artifacts/uiwalk/`,走的新帧 BOARD_TRUTH 段永远读不到,静默"跳过(无
|
||||
留档)")。
|
||||
|
||||
Reference in New Issue
Block a user