chore(全仓): @build/@test 旧文档别名清退为技能调用名

现状口径:/keil-build 与 /serial-boot-test 是 DSH 会话的技能调用名,
不是 shell 命令;「名 + 命令行参数」的命令形态改为可执行体
run_boot_test.py 的真实调用。

- AGENTS.md:别名说明重写为「技能调用名不是 shell 命令」,两条目改
  「编译(/keil-build)」「串口回归(/serial-boot-test)」
- keil-build / serial-boot-test 两 skill 调用名与示例同步;task-worktree
  方案文档去掉 @build/@test 惯例从句;@task 保留(不在点名范围)
- 123 文件现状陈述全改;台架捕获、变更记录/时间线、rename 映射输入
  等 41 行历史证据保留旧名
- gen_memory_svg.py 6 处措辞随改,3 张 SVG 产物同批重跑
- 顺手补并行方案同行漏网计数 51→52 钩子

验证:提交期快钩子对 123 文件实跑全 Passed;check_doc_links --all
rc=0(3038 处、无法判定 0);check_mermaid --all rc=0;YAML 解析 52
钩子不变;skill-size rc=0;py_compile 全过;字节卫生零漂移。
This commit is contained in:
2026-10-30 13:03:12 +08:00
parent dc964090ea
commit 4a4ad6bc5f
123 changed files with 455 additions and 455 deletions
+3 -3
View File
@@ -15,7 +15,7 @@
## 运行方式
```bash
# @test 一键闭环(推荐)
# /serial-boot-test 一键闭环(推荐)
& '.venv\Scripts\python.exe' .dsh/skills/serial-boot-test/scripts/run_boot_test.py
# 单独校验日志
@@ -41,7 +41,7 @@
⚠️ 每轮要真机烧录 + 采集,4 套件约数分钟起;破坏性套件还会改设备持久状态。
**仅回归窗口用,绝不挂 pre-commit**。
`--check-build` 则相反:**只改宏 + `@build`,不烧录不采集,无需任何硬件**,用于防止
`--check-build` 则相反:**只改宏 + `/keil-build`,不烧录不采集,无需任何硬件**,用于防止
"测试套件长期编不过而无人知"(2026-08~09 CH395F 套件实例)。改动 `test/board/` 下测试
代码后建议先跑它——实测 4 套件均 `BUILD_OK: 0 errors, 0 warnings`。
@@ -57,6 +57,6 @@
## 相关文档
- `docs/测试说明/流程与规范/测试开发标准流程.md` — 测试验证分层与门禁决策表
- `docs/测试说明/流程与规范/自动化测试流程.md` — `@test` 细节与失败模式
- `docs/测试说明/流程与规范/自动化测试流程.md` — `/serial-boot-test` 细节与失败模式
- 各模块测试指南:`docs/测试说明/板级测试/*_Test_Guide.md`
- `docs/测试说明/专项验证/链路延迟测试说明.md`
+1 -1
View File
@@ -36,7 +36,7 @@
1. 在 `test_config.h` 加开关(并入互斥 `#error` 检查)
2. 新建 `<模块>_test_task.c/h`
3. **注册进 Keil 工程**(`<FilePath>..\test\board\xxx.c</FilePath>`)
4. 跑回归:`@test`(`.dsh/skills/serial-boot-test/scripts/run_boot_test.py`)
4. 跑回归:`/serial-boot-test`(`.dsh/skills/serial-boot-test/scripts/run_boot_test.py`)
## 相关文档
+1 -1
View File
@@ -66,7 +66,7 @@ typedef struct {
/*
* 报告内核:套件运行结束时打印汇总行
* `=== <name>: N/M PASSED (failed=0) ===`
* 该汇总行是 `@test` 回归的默认判定标记(见 测试开发标准流程.md §3.2/§6.2.1)。
* 该汇总行是 `/serial-boot-test` 回归的默认判定标记(见 测试开发标准流程.md §3.2/§6.2.1)。
*/
#define TEST_REPORT_IMPL(stats, name) do { \
DBG_INFO("=== %s: %u/%u PASSED (failed=%u) ===", \
+3 -3
View File
@@ -8,7 +8,7 @@
| 脚本 | 作用 |
|---|---|
| `run_boot_test.py` | **`@test` 一键闭环**:开串口+清日志 → 烧录 → wait-idle → `verify_log` 校验(退出码 0=PASS) |
| `run_boot_test.py` | **`/serial-boot-test` 一键闭环**:开串口+清日志 → 烧录 → wait-idle → `verify_log` 校验(退出码 0=PASS) |
| `verify_log.py` | **日志标记校验**:Required / Forbidden 标记 → PASS / FAIL;可选 `--require-suite-summary` 校验套件汇总行(`=== <名称>: N/M PASSED (failed=0) ===` 且 `N>0`),抓"没跑到汇总行/断言数为 0"的盲区 |
| `e02_probe.py` | 头阻塞专项探针 |
@@ -98,7 +98,7 @@
## 运行方式
```bash
# @test 一键闭环(推荐,需真机)
# /serial-boot-test 一键闭环(推荐,需真机)
& '.venv\Scripts\python.exe' .dsh/skills/serial-boot-test/scripts/run_boot_test.py
# 测试套件构建的回归:要求套件跑到汇总行且断言数 > 0
@@ -149,7 +149,7 @@
## 相关文档
- `docs/测试说明/流程与规范/自动化测试流程.md` — `@test` 细节与失败模式
- `docs/测试说明/流程与规范/自动化测试流程.md` — `/serial-boot-test` 细节与失败模式
- `docs/测试说明/流程与规范/测试开发标准流程.md` — 测试分层与门禁
- `docs/测试说明/单元测试/看门狗单元测试说明.md` — 主机侧单测(用例 / 平台层 / 扩展方法)
- `docs/测试说明/单元测试/系统时钟单元测试说明.md` — 系统时钟换算单测(用例 / 桩 / Zeller 缺陷记录)
+1 -1
View File
@@ -812,7 +812,7 @@ static void tc_full_drop(void)
con_dwt_step = 0U;
writer_drain();
CHECK(tx_contains("[ERR] CONSOLE dropped 1 lines"),
"TC-CONLOG-060 the drain tail flushes [ERR] CONSOLE dropped 1 lines (loss is never silent, @test marks FAIL)");
"TC-CONLOG-060 the drain tail flushes [ERR] CONSOLE dropped 1 lines (loss is never silent, serial-boot-test marks FAIL)");
CHECK(dbg_console_dropped() == 0U, "TC-CONLOG-061 the counter is cleared once flushed (next round does not repeat the warning)");
CHECK(used_now() == 0U,
"TC-CONLOG-062 the warning goes out raw: not through the ring -> no con_append->drain recursion");
+1 -1
View File
@@ -9,7 +9,7 @@
* private/lftpd_log.h——桩目录赢不过它。所以正确做法是让真实 lftpd_log.h 照常参与
* 编译(它的分级语义也就一起被验证了),只把最底下的 DBG_* 换成计数。
* 顺带说明分级(真实头注释里写得很清楚):lftpd_log_peer 是 **info** 级不是 error,
* 因为"客户端关了个窗口"不该把 @test 的 Forbidden 标记 [ERR] 触发成 FAIL,也不该
* 因为"客户端关了个窗口"不该把 /serial-boot-test 的 Forbidden 标记 [ERR] 触发成 FAIL,也不该
* 让任何人连 21 端口就走就能无限制造固件级 ERROR;而 DOWNLOAD/UPLOAD FAILED 仍记
* error(那是数据完整性事件)。
*
+9 -9
View File
@@ -8,9 +8,9 @@
对每个套件:
1. 改 test_config.h 启用该套件(其它全注释)
2. @build(0 错 0 警,否则跳过该套件)
2. /keil-build(0 错 0 警,否则跳过该套件)
3. 烧录(stlink-flash skill:stlink_flash.py flash,Reset & Run)
4. @test 采集 + 判读(.dsh/skills/serial-boot-test 的 verify_log.py,含套件汇总行校验)
4. /serial-boot-test 采集 + 判读(.dsh/skills/serial-boot-test 的 verify_log.py,含套件汇总行校验)
结束后:
5. **无条件还原 test_config.h**(try/finally,含异常/KeyboardInterrupt 路径)
@@ -35,7 +35,7 @@
& '.venv\\Scripts\\python.exe' test/run_all_suites.py --keep-config # 不还原(调试用,慎)
--check-build:
只做"改宏 + @build",不烧录不采集,故**不需要 MCU / 串口 / ST-LINK**。
只做"改宏 + /keil-build",不烧录不采集,故**不需要 MCU / 串口 / ST-LINK**。
用途:① 改动测试固件或 test_config.h 后自检 4 套件仍可编译;
② 防止"某套件长期编不过而无人知"(2026-08~09 CH395F 套件实例)。
注意 RAM 溢出会自然暴露为链接错误 L6406E——这正是想要的。
@@ -72,7 +72,7 @@ FORBIDDEN_SUITE = "HardFault;MEMFAULT;BUSFAULT;USAGEFAULT;assert;bring-up FAIL"
# 但 MEM/BUS/USAGE 三种**平时完全靠 [ERR] 兜**。所以旧 GD5F 只写 `HardFault;assert` 其实
# 放过了后三种崩溃。覆盖集合一律显式列出四个 Fault 标签 + assert + 起网失败字样:
# 豁免的是**设计内的守卫 [ERR]**,崩溃照旧判失败。
# 产品 @test 判据(.serialtest/config.json 的 forbidden 含 [ERR])**不在这里动**——
# 产品 /serial-boot-test 判据(.serialtest/config.json 的 forbidden 含 [ERR])**不在这里动**——
# 豁免只活在"套件回归"这条路上,渗不回产品路径。
# GD5F:TC-GD5F-704 故意用非 DMA 可达缓冲触发 `[ERR][NAND] RX DMA buffer not
# DMA-reachable` 回落轮询(用例 PASS)→ 需豁免设计内 [ERR]。
@@ -151,7 +151,7 @@ def main(argv=None):
ap.add_argument("--flash-timeout", type=int, default=300)
ap.add_argument("--dry-run", action="store_true", help="只打印计划,不改配置不构建不烧录")
ap.add_argument("--check-build", action="store_true",
help="只编译不烧录:逐套件改宏 + @build,验证 4 套件可编译性;"
help="只编译不烧录:逐套件改宏 + /keil-build,验证 4 套件可编译性;"
"不需要 MCU / 串口 / ST-LINK,可用于 CI 或改动测试固件后自检")
ap.add_argument("--keep-config", action="store_true",
help="结束后不还原 test_config.h(调试用;⚠️ 会留下测试固件配置)")
@@ -199,7 +199,7 @@ def main(argv=None):
print("################ {} ################".format(suite))
_rewrite_config(macro)
# 1) 构建(@build = keil-build skill;脚本内超时先于 _run 超时触发,
# 1) 构建(keil-build skill 执行体;脚本内超时先于 _run 超时触发,
# 超时会返回 rc=1 + BUILD_FAIL 文案,而不是被 _run 杀掉)
rc, out = _run([py, str(KEIL_BUILD), "--timeout", str(args.build_timeout)],
timeout=args.build_timeout + 60)
@@ -224,7 +224,7 @@ def main(argv=None):
print("[FLASH] rc={} elapsed={:.1f}s".format(frc, time.monotonic() - t0))
if frc != 0:
print("\n".join(fout.strip().splitlines()[-6:]))
# 烧录失败不直接判死:板子可能已复位,交由采集+判读决定(与 @test 一致)
# 烧录失败不直接判死:板子可能已复位,交由采集+判读决定(与 /serial-boot-test 一致)
print("[WARN] 烧录 rc={}(继续:板子可能已复位)".format(frc))
# 3) 采集 + 判读(含套件汇总行校验)
@@ -265,7 +265,7 @@ def main(argv=None):
# 5) 复位构建产物为产品态(2026-10-02):最后一轮构建留下的是**测试套件**的
# .map/.axf,会污染 mem-numbers 体积门禁(下次提交即 FAIL)。仅还原源码不够
# ——必须再编一次产品固件,使 .map 与 test_config.h 一起回到产品态。
# --check-build 也要做:它每轮都 @build,同样会留下测试态 .map。
# --check-build 也要做:它每轮都 /keil-build,同样会留下测试态 .map。
if restored and not args.keep_config:
print("")
print("[..] 复位构建产物为产品态(重建一次产品固件,避免 .map 停留在测试套件态)...")
@@ -276,7 +276,7 @@ def main(argv=None):
print("[OK] 产品固件已重建(.map/.axf 复位)")
else:
# 不判死:配置已还原,仅提示手工重建
print("[WARN] 产品固件重建失败(rc={}),请手工跑 @build 复位 .map".format(rc))
print("[WARN] 产品固件重建失败(rc={}),请手工跑 /keil-build 复位 .map".format(rc))
if tail:
print(tail)