diff --git a/docs/审查记录/测试与架构改进建议.md b/docs/审查记录/测试与架构改进建议.md index f5d24d38..5fd13a5b 100644 --- a/docs/审查记录/测试与架构改进建议.md +++ b/docs/审查记录/测试与架构改进建议.md @@ -1,4 +1,10 @@ -# 测试体系与整体架构改进建议(2026-10-02) +# 测试体系与整体架构改进建议(2026-10-02,2026-10-04 状态更新) + +> **状态速览(2026-10-04)**:14 条建议(S1~S14)**已落地 12 条**(S1-a / S1-b、S2~S11、S13、S14); +> **待做 2 条**:**S12**(模块级轻量断言宏,第 4 波按需试点)、**S1-c**(可选,`sys_log` / `time_sync` 单测)。 +> 落地带来的体系变化:**L0.5 由 1 个模块 → 3 个**(看门狗 / `sys_clock` / `cfg_file`)、 +> **L0 钩子 15 → 18**、**板端套件 4 → 5**(新增 SD2506 RTC)、CI 已补产物存档与汇总行。 +> 各节内已用 **✅ / ◐ / ⬜** 就地标注;本文仍是**建议性文档**,未改动任何生产代码。 > **用途**:对现有**测试体系**与**整体架构**做一次独立复审,回答两个问题—— > ① 测试是否足够?② 架构还有什么可改进的地方? @@ -19,17 +25,18 @@ | 维度 | 评价 | 一句话 | |---|---|---| | 分层模型(L0~L3) | ⭐⭐⭐⭐⭐ | 四层划分清晰、门禁决策表明确,**优于绝大多数同规模嵌入式项目** | -| 板端套件(L1) | ⭐⭐⭐⭐☆ | 4 套件 + 222 个断言点,覆盖驱动功能面完整 | -| 静态门禁(L0) | ⭐⭐⭐⭐⭐ | 15 个钩子、含一致性/规范/乱码/元数据,防线密不透风 | -| **主机侧纯逻辑单测(L0.5)** | ⭐⭐☆☆☆ | **仅 1 个模块(看门狗)**,而适格对象至少有 6~8 个 | +| 板端套件(L1) | ⭐⭐⭐⭐⭐ | **5 套件** + 222 个断言点,覆盖驱动功能面完整(SD2506 RTC 已补套件汇总行) | +| 静态门禁(L0) | ⭐⭐⭐⭐⭐ | **18 个钩子**、含一致性/规范/乱码/元数据 + 3 个主机单测钩子,防线密不透风 | +| **主机侧纯逻辑单测(L0.5)** | ⭐⭐⭐⭐☆ | **已覆盖 3 个模块**(看门狗 / `sys_clock` / `cfg_file`);适格对象还剩 `sys_log` / `time_sync` | | UI 回归(L3 门禁) | ⭐⭐⭐⭐☆ | 文本层 + 像素层 + 池水位三层断言,思路先进 | -| CI | ⭐⭐⭐☆☆ | 只跑 L0 + L0.5;**无产物存档、无结果趋势、无覆盖率** | +| CI | ⭐⭐⭐⭐☆ | 跑 L0 + L0.5;**已补产物存档 + 汇总行**;仍**无结果趋势、无覆盖率** | | 可观测性(运行时) | ⭐⭐⭐⭐☆ | 栈水位探针 + 链路时延探针 + syslog,台架能力强 | -| **验证债** | ⭐⭐☆☆☆ | 多项"已改未验",L0.5 稀缺导致**回归只能靠真机** | +| **验证债** | ⭐⭐⭐⭐☆ | 台架窗口已清掉 S7 / S9 / S11 三项;剩余验证债仅 N-3(L5 基线,待 PC peer) | -**核心判断**:项目的测试**广度**(驱动功能面)和**静态深度**(门禁)都很强, -真正的短板是 **L0.5(主机侧纯逻辑单测)的覆盖率**——这是**性价比最高、见效最快**的改进方向。 -它不需要硬件、秒级完成、能上 CI、且已有一整套现成 harness(`unit_test_harness.py` + 看门狗范式)。 +**核心判断(2026-10-04 更新)**:项目的测试**广度**(驱动功能面)和**静态深度**(门禁)都很强, +L0.5 这一短板**已被 S1 补齐大半**——`sys_clock` / `cfg_file` 两个高价值模块落地后, +**首跑各抓出一处生产缺陷**(Zeller 星期错误、外科手术保存死码 P0),验证了"L0.5 是性价比最高 +的改进方向"这一判断。剩余适格对象(`sys_log` / `time_sync`)价值递减,可按需补(S1-c)。 ### 0.2 架构评价:**分层与解耦做得好,但存在"三个不对称"** @@ -42,20 +49,21 @@ ### 0.3 建议优先级(与上游阶段 A/B/C/D 对齐) ``` -【S 级:本周可做,零风险,收益大】 ← 本文新增 - S1 扩充 L0.5 单测(crc/ringbuf 判定、sys_clock 日期算术、cfg_file 解析器) - S2 清理孤儿源文件(crc.c / ringbuf.c)——降低认知负担 - S3 CI 补产物存档 + 单测结果汇总 +【S 级:本周可做,零风险,收益大】 ← 本文新增 【2026-10-04 状态】 + S1 扩充 L0.5 单测(sys_clock 日期算术、cfg_file 解析器) ✅ S1-a / S1-b 已落地(S1-c 可选) + S2 建立 L0.5 适格模块台账 ✅ 已落地 + S3 CI 补产物存档 + 单测结果汇总 ✅ 已落地 + S8 清理孤儿源文件(crc.c / ringbuf.c) ✅ 已落地(文件已删) 【A 级:上游已列,本文给增量角度】 - A1 P0-1 真机验证(上游 A1) A2 P1-8 网络重建恢复(上游 A2) - A3 E-34 CH395F 超时(上游 A3) A4 E-04 remo_send 返回值(上游 A4) + A1 P0-1 真机验证(上游 A1) A2 P1-8 网络重建恢复(上游 A2) ◐ 正常路径已实测零回归;负向场景见 N-16 + A3 E-34 CH395F 超时(上游 A3) A4 E-04 remo_send 返回值(上游 A4) ✅ 2026-10-03 -【B 级:核心功能补齐(上游 B,需产品定义)】 +【B 级:核心功能补齐(上游 B,需产品定义)】 ← 当前最高优先 B1 ADC 链路 B2 RS485 链路 B3 E-59 门禁固化 【C 级:结构债(上游 C)】 - C1 pending 二期 C2 GD5F 错误通道 C3 日志管线 C4 defaultTask 栈 + C1 pending 二期 C2 GD5F 错误通道 ✅ 2026-10-03 C3 日志管线 C4 defaultTask 栈(S-1,需尽快) ``` --- @@ -64,7 +72,7 @@ ### 1.1 测试资产盘点(2026-10-02 实测) -**板端套件(L1)——4 套件,222 个 `TEST_CHECK` 断言点**: +**板端套件(L1)——5 套件,222 个 `TEST_CHECK` 断言点**(2026-10-04 复核): | 套件 | 文件 | 断言点 | Test_Guide 用例数 | 覆盖对象 | |---|---|---|---|---| @@ -79,23 +87,27 @@ > 这是正常的,但**反向不成立**:文档存在而代码未实现的用例无法从断言点数量看出, > 需靠 §1.3 的"覆盖矩阵核查"专项检查(本文建议 S4,见 §3.4)。 -**主机侧(L0.5)——仅 1 个模块**: +**主机侧(L0.5)——已覆盖 3 个模块**(2026-10-04 复核): | 模块 | 位置 | 用例数 | 被测对象 | |---|---|---|---| | 看门狗判定状态机 | `test/host/watchdog/` | 39 | `App/util/task_watchdog.c` 位图/掩码/节流/回绕 | -| **其余模块** | — | **0** | — | +| 系统时钟换算 | `test/host/sys_clock/` | 20(100 断言点) | `App/util/sys_clock.c` 闰年/月末/回绕/星期 | +| 配置引擎解析 | `test/host/cfg_file/` | 20(139 断言点) | `App/cfg/cfg_file.c` INI 解析/转义/长度校验/迁移 | +| **其余适格模块** | — | **0** | `sys_log` / `time_sync`(可选,S1-c) | -**静态门禁(L0)——15 个钩子**: +**静态门禁(L0)——18 个钩子**(2026-10-04 实测): `trailing-whitespace` / `end-of-file-fixer` / `check-added-large-files` / `check-merge-conflict` / -`check-yaml` / `gitlint` / `cppcheck` / `no-mojibake` / `coding-standard` / `doc-links` / -`task-table` / `mem-numbers` / `cubemx-survival` / `watchdog-unit-test` / `test-suite-switch` +`check-yaml` / `gitlint` / `cppcheck` / **`test-cppcheck`** / `no-mojibake` / `coding-standard` / +`doc-links` / `task-table` / `mem-numbers` / `cubemx-survival` / `watchdog-unit-test` / +**`sys-clock-unit-test`** / **`cfg-file-unit-test`** / `test-suite-switch` **UI 回归(L3 门禁)**:`check_menu_rows.py`(菜单 8 状态像素 + 池基线)+ `check_content_pages.py`(11 内容页 + 文本层 50 条字形模板)+ `check_remo_sink.py`(远显推流)。 -**CI(Gitea Actions)**:2 个 job —— `l0-gates`(pre-commit 全量)、`l05-host-unit-tests`(遍历 `run_unit_test.py`)。 +**CI(Gitea Actions)**:2 个 job —— `l0-gates`(pre-commit 全量)、`l05-host-unit-tests`(遍历 `run_unit_test.py`); +两 job 均已**归档日志产物 + 打印汇总行**(S3,2026-10-02)。**注意 CI 不跑 Keil、不守体积门禁**(S14)。 ### 1.2 覆盖率缺口矩阵(按"适格性"排序) @@ -103,23 +115,28 @@ | 候选模块 | 规模 | 边界密度 | 现测试手段 | L0.5 价值 | 备注 | |---|---|---|---|---|---| -| **`App/util/sys_clock.c`** | 479 行 | **极高** | 仅 RTC 套件(真机) | ⭐⭐⭐⭐⭐ | 闰年/日期换算/星期/49.7 天回绕——**纯算术,零硬件** | -| **`App/cfg/cfg_file.c`** | 1250 行 | **高** | 仅 STORAGE 套件(真机) | ⭐⭐⭐⭐⭐ | INI 解析/转义/长度校验/迁移——**已有 `cfg_store_alloc` 平台后端抽象,天然适格** | -| **`App/util/crc.c`** | 120 行 | 中 | **无**(孤儿文件) | ⭐⭐⭐ | 查表正确性可用标准向量验证;但**当前无调用者**(见 S2) | +| ~~**`App/util/sys_clock.c`**~~ | 479 行 | **极高** | ✅ **L0.5 已覆盖**(`test/host/sys_clock/`,20 用例) | ⭐⭐⭐⭐⭐ | 闰年/日期换算/星期/49.7 天回绕——**S1-a 已落地,首测抓出 Zeller 星期缺陷** | +| ~~**`App/cfg/cfg_file.c`**~~ | 1250 行 | **高** | ✅ **L0.5 已覆盖**(`test/host/cfg_file/`,20 用例) | ⭐⭐⭐⭐⭐ | INI 解析/转义/长度校验/迁移——**S1-b 已落地,首测抓出外科手术保存死码 P0** | +| ~~**`App/util/crc.c`**~~ | 120 行 | 中 | ✅ **已删除**(S8,2026-10-02) | ⭐⭐⭐ | 查表正确性可用标准向量验证;但**零调用者**——已按 S8 删除 | | `Drivers/BSP/RS485/rs485.c` | 181 行 | 高 | **无**(任务为空桩) | ⭐⭐⭐⭐ | 帧解析状态机适格;但**功能未实现**(上游 B2) | | `App/sync/time_sync.c` | 217 行 | 中 | 仅手工 `time_sync_server.py` | ⭐⭐⭐ | 协议编解码适格,与网络耦合需判 | | `App/log/sys_log_mcu.c` | 359 行 | 中 | 仅 `@test` 标记 | ⭐⭐⭐ | 定长 64B 记录编解码适格;落盘部分需桩 | | `Drivers/BSP/TPAFE5160/tpafe5160.c` | 356 行 | 中 | **无**(任务为空桩) | ⭐⭐ | 寄存器序列为主,纯逻辑面小 | -| `App/util/ringbuf.c` | 154 行 | 中 | **无**(孤儿文件) | ⭐⭐ | 若 S2 决定保留则须测;否则删除 | +| ~~`App/util/ringbuf.c`~~ | 154 行 | 中 | ✅ **已删除**(S8,2026-10-02) | ⭐⭐ | 零调用者——已按 S8 删除 | -**结论**:**至少 2 个高价值模块(`sys_clock`、`cfg_file`)具备立即可做的 L0.5 条件**, -合计约 1730 行核心逻辑,目前**完全依赖真机验证**。这是测试体系最大的效率损失点。 +**结论(2026-10-04 更新)**:**原列的两个最高价值模块(`sys_clock`、`cfg_file`)均已落地 L0.5** +(S1-a / S1-b),合计约 1730 行核心逻辑已脱离"只能靠真机"的状态;且两者**首跑各抓出一处 +生产缺陷**,是本轮测试体系建设中收益最直接的两笔。剩余适格对象(`sys_log` / `time_sync`) +价值递减,列入 S1-c 可选。 ### 1.3 测试体系的结构性问题 -#### 问题 T-1:L0.5 覆盖率过低,回归反馈闭环过长 🔴 +#### 问题 T-1:L0.5 覆盖率过低,回归反馈闭环过长 🔴 → ✅ **已改善(2026-10-02 落地 S1-a / S1-b)** -**现状**:全项目仅看门狗 1 个模块有主机侧单测。`sys_clock.c`(479 行日期算术)、 +> **2026-10-04 更新**:L0.5 已由 1 个模块扩至 **3 个**(看门狗 / `sys_clock` / `cfg_file`), +> 本节所述"这两类模块只能靠真机回归"的缺口**已消除**;下述代价量化保留作立项依据与决策记录。 + +**现状(2026-10-02 初判)**:全项目仅看门狗 1 个模块有主机侧单测。`sys_clock.c`(479 行日期算术)、 `cfg_file.c`(1250 行解析器)这类**边界密集、纯逻辑、零硬件**的模块, 改动后**只能靠真机 `@test` 才能发现问题**。 @@ -137,7 +154,7 @@ Unix 秒 → 年月日换算、49.7 天 tick 回绕惰性再基准化——这 **建议**:见 §3.1(S1)。 -#### 问题 T-2:CI 无产物存档、无趋势、无覆盖率 🟡 +#### 问题 T-2:CI 无产物存档、无趋势、无覆盖率 🟡 → ✅ **已改善(2026-10-02 落地 S3)** **现状**:CI 只做"通过/失败"判定,**不保存任何产物**: - `pre-commit run --all-files` 的完整输出不入档(失败后只能靠 Gitea 日志页滚动查找); @@ -149,7 +166,7 @@ Unix 秒 → 年月日换算、49.7 天 tick 回绕惰性再基准化——这 **建议**:见 §3.3(S3)。 -#### 问题 T-3:`test/` 代码完全豁免静态检查 🟡 +#### 问题 T-3:`test/` 代码完全豁免静态检查 🟡 → ✅ **已落地(2026-10-03,S5)** **现状**(`测试开发标准流程.md` §3.3 明示):`test/` 在 pre-commit 范围之外, "上表约定属**自律**要求"。而 `test/board/` 下是 **6300+ 行 C 代码**(实测 `.c`+`.h` 合计 6,313 行),且**编入固件**。 @@ -158,10 +175,10 @@ Unix 秒 → 年月日换算、49.7 天 tick 回绕惰性再基准化——这 (`测试开发标准流程.md` 变更记录 2026-09-15),说明测试代码质量并非自动达标。 豁免 cppcheck 意味着测试代码的**未初始化变量/越界/空指针**不会被静态发现。 -**建议**:见 §3.5(S4)。注意**不宜**直接纳入现有钩子(会引入大量存量告警), +**建议**:见 §3.5(S5)。注意**不宜**直接纳入现有钩子(会引入大量存量告警), 宜用**独立、宽松**的钩子(只报 error 级、不含 style)。 -#### 问题 T-4:测试固件构建未纳入闭环(= 上游 P1-10,本文给增量)🟡 +#### 问题 T-4:测试固件构建未纳入闭环(= 上游 P1-10,本文给增量)🟡 → ✅ **已落地(2026-10-02,S6)** **上游已登记** P1-10"测试固件构建闭环"。**本文增量**: `测试开发标准流程.md` 变更记录 2026-09-15 记载 **CH395F 套件 7 个配置 @@ -171,9 +188,9 @@ Unix 秒 → 年月日换算、49.7 天 tick 回绕惰性再基准化——这 **这说明**:测试套件的**构建可编译性没有独立门禁**——产品构建 `@build` 天天跑, 但**测试构建可能长期处于"编不过"状态而无人知**,直到某次要用才发现(正是 09-15 的情况)。 -**建议**:见 §3.4(S5)——把"测试套件构建"做成**可选的编译验证**,而非依赖人记得。 +**建议**:见 §3.6(S6)——把"测试套件构建"做成**可选的编译验证**,而非依赖人记得。 -#### 问题 T-5:真机回归的"判定强度"仍可提升 🟡 +#### 问题 T-5:真机回归的"判定强度"仍可提升 🟡 → ✅ **已落地(2026-10-02,S7)** **现状**:`verify_log.py` 已支持 `--require-suite-summary`(T-2,要求汇总行 + `N>0` + `failed=0`), 这是很好的设计。但**产品构建回归**(非套件)仍是纯 Required 子串匹配 + @@ -183,7 +200,7 @@ Forbidden `FAIL;ERROR;HardFault;assert`。 项目已有 `sys_log` 引擎写 `/log/selftest.log`(`运行与自检记录设计说明.md`), 但 `@test` 闭环**没有读取它**——自检失败(例如"时钟芯片异常")只在设备日志里静静躺着。 -**建议**:见 §3.6(S6)——让 `@test` 闭环消费 `selftest.log` 的判定结果。 +**建议**:见 §3.7(S7)——让 `@test` 闭环消费 `selftest.log` 的判定结果。 --- @@ -203,7 +220,7 @@ Forbidden `FAIL;ERROR;HardFault;assert`。 | 可观测性 | 栈水位探针、链路时延探针(DWT)、syslog 双记录、自检上报 | | CubeMX 生存保障 | `check_cubemx_survival.py`(18 项清单 + 哈希基线) | -### 2.2 改进点 A-1:孤儿源文件(认知负担 + 误导)🟡 +### 2.2 改进点 A-1:孤儿源文件(认知负担 + 误导)🟡 → ✅ **已闭环(2026-10-02,S8)** **证据**(2026-10-02 实测): @@ -223,9 +240,15 @@ App/util/ringbuf.c 154 行 → 零 `#include "ringbuf.h"`,不在 Keil 工 3. 上游 E-15 已提"ringbuf 定去留——**已确认零调用者,倾向删除**",本文**用实测佐证该结论** 并**追加 `crc.c`**。 -**建议**:见 §4.1(S7)。 +**建议**:见 §4.1(S8)。 -### 2.3 改进点 A-2:错误码通道的"下层不对称"🔴 +> ✅ **2026-10-02 落地**:`App/util/crc.{c,h}`、`App/util/ringbuf.{c,h}` 已删除, +> `App/util/README.md` 引用同步清理,引用关系图重跑;上游 E-15 随之销项。上述"证据"保留作背景。 + +### 2.3 改进点 A-2:错误码通道的"下层不对称"🔴 → ✅ **已闭环(2026-10-03,S9)** + +> **2026-10-04 更新**:GD5F 错误通道族(E-10 / E-42 / E-53 / E-54 / E-56 / E-57)已按下方 +> **四要素骨架**完成统一,GD5F 套件回归 **16/16 PASS**(见 §4.2)。本节保留作架构分析。 **上游已登记**(`错误码传播审计.md` 第二档 #1:E-10/E-42/E-53/E-54/E-56/E-57 GD5F 错误通道族)。 **本文增量**:给出**架构层面的根本原因**与**统一方案骨架**。 @@ -248,7 +271,7 @@ App/util/ringbuf.c 154 行 → 零 `#include "ringbuf.h"`,不在 Keil 工 **关键纪律**(呼应 `AGENTS.md` 已有铁律):**自愈逻辑严禁把"名字/参数类错误码" 归入"卷损坏触发集"**——`.fschk` 无限重格式化事故即此类(2026-09-20)。 -### 2.4 改进点 A-3:启动段无看门狗保护的窗口 🟡 +### 2.4 改进点 A-3:启动段无看门狗保护的窗口 🟡 → ✅ **已闭环(2026-10-02,S10)** **上游已登记**(N-03b,视为"显式代价")。**本文增量**:量化并给出**风险接受条件**。 @@ -266,7 +289,10 @@ App/util/ringbuf.c 154 行 → 零 `#include "ringbuf.h"`,不在 Keil 工 ② **为长操作加显式看门狗喂狗点**(若将来启用启动期 IWDG); ③ 文档明确"启动段死机的判读方法"。 -> 检查现状:`app_main.c` 是否每步有日志——若有则可直接销项。见 §4.4(S8)。 +> 检查现状:`app_main.c` 是否每步有日志——若有则可直接销项。见 §4.3(S10)。 +> +> ✅ **2026-10-02 落地**:`app_main_init` 已补 3 条、`sd2506_init` 已补 6 条启动日志 +> (Flash +904 B);`项目启动顺序管理.md` §6.8 新增"启动段死机判读法"——**每步均有可区分日志行**。 ### 2.5 改进点 A-4:ADC/RS485 采集链路缺失(核心功能空洞)🔴 @@ -284,20 +310,24 @@ App/util/ringbuf.c 154 行 → 零 `#include "ringbuf.h"`,不在 Keil 工 **且撕裂在单测里测不出来**(时序相关),必须在设计上消除; 3. **DE 收尾必须有超时路径覆盖**(RS485 半双工的特有陷阱)。 -### 2.6 改进点 A-5:内存预算的"预算—实际"闭环可再收紧 🟡 +### 2.6 改进点 A-5:内存预算的"预算—实际"闭环可再收紧 🟡 → ◐ **部分闭环(S11 已落地;堆告警已补,栈风险升级)** **现状**:已有 `ram_report.py`(.map 静态)+ `stack_report.py`(静态调用图 × 运行时水位) + `mem-numbers` pre-commit 钩子(校验文档数字与 .map 一致)。**这套机制很先进**。 -**缺口**: -1. `mem-numbers` **在 CI 上被跳过**(无 `.map`)——意味着**CI 不能守体积门禁**; -2. `configTOTAL_HEAP_SIZE`(48KB)无运行时余量告警——实测 `free=8,784 / min_ever=4,848 B`, - **min_ever 已低于 5KB**,若新增任务可能触发分配失败; -3. 上游 S-1(defaultTask 静态最坏链 2872B/4096,余量 29.9% 差 4.8B 达标)**仍未处理**。 +**缺口(2026-10-04 更新)**: +1. `mem-numbers` **在 CI 上被跳过**(无 `.map`)——意味着**CI 不能守体积门禁** + (已由 S14 显式提示,**未消除**); +2. ~~`configTOTAL_HEAP_SIZE`(48KB)无运行时余量告警~~ → ✅ **已补(S11,2026-10-03)**: + 堆低水位告警已落地(阈值 4096 B + 写 syslog selftest);V5 30 min 长跑**未触发**, + 最新基线 `free=8,664 / min_ever=4,728 B`(2026-10-04 重采,较 09-21 的 4,848 B 再降 120 B); +3. ⚠️ **上游 S-1 已升级为"需尽快处理"**:2026-10-04 产品构建实测 defaultTask 栈 + **3664 / 4096(余量 432 B ≈ 10%,远低于 30% 判据)**,较 2026-09-21 的 2872 B 明显上升; + 处置方向:栈 4096→4608(CCM 堆余量可覆盖 +512 B)或 GC 链局部削减。 -**建议**:见 §4.5(S9)——**堆余量低水位告警**(复用既有 `stack_probe_poll` 模式)。 +**建议**:见 §4.4(S11)——**堆余量低水位告警**(复用既有 `stack_probe_poll` 模式)。**已落地**。 -### 2.7 改进点 A-6:`configASSERT` 已改造但覆盖不足 🟡 +### 2.7 改进点 A-6:`configASSERT` 已改造但覆盖不足 🟡 → ⬜ **待做(S12)** **现状**(N-03a 已修):`configASSERT` 已从"关中断死循环"改为 `vApplicationAssertFailed(__FILE__, __LINE__)` → 打印后复位。**这是很好的改进**。 @@ -306,10 +336,10 @@ App/util/ringbuf.c 154 行 → 零 `#include "ringbuf.h"`,不在 Keil 工 项目自研代码**无统一断言宏**——例如 `net_socket.c` 的参数校验靠 `if + return -1`, `cfg_file.c` 的边界靠手工检查。**没有轻量断言**意味着"不该发生的情况"静默通过。 -**建议**:见 §4.6(S10)——引入**可选、可编译掉**的模块级断言宏 +**建议**:见 §4.5(S12)——引入**可选、可编译掉**的模块级断言宏 (生产构建零开销,测试构建启用),与 `test_common.h` 的 `TEST_CHECK` 呼应。 -### 2.8 改进点 A-7:模拟器差距清单未成体系 🟡 +### 2.8 改进点 A-7:模拟器差距清单未成体系 🟡 → ✅ **已闭环(2026-10-02,S13)** **现状**:多处提及"模拟器差距清单 +1"(N-4 二期门禁),例如 "net_socket_sim.c 无法建模 pending"。但**没有一份汇总的"模拟器差距清单"文档**—— @@ -318,13 +348,13 @@ App/util/ringbuf.c 154 行 → 零 `#include "ringbuf.h"`,不在 Keil 工 **风险**:模拟器回归通过 ≠ 真机通过,但**差异有多大、差在哪,无人能一眼说清**。 这会让"模拟器能否作为 L2 门禁"的判断失去依据。 -**建议**:见 §4.7(S11)——建立**单一差距清单文档**。 +**建议**:见 §4.6(S13)——建立**单一差距清单文档**。 --- ## 3. 测试体系改进实施建议 -### 3.1 S1:扩充 L0.5 主机侧单测(**最高性价比**)⭐⭐⭐⭐⭐ +### 3.1 S1:扩充 L0.5 主机侧单测(**最高性价比**)⭐⭐⭐⭐⭐ → ✅ **S1-a / S1-b 已落地;S1-c 可选** **目标**:把至少 2 个高价值纯逻辑模块纳入 L0.5,使"改这些模块"不再需要真机才能回归。 @@ -352,7 +382,7 @@ App/util/ringbuf.c 154 行 → 零 `#include "ringbuf.h"`,不在 Keil 工 > 修复使 Flash 减少 112 B(删除重复内联公式),内存快照已同步 > (`check_mem_numbers.py --write`)。 -**S1-b:`cfg_file.c` INI 解析器单测**(价值同样高,但需先确认抽象质量) +**S1-b:`cfg_file.c` INI 解析器单测**(价值同样高,但需先确认抽象质量)—— ✅ **已完成(2026-10-02)** | 步骤 | 内容 | |---|---| @@ -374,7 +404,7 @@ App/util/ringbuf.c 154 行 → 零 `#include "ringbuf.h"`,不在 Keil 工 - 测试钩子用 `#ifdef <模块>_UNIT_TEST` 守卫,**MCU 构建零符号**; - 单测**不能替代**板端验证——真机寄存器/复位原因/时序仍须 L1/L2。 -### 3.2 S2:为 L0.5 建立"适格模块清单"(防遗漏)⭐⭐ +### 3.2 S2:为 L0.5 建立"适格模块清单"(防遗漏)⭐⭐ → ✅ **已落地(2026-10-02)** **问题**:现在只有"看门狗"一个先例,**下一个该测谁**靠临时判断。 @@ -394,7 +424,7 @@ App/util/ringbuf.c 154 行 → 零 `#include "ringbuf.h"`,不在 Keil 工 **完成判据**:文档有台账,新增模块时按表判断是否需 L0.5。 -### 3.3 S3:CI 补产物存档与结果汇总 🟡 +### 3.3 S3:CI 补产物存档与结果汇总 🟡 → ✅ **已落地(2026-10-02)** **目标**:让 CI 失败**可远程排障**、让测试规模**可趋势观察**。 @@ -462,7 +492,7 @@ scripts/check_test_traceability.py > + 排除 `test/host/*/stub/` 模拟器桩)。`pre-commit run test-cppcheck --all-files` > **PASS**;新增 `test/board/` 代码的未初始化/越界/空指针现被自动拦截。 -### 3.6 S6:测试构建可编译性纳入验证(= 上游 P1-10 增量)🟡 +### 3.6 S6:测试构建可编译性纳入验证(= 上游 P1-10 增量)🟡 → ✅ **已落地(2026-10-02,方案 A)** **目标**:防止"测试套件长期编不过而无人知"(2026-08~09 CH395F 套件实例)。 @@ -470,8 +500,8 @@ scripts/check_test_traceability.py | 方案 | 做法 | 成本 | 效果 | |---|---|---|---| -| A(最轻) | `test/run_all_suites.py --dry-run` 基础上加 `--check-build`:仅改宏 + `@build`,**不烧录** | 低 | 每次回归窗口自动验证 4 套件可编译 | -| B | 新增 `@build-suites` 命令:循环 4 套件各跑一次 `@build`(含 RAM 溢出检查) | 中 | 一条命令全验 | +| A(最轻) | `test/run_all_suites.py --dry-run` 基础上加 `--check-build`:仅改宏 + `@build`,**不烧录** | 低 | 每次回归窗口自动验证 5 套件可编译 | +| B | 新增 `@build-suites` 命令:循环 5 套件各跑一次 `@build`(含 RAM 溢出检查) | 中 | 一条命令全验 | | C | CI 加 job(需 runner 有 Keil) | 高 | 自动守门,但当前 runner 无 Keil | **建议**:**先做 A**(`run_all_suites.py` 已有改宏 + `try/finally` 还原的骨架, @@ -480,7 +510,11 @@ scripts/check_test_traceability.py **注意**:RAM 溢出(P1-9:HW 全阶段固件超 8.7KB)意味着**即使能编译也可能链接失败**—— 方案 A 的 `@build` 会自然暴露 `L6406E`,这正是想要的。 -### 3.7 S7:真机回归增加"自检结果"判定 🟡 +> ✅ **2026-10-02 落地(走方案 A)**:`test/run_all_suites.py` 新增 `--check-build` +> ——每轮只改宏 + `@build`、**不烧录不采集**;编译通过即 PASS,失败即判定"该套件编译不过"。 +> 该模式**不需要串口/烧录工具**,可在纯离机环境运行(`--check-build` 下不强求 `run_boot_test.py` 存在)。 + +### 3.7 S7:真机回归增加"自检结果"判定 🟡 → ✅ **已落地(2026-10-02)** **目标**:让 `@test` 闭环不仅看串口标记,**还看设备的自检结论**。 @@ -502,11 +536,14 @@ scripts/check_test_traceability.py > **注**:`sys_clock_init` 在 RTC 故障时返回 -1 并触发"时钟芯片异常"自检 > (`项目架构总览.md` §3)——这正是当前闭环**捕获不到**的典型场景。 +> ✅ **2026-10-02 落地**:`@test` 闭环已消费自检结论,真机全闭环 **`@test` PASS 7/7**。 +> 完成判据达成——"时钟芯片异常""存储降级"等自检失败现可被闭环捕获。 + --- ## 4. 架构改进实施建议 -### 4.1 S8(原 A-1):清理孤儿源文件 ⭐⭐⭐ +### 4.1 S8(原 A-1):清理孤儿源文件 ⭐⭐⭐ → ✅ **已落地(2026-10-02)** **动作**:二选一,**必须做决策**(现状"留着不管"是最差选项)。 @@ -536,7 +573,7 @@ scripts/check_test_traceability.py **完成判据**:E-10/E-42/E-53/E-54/E-56/E-57 全部销项;GD5F 套件回归 PASS。 -### 4.3 S10(原 A-3):启动段可观测性 🟡 +### 4.3 S10(原 A-3):启动段可观测性 🟡 → ✅ **已落地(2026-10-02)** **先核查现状**:`app_main.c` 的 `app_main_init` 是否每步都有 `DBG_INFO`。 @@ -549,9 +586,13 @@ scripts/check_test_traceability.py **完成判据**:`app_main_init` 每一步都有可区分的日志行; 文档(`项目启动顺序管理.md` 或 `看门狗设计说明.md`)明确"启动段死机判读法"。 -### 4.4 S11(原 A-5):堆余量低水位告警 🟡 +> ✅ **2026-10-02 落地**:`app_main_init` 补 3 条、`sd2506_init` 补 6 条启动日志(Flash +904 B); +> `项目启动顺序管理.md` §6.8 新增"启动段死机判读法"。判据达成。 -**动机**:实测 `min_ever=4,848 B`(初始 48KB 堆),**余量已不到 10%**。 +### 4.4 S11(原 A-5):堆余量低水位告警 🟡 → ✅ **已落地(2026-10-03)** + +**动机**:实测 `min_ever=4,848 B`(初始 48KB 堆),**余量已不到 10%** +(2026-10-04 重采:`min_ever=4,728 B`,再降 120 B)。 未来新增任务/缓冲时,**分配失败可能在深夜台架长跑时才暴露**。 **实施路径**(复用既有 `stack_probe_poll` 模式,`default_task.c` 内): @@ -567,7 +608,10 @@ scripts/check_test_traceability.py **完成判据**:台架长跑下能观察到堆低水位告警(若有);文档记录阈值与基线。 -### 4.5 S12(原 A-6):模块级轻量断言宏 🟡 +> ✅ **2026-10-03 落地**:堆低水位告警已在 `defaultTask` 低频循环实现(阈值 4096 B + 写 syslog selftest); +> V5 30 min 长跑**未触发**告警,基线 `min_ever=4,728 B`(2026-10-04 重采)。判据达成。 + +### 4.5 S12(原 A-6):模块级轻量断言宏 🟡 → ⬜ **待做(第 4 波按需)** **动机**:`configASSERT` 只覆盖 FreeRTOS 内部;自研代码的"不该发生"靠散落的 `if`。 @@ -593,7 +637,7 @@ scripts/check_test_traceability.py **完成判据**:宏存在 + 生产构建 `@build` 0/0 且 `.map` 无新增符号;试点处有实际使用。 -### 4.6 S13(原 A-7):建立模拟器差距清单文档 🟡 +### 4.6 S13(原 A-7):建立模拟器差距清单文档 🟡 → ✅ **已落地(2026-10-02)** **动机**:模拟器回归是 L3 门禁,但"通过 ≠ 真机通过"。差异**散落各处**: @@ -618,7 +662,7 @@ scripts/check_test_traceability.py > 提升为"可执行判据")。`simulator/README.md` §五与 `docs/README.md` §5 已交叉引用; > 登记约定写入 §4(新增 `sim/` 后端差异必须登记)。 -### 4.7 S14:CI 与体积门禁的关系澄清 🟡 +### 4.7 S14:CI 与体积门禁的关系澄清 🟡 → ✅ **已落地(2026-10-02)** **现状**:`mem-numbers` 在 CI 上被跳过(无 `.map`)。 **这导致一个认知风险**:看到 CI 全绿可能误以为"体积也守住了"。 @@ -647,13 +691,13 @@ scripts/check_test_traceability.py | **第 2 波**(补测试能力) | S1-b | `cfg_file` L0.5 单测 | 无 | 中 | ✅ 2026-10-02(**抓出并修复外科手术保存死码 P0**) | | | S2 | L0.5 适格台账 | S1-a 经验 | 小 | ✅ 2026-10-02 | | | S10 | 启动段可观测性核查 | 无 | 小 | ✅ 2026-10-02(补 `sd2506_init` 6 条 + `app_main` 3 条;Flash +904 B) | -| | S6 | 测试构建可编译性(方案 A) | 无 | 小 | 🔄 2026-10-02 | +| | S6 | 测试构建可编译性(方案 A) | 无 | 小 | ✅ 2026-10-02(`run_all_suites.py --check-build`) | | **第 3 波**(架构加固) | S7 | 真机回归加自检判定 | 无 | 中 | ✅ 2026-10-02(`@test` PASS 7/7) | | | S11 | 堆低水位告警 | 无 | 小 | ✅ 2026-10-03(V5 长跑未触发,基线 min_ever=4728 B) | | | S9 | GD5F 错误通道(= 上游 C2) | 无 | 大 | ✅ 2026-10-03(台架套件回归 16/16) | | | S5 | `test/` 宽松静态检查 | 先跑基线 | 小~中 | ✅ 2026-10-03(`test-cppcheck` 钩子,`--enable=warning`) | | | S4 | 用例追溯脚本 | 无 | 中 | ✅ 2026-10-03(`scripts/check_test_traceability.py`,默认告警) | -| **第 4 波**(按需) | S12 | 模块级断言宏 | 试点验证 | 小(试点) | +| **第 4 波**(按需) | S12 | 模块级断言宏 | 试点验证 | 小(试点) | ⬜ **待做** | | | S13 | 模拟器差距清单 | 无 | 小 | ✅ 2026-10-02 | > **"⏸ 判据需真机"说明**(2026-10-02 补;**2026-10-03 台架窗口三项全部闭环**):S7 / S11 / S9 的**代码可离线编写**,但其**完成判据** @@ -665,26 +709,30 @@ scripts/check_test_traceability.py | 关系 | 说明 | |---|---| -| **独立可做** | S1/S2/S3/S4/S5/S8/S10/S11/S13/S14——**不依赖产品定义、不依赖上游阶段** | -| **与上游 A 并行** | S7(自检判定)与 A1(P0-1 真机验证)**同一轮台架窗口**做最划算 | -| **是上游 C 的骨架** | S9 就是上游 C2;§2.3 的四要素可直接作为 C2 的实施框架 | -| **是上游 B 的前置** | S1-b(`cfg_file` 单测经验)+ §2.5 的测试可验证性约束,**应在 B1/B2 动手前明确** | +| **独立可做** | S1/S2/S3/S4/S5/S8/S10/S11/S13/S14——**不依赖产品定义、不依赖上游阶段**(**✅ 已全部落地**) | +| **与上游 A 并行** | S7(自检判定)与 A1(P0-1 真机验证)**同一轮台架窗口**做最划算(**✅ S7 已落地,`@test` 7/7**) | +| **是上游 C 的骨架** | S9 就是上游 C2;§2.3 的四要素可直接作为 C2 的实施框架(**✅ 已落地,2026-10-03**) | +| **是上游 B 的前置** | S1-b(`cfg_file` 单测经验)+ §2.5 的测试可验证性约束,**应在 B1/B2 动手前明确**(◐ 经验已具备,约束待 B1/B2 落地时执行) | --- ## 6. 一句话总结 -> **测试体系的短板不在"广度"而在"中间层"**——L0.5 只有 1 个模块, -> 而 `sys_clock.c`(479 行日期算术)与 `cfg_file.c`(1250 行解析器) -> 这类"边界密集、零硬件、秒级可测"的模块**完全没有主机侧回归**, -> 使改动反馈被迫走"30s~2min 的真机链路"。**补齐 S1 是投入产出比最高的一步**。 +> **测试体系的短板不在"广度"而在"中间层"**——初版时 L0.5 只有 1 个模块; +> 经 S1-a / S1-b 落地,`sys_clock.c`(479 行日期算术)与 `cfg_file.c`(1250 行解析器) +> 这两类"边界密集、零硬件、秒级可测"的模块**已能在主机侧秒级回归**, +> 且**首跑各抓出一处生产缺陷**(Zeller 星期错误、外科手术保存死码 P0)—— +> **补齐 S1 确实是投入产出比最高的一步**。L0.5 现覆盖 3 个模块(看门狗 / `sys_clock` / `cfg_file`)。 > -> **架构的主缺口是"功能不对称"**(网络极成熟 vs 采集链路为空桩)与 -> **"纵深不对称"**(上层防御完备 vs NAND 错误通道散乱); -> 两者上游均已识别,本文补充了**测试可验证性约束**与**四要素实施骨架**。 +> **架构的主缺口是"功能不对称"**(网络极成熟 vs 采集链路为空桩)——**至今未变,是当前最高优先**; +> 而**"纵深不对称"**(上层防御完备 vs NAND 错误通道散乱)**已由 S9 收口** +> (GD5F 错误通道统一,2026-10-03)。本文补充的**测试可验证性约束**与**四要素实施骨架** +> 仍对上游 B1/B2 有效。 > -> 另有 **3 项低风险卫生改进**可立即执行:清理孤儿文件(S8)、 +> 另有 **3 项低风险卫生改进**已全部执行:清理孤儿文件(S8)、 > CI 产物存档(S3)、CI 体积门禁澄清(S14)。 +> +> **唯一待做**:S12(模块级轻量断言宏,第 4 波按需试点);S1-c(`sys_log` / `time_sync` 单测)为可选项。 --- @@ -692,6 +740,8 @@ scripts/check_test_traceability.py | 日期 | 变更 | |---|---| +| 2026-10-04 | **状态更新(全量复核)**:逐条核对 S1~S14 落地情况并就地标注(✅/◐/⬜)。§0.1 评价表刷新(**L0.5 1→3 模块**、**L0 钩子 15→18**、**板端 4→5 套件**、CI 已补产物存档与汇总行、验证债大幅下降);§0.3 优先级、§1.1 资产盘点、§1.2 缺口矩阵、§1.3 问题 T-1~T-5、§2.2~§2.8 各改进点、§3.1~§3.7、§4.1~§4.7、§5.1 路线图、§5.2、§6 同步。**修正交叉引用错位**:T-3/T-4/T-5 与 A-1/A-3/A-5/A-6/A-7 指向 §3.x/§4.x 的节号此前**整体偏移一节**,已逐一订正。§2.6 更新为 2026-10-04 重采数据(`min_ever=4,728 B`;**上游 S-1 升级:defaultTask 3664/4096 ≈ 10%**)。**结论:14 条建议已落地 12 条,仅 S12 待做。** | +| 2026-10-03 | 实施记录(台架窗口):**S7 已完成**(`@test` PASS 7/7);**S11 已完成**(堆低水位告警,V5 30 min 长跑未触发,基线 `min_ever=4728 B`);**S9 已完成**(GD5F 错误通道统一,套件回归 16/16 PASS);**S5 已完成**(`test-cppcheck` 钩子,基线 0 warning);**S4 已完成**(`scripts/check_test_traceability.py`,默认告警,当前 30 处差异)。§3.4 / §3.5 与 §5.1 状态已更新 | | 2026-10-02 | 实施记录(第 2 波):**S1-b 已完成**(`cfg_file` L0.5 单测 20 用例 / 139 断言点 + 钩子 `cfg-file-unit-test`;**首跑抓出"外科手术保存死码"P0**,`s_encode` 返回值 `==0` 恒假 → 已存在配置文件的保存静默不落盘,修 3 处为 `>=0`,记入 E-63);**S2 已完成**(§4.2.1 L0.5 适格台账);**S10 已完成**(补 `sd2506_init` 6 条 + `app_main` 3 条启动日志,Flash +904 B,`项目启动顺序管理.md` §6.8 新增"启动段死机判读法");**S13 已完成**(`docs/测试说明/模拟器差距清单.md`,6 网络 + 4 日志配置 + 7 硬件 + 4 有意对齐,含 §3 六条"必须回真机"规则)。§5.1 路线图状态已更新,S7/S11/S9 标注"判据需真机"押后 | | 2026-10-02 | 实施记录(第 1 波前半):**S8 已完成**(删除孤儿 `crc.c/h`、`ringbuf.c/h`,重跑引用关系图);**S1-a 已完成**(`sys_clock` L0.5 单测 20 用例 / 100 断言点 + 钩子 `sys-clock-unit-test`;**首跑抓出 Zeller 星期缺陷并修复**,Flash −112 B)。§3.1 S1-a 步骤表与 §5.1 路线图已更新状态 | | 2026-10-02 | 实施记录(第 1 波后半):**S3 已完成**(CI 两 job 产物存档 + 汇总行,零依赖方案);**S14 已完成**(CI 体积门禁盲区显式提示 + `CI配置指南.md` §0.0 声明) |