merge: task/navfix-walk-out 合入 v2-on-ui
任务 navfix(1 个提交)经 task-worktree 回收: - fix(判据脚本): --walk 存证不进工作树;真机动作需显式持锁确认
This commit is contained in:
+22
-5
@@ -140,6 +140,7 @@ cmake --build simulator/build --config Debug # 0) 构建模拟器(须 0 警
|
||||
- **收级联列按 `l`、不按 `s`**:菜单态按 `s` 不收列,用 `ssssssss` 回根正是深页错位的来源之一;
|
||||
- 菜单树的 `#P` 注记可能写在 `#page=` **之前**(`网口设置 #P #page=net_cfg`),解析顺序错了就
|
||||
剥不掉,那一叶的页面 id 也永远认不出来。
|
||||
|
||||
### 7.3 用法与门禁档位
|
||||
|
||||
```powershell
|
||||
@@ -147,17 +148,30 @@ cmake --build simulator/build --config Debug # 0) 构建模拟器(须 0 警
|
||||
& '.venv\Scripts\python.exe' scripts/board_ui_nav.py --selftest-quick
|
||||
# 完整自检:再加全绑定页闭环导航(需模拟器可执行文件,约 30 s)
|
||||
& '.venv\Scripts\python.exe' scripts/board_ui_nav.py --selftest
|
||||
# 台架窗口:一条命令走完全部绑定页并逐页存帧(须持 bench 锁)
|
||||
& '.venv\Scripts\python.exe' scripts/board_ui_nav.py --walk
|
||||
# 只走一页并抓图;--trace 落步迹、--dump-fail 落「认错的那一屏」
|
||||
& '.venv\Scripts\python.exe' scripts/board_ui_nav.py --board --to yx --grab D:/tmp/yx
|
||||
# 台架窗口:一条命令走完全部绑定页并逐页存证
|
||||
# ⚠ 真机动作必须显式确认已持 bench 锁,否则脚本直接拒绝(不碰网络,退出码 3)
|
||||
& '.venv\Scripts\python.exe' scripts/board_ui_nav.py --walk --i-hold-bench-lock
|
||||
# 只走一页并抓图;--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
|
||||
```
|
||||
|
||||
- 提交钩子 `uinav-selftest` 跑的是**快检档**(`--selftest-quick`)。为什么不挂完整档:闭环
|
||||
那一段要模拟器可执行文件——它是构建产物,新工作树里没有,正是同一天 `mem-numbers` 缺
|
||||
`.map` 那课的形状。脚本对「缺可执行文件」报 FAIL 并给可执行提示,不「跳过当通过」;
|
||||
合入前 / 上板前请手工跑一次完整档(快检 ≠ 闭环,两者结论不同,别互相顶替)。
|
||||
- 板端后端只连 7003 取图注键,**不含串口、烧录、复位**;跑真机必须自己持 `bench` 锁。
|
||||
- 板端后端只连 7003 取图注键,**不含串口、烧录、复位**;`--board` / `--walk` 必须另加
|
||||
`--i-hold-bench-lock` 才会去连——没给就直接拒绝(退出码 3,不碰网络)。这条不是防御性
|
||||
设计,是**同一天踩出来的**:跑 `--walk` 想看一眼默认存证目录打印成什么,脚本就照着连上
|
||||
板子注入了按键,而那时台架属于验收窗的准备方。「必须持锁」写在文档里防不住「我只是跑
|
||||
一下」,所以把确认做成命令行参数:要动真机,就得在命令行里留下字面证据(脚本不代取锁,
|
||||
也不替人判断「应该没人在用」)。
|
||||
- **存证不进工作树**:`--walk` 的帧默认落 `ci-artifacts/uinav/walk/`(版本控制之外),
|
||||
`--outdir` 可改;给的路径若落在版本控制内(且不在 `ci-artifacts` 之下),脚本**直接拒绝
|
||||
执行**并退出 3。理由与提交门禁同一条:产物一旦写进工作树,`git status` 就不再是判据,
|
||||
而「记得删」只防得住记得的人。
|
||||
- 步迹只在 `--trace <路径>` 给出时落盘;认错那一屏只在 `--dump-fail <目录>` 给出时留存——
|
||||
两者都指到 `ci-artifacts/` 下,窗口结束把工作目录交回来时工作树仍是干净的。
|
||||
- 台架留档帧目录在 gitignore 内、不入库:缺就整段跳过,不算失败——但脚本把「没跑」与
|
||||
「跑过且通过」分开打印,不把前者写成后者。
|
||||
|
||||
@@ -196,6 +210,9 @@ cmake --build simulator/build --config Debug # 0) 构建模拟器(须 0 警
|
||||
| 2026-09-13 | 管线同步:`UI_界面制作流程.md` 移除 HTML 样机阶段(五阶段 → 四阶段 P0~P4),本文定位改为"P2/P3 门禁的可执行版本";§六 关系描述更新为 P0 规格 → P1 编码 → P2 本文回归 → P3 上机目检 → P4 归档;移除 `tools/ui_mock/` 引用 |
|
||||
| 2026-10-11 | **裁剪 LVGL 死代码(F-1/F-2/F-3)时的门禁记录**:先用**未裁剪**配置 `--update` 生成 11 页黄金参考,再切到裁剪配置重编重跑 → **逐字节全部一致**(菜单 8 状态像素一致),证明裁剪零视觉影响。池水位门禁随之 5440/5520 → **5368/5448**(−72 B;一次性残留仍 80 B,故非泄漏变化,见 §三 水位历史)。顺带揪出并修掉 `Lib/lv_conf.h` 与 `simulator/lv_conf.h` 的**长期漂移**(模拟器早已 I1-only、MCU 端未裁)→ 规则见 `UI_设计架构.md` §1.4 第 10 条,量化见 `../内存管理/RAM使用分析与优化方案.md` §2.6.4 |
|
||||
| 2026-10-15 | **回归改为自洽运行(修 `netcfg_save` 假失败)**:`check_menu_rows.py` / `check_content_pages.py` 一律以**空临时目录当工作目录**跑 `lvgl_sim`(模拟器按 CWD 读写 `sim_config.ini`,残留档会改变页面内容);`simulator/main.c` 的 `--cfgtest` 加外壳,**无论成败一律删除伪造的 4000 B 配置档**——旧行为连 PASS 路径也会留雷,之后每次 UI 回归的保存行都从 `OK` 变 `ERR`(引擎拒写超长文档,属正确行为)。脚本里"删 `sim_netcfg.bin` 残留"的旧兼容清理随之作废(旧档迁移 2026-10-10 已删),改为**只提示不删除**。修后 11 页 + 往返池水位 5,448 B 全过,**未刷任何黄金参考**;排查口径见 §五 |
|
||||
| 2026-10-25 | 第七节同日修订:`--walk` 的存证默认落 `ci-artifacts/uinav/walk/`(第一版写进
|
||||
`scripts/walk/`,污染工作树);路径落在版本控制内直接拒绝;`--board` / `--walk` 需显式
|
||||
`--i-hold-bench-lock`(实测过一次未持锁就注入按键,故把确认做成参数而非文字纪律)|
|
||||
| 2026-10-25 | 新增第七节「板端有状态导航判据」(`scripts/board_ui_nav.py`):真机侧闭环导航、
|
||||
盲走 9 帧仅 3 帧名副其实的实测表、认屏三判据、`uinav-selftest` 钩子档位、四条已知限度与
|
||||
过密码口径;三张证据 PNG 落 `boot_log_data/` |
|
||||
|
||||
+45
-4
@@ -22,6 +22,10 @@
|
||||
python scripts/board_ui_nav.py --walk # 台架窗口:走全部绑定页并存帧
|
||||
python scripts/board_ui_nav.py --board --to yx --grab /tmp/yx
|
||||
可选:--trace 路径(步迹落盘) --dump-fail 目录(把认错的那一屏存下来)
|
||||
--board / --walk 属真机动作:必须另加 --i-hold-bench-lock 显式确认已持 bench 锁,
|
||||
否则直接拒绝(退出码 3,不碰网络)——台架是独占资源,脚本不替人判断有没有在用。
|
||||
--walk 的存证目录默认在 ci-artifacts/uinav/walk(版本控制之外),--outdir 可改;
|
||||
落在版本控制内会被直接拒绝——台架证据不进工作树,工作树才能保持干净可比对。
|
||||
退出码: 0 = 成功;1 = 分类或导航失败;2 = 环境错误(exe 缺失 / 板子连不上)
|
||||
创建日期:2026-10-25(道E,Lead 大窗反馈后的判据脚本升级)
|
||||
"""
|
||||
@@ -69,6 +73,13 @@ COL_W = 66 # 一级子列宽(板端与模拟器同源)
|
||||
BLANK_INK = 900 # "几乎空白"屏的墨量上限(待机/密码页形态,实测 512)
|
||||
MAX_STEPS = 60 # 单次导航按键上限,到顶即失败而不是继续猜
|
||||
|
||||
# 直连真机的显式确认位:命令行里没有它,--board / --walk 一律不碰网络。
|
||||
# 为什么需要(2026-10-25 实测踩过):--walk 在没有任何拦截的情况下就连上板子注入了按键
|
||||
# ——跑的人只想“看一下默认存证目录打印成什么”,可台架是独占资源,别人可能正停在验收态。
|
||||
# 文档里那句“必须持 bench 锁”防不住“我只是跑一下”,所以把确认做成命令行参数:要连真机,
|
||||
# 就得在命令行里留下“我持锁”的字面证据。脚本不代取锁,也不接受“应该没人在用”的判断。
|
||||
BENCH_CONFIRM = "--i-hold-bench-lock"
|
||||
|
||||
|
||||
def load_harness():
|
||||
"""载入库内黄金回归脚本,复用它的字体解析与字形渲染(不复制第二套规则)。"""
|
||||
@@ -848,6 +859,17 @@ def selftest_closed_loop(clf, want):
|
||||
return len(want), bad, log
|
||||
|
||||
|
||||
def bench_gate(argv, what):
|
||||
"""真机动作前的闸:没给显式确认位就拒绝(退出码 3,且不碰网络)。"""
|
||||
if BENCH_CONFIRM in argv:
|
||||
return 0
|
||||
print("[拒绝] %s 会直连真机(注 KEY + 取 LCDMEM 帧),台架是独占资源。" % what)
|
||||
print(" 先取 bench 锁,再由人在同一命令行加 %s 明确确认已持锁:" % BENCH_CONFIRM)
|
||||
print(" .venv/Scripts/python.exe .dsh/skills/task-worktree/scripts/task_worktree.py lock acquire bench --task <ID>")
|
||||
print(" 本脚本不代取锁,也不接受“应该没人在用”——那种判断只有持锁的人能做。")
|
||||
return 3
|
||||
|
||||
|
||||
def _dump_trace(log):
|
||||
"""轨迹只在 --trace 给了路径时落盘(默认不往仓库里写东西)。"""
|
||||
if not TRACE:
|
||||
@@ -918,12 +940,29 @@ def main(argv):
|
||||
# 但黄金参考与闭环必须真跑过:任一为 0 说明这次"自检"其实什么都没检查
|
||||
return 1 if (badr or bad1 or bad2 or nr == 0 or m == 0) else 0
|
||||
if "--walk" in argv:
|
||||
rc = bench_gate(argv, "--walk")
|
||||
if rc:
|
||||
return rc
|
||||
# 台架窗口用:一条命令走完菜单树上**所有绑定页**,每页存一帧 + 一份轨迹。
|
||||
# 之所以要"一条命令",是因为 5 分钟窗口里没时间让人逐页手按;跑完只需把
|
||||
# uinav/walk/ 与 trace.json 交给 Lead,判据失败在哪一屏、当时认出的是什么,
|
||||
# 都在文件里,不用现场再猜。
|
||||
# 存证目录(默认 ci-artifacts/uinav/walk/)与 --trace 落下的步迹交给 Lead,
|
||||
# 判据失败在哪一屏、当时认出的是什么都在文件里,不用现场再猜。
|
||||
pid = None
|
||||
print("⚠ --walk 直连真机:调用方必须已持 bench 锁")
|
||||
# 存证**必须落在版本控制之外**。第一版写 HERE/walk = <仓库根>/scripts/walk/,等于
|
||||
# 把台架产物写进工作树:git status 立刻脏、done 的并集残留审计会把它当成任务遗留
|
||||
# 物,下一个窗口还盖掉上一个窗口的证据。默认落 ci-artifacts/uinav/walk/(已
|
||||
# gitignore,本仓台架产物一贯在此),--outdir 可改。
|
||||
# 反向拒绝:落在版本控制内且不在 ci-artifacts 之下就**直接不跑**——规矩一旦依赖
|
||||
# "跑完记得删",它就只防得住记得的人(这条道理同 bom-guard 的立项理由)。
|
||||
outdir = argv[argv.index("--outdir") + 1] if "--outdir" in argv else \
|
||||
os.path.join(REPO, "ci-artifacts", "uinav", "walk")
|
||||
rp = os.path.abspath(outdir)
|
||||
if rp.lower().startswith(os.path.abspath(REPO).lower() + os.sep) \
|
||||
and ("ci-artifacts" not in rp.lower()):
|
||||
print("[FAIL] --walk 的存证目录不能落在版本控制内:%s" % rp)
|
||||
print(" 默认 ci-artifacts/uinav/walk/;换目录请用 --outdir <忽略区里的路径>")
|
||||
return 3
|
||||
print("⚠ --walk 直连真机:调用方必须已持 bench 锁;存证目录 %s" % rp)
|
||||
dev = BoardDevice()
|
||||
ok, bad = 0, []
|
||||
try:
|
||||
@@ -932,7 +971,6 @@ def main(argv):
|
||||
nav = Navigator(dev, clf)
|
||||
try:
|
||||
fr, st = nav.go_page(pid)
|
||||
outdir = os.path.join(HERE, "walk")
|
||||
if not os.path.isdir(outdir):
|
||||
os.makedirs(outdir)
|
||||
with open(os.path.join(outdir, pid + ".bin"), "wb") as fp:
|
||||
@@ -948,6 +986,9 @@ def main(argv):
|
||||
print("走完 %d 页:成功 %d,失败 %d;轨迹 %s" % (ok + len(bad), ok, len(bad), TRACE))
|
||||
return 1 if bad else 0
|
||||
if "--board" in argv:
|
||||
rc = bench_gate(argv, "--board")
|
||||
if rc:
|
||||
return rc
|
||||
if "--to" not in argv:
|
||||
print("--board 需要 --to <页面 id>(见 --list)")
|
||||
return 3
|
||||
|
||||
Reference in New Issue
Block a user