merge: v2-on-ui into task/screenlink-bench-serial (wave + screenlink)

This commit is contained in:
2026-10-30 01:08:37 +08:00
134 changed files with 10699 additions and 1190 deletions
+1 -1
View File
@@ -44,7 +44,7 @@
| `ci_local.py` | **本地跑与 CI 等价的门禁**(静态门禁 pre-commit 47 根 + **manual 段**(`cppcheck` / `test-cppcheck` / `test-coverage` 三根逐根 `--hook-stage manual`,默认跑)+ 提交信息门禁 + **体积门禁** + 主机侧纯逻辑单测):自动选用装了 pre-commit 的解释器;无 `.map` 时自适应跳过 `mem-numbers` / `mem-budget`(⚠ 那是 SKIP 不是通过,缺口由体积门禁兜住);退出码 0/1/2 与 CI 对齐。CI 定义见 `../.gitea/workflows/ci.yml`,覆盖边界见 `docs/测试说明/测试开发标准流程.md` §9 |
| `check_size_gate.py` | **体积门禁的强制路径**:`.map` 只在本地有,钩子无它时自适应 SKIP,于是"没测=通过"。本脚本用**已提交的同码凭证** `scripts/size_attestation.json` 把这条判据变成无需 Keil 也能跑:`--stamp` 只在"`.map` 存在、比全部受管源码新、且未超 92%"时才盖章(已挂在 `ram_baseline.py --update` 里,无新增人工步骤);`--local` 供 ci_local 的体积门禁步;`--ci` 供 runner(同码性 + 按凭证数字复核红线,主干 push 拦红、其余事件 `--warn-only`);`--show` 排障。**口径与边界的唯一正文在本脚本模块 docstring** |
| `size_attestation.json` | (被 `check_size_gate.py` 读写)体积同码凭证:受管源码指纹(`git ls-files` 范围内逐文件 sha256 聚合)+ 测量数字与占比 + `.map` 出处。改固件源码后不重测 → 指纹对不上 → 体积门禁与 CI 同时拦红 |
| `check_test_coverage.py` | 主机单测**覆盖率**(2026-10-23):mscoverage 动态插桩跑 `test/host/**` 全部 41 套,统计自研生产源码行/函数覆盖(并集)+ 与 `test_coverage_baseline.json` 比回退;`--module/--update-baseline/--md/--json/--list`;挂在 `test-coverage` 钩子上(`stages: [manual]`,**`git commit` 不跑**),入口 = 远端 CI「手动阶段门禁」步 / `scripts/ci_local.py` 的 manual 段(`--coverage` 旗标保留只为兼容旧命令;口径见 `docs/测试说明/主机单测覆盖率口径.md`) |
| `check_test_coverage.py` | 主机单测**覆盖率**(2026-10-23):mscoverage 动态插桩跑 `test/host/**` 全部 44 套,统计自研生产源码行/函数覆盖(并集)+ 与 `test_coverage_baseline.json` 比回退;`--module/--update-baseline/--md/--json/--list`;挂在 `test-coverage` 钩子上(`stages: [manual]`,**`git commit` 不跑**),入口 = 远端 CI「手动阶段门禁」步 / `scripts/ci_local.py` 的 manual 段(`--coverage` 旗标保留只为兼容旧命令;口径见 `docs/测试说明/主机单测覆盖率口径.md`) |
| `ci_gitlint_range.ps1` | CI 侧**提交信息门禁**:逐条校验本次 push/PR 引入的提交(`--all-files` 跑不到 `commit-msg` stage,故必须单独守) |
| `ci_find_python.ps1` | CI 侧 Python 探测(候选顺序须与 `ci_local.py` 同序同步,否则 CI 与本地判定会分叉) |
| `ci_runner_bootstrap.ps1` | **本机 runner 运维脚本**(体检 `-Status` / 干跑 `-DryRun` / 部署 `-SetEnv -StartNow`):装"等 Gitea 就绪 + 崩溃自拉起"的看门狗 + 开机计划任务 + 机器级 `DTU_*` |
+9 -7
View File
@@ -1,11 +1,12 @@
# 编号门禁·全库语料审计(已退役,2026-10-28 归档)
# 编号门禁归档(两道都已退役:全库语料审计 2026-10-28、新增行检查 2026-10-29)
本目录是 2026-10-20 ~ 2026-10-28 期间在 `pre-commit` 里跑的那套**全库编号审计**,
连同它的两份语料一起搬进来,**不再进提交门禁**。
本目录是 2026-10-20 ~ 2026-10-29 期间在 `pre-commit` 里跑过的**两套编号门禁**,连同它们的
语料与白名单一起搬进来,**都不再进提交门禁**。2026-10-29 的裁定见每篇文末与其留档文档。
| 文件 | 是什么 |
|---|---|
| `check_ids.py` | 八项校验脚本(规范 §8)。手工复查存量编号现状时才跑 |
| `check_ids_new.py` | 只查新增行的那道(2026-10-28 ~ 2026-10-29 在钩子里跑),2026-10-29 用户裁定退役后降为**手工形态普查**;`--self-test` 保留,`REPO_ROOT` 因归档位置深两级改取 `parents[3]` |
| `id_registry.json` | 99 族的注册表:形态正则 / 属主登记处 / 冻结 / 游标 / 两条护栏的数值 |
| `id_aliases.json` | 旧号 → 新号 / 作废(`retired-to-phrase`、`void`)的别名表,187 KB |
| `id_known_backlog.json` | 债务台账(收口时已还清到 0 条) |
@@ -18,10 +19,11 @@
## 现在用什么
- **现行门禁**:`scripts/check_ids_new.py` + 钩子 `id-check-new` —— 只查 `git diff` 新增行,
零语料。详解 `docs/门禁说明/id-check-new.md`。
- **路线与验收条件**:`docs/编号规范.md` §8.5(①②③ 三步的来龙去脉)。
- **规范正文**(仍然有效,只是不再全库机械校验):`docs/编号规范.md` §1 先问三句、§4.1 族总表。
- **没有现行门禁**:接班的 `id-check-new`(只查新增行、零语料)也在 2026-10-29 被用户裁定退役,
脚本进本目录。编号形态此后无机器面,判据 = `docs/编号规范.md` §1 的默认答案(2026-10-29 起一律停发)+ §4.1 存量族表 + 评审;
留档 `docs/门禁说明/id-check-new.md`(拦下过什么、为什么退、手工怎么再跑)。
- **手工普查与恢复机器面**:`docs/编号规范.md` §8.5(退役流水在 `编号治理历史.md`)。
- **规范正文**(仍然有效,只是不再全库机械校验):`docs/编号规范.md` §1 默认答案、§4.1 存量族表。
## 怎么手工跑一次
+5 -3
View File
@@ -5,10 +5,12 @@ check_ids.py — 编号门禁(docs/编号规范.md §8 的 8 项校验)—
⚠ 退役说明(先读这段,别把它当活门禁用):
本脚本与两份语料(id_registry.json / id_aliases.json)已整体移入 scripts/archive/id_gate/,
**不再进 pre-commit**,也不再有人被要求维护语料。现行编号门禁是 scripts/check_ids_new.py
(钩子 id-check-new:只查新增行、零语料)。本脚本保留下来只做一件事:
**不再进 pre-commit**,也不再有人被要求维护语料。接班的 scripts/check_ids_new.py
(钩子 id-check-new:只查新增行、零语料)已于 2026-10-29 一并退役,也进了本目录——
**编号形态此后没有机器面**。本脚本保留下来只做一件事:
想复查「存量编号现状」时手工跑一遍出报告。
路线与判据替换的来龙去脉 → docs/编号规范.md §8.5;新门禁详解 → docs/门禁说明/id-check-new.md。
手工普查与恢复机器面 → docs/编号规范.md §8.5;两道门禁的留档 → docs/门禁说明/id-check.md
与 docs/门禁说明/id-check-new.md。
下面这份 docstring 是退役前的原样,未改,作为历史口径保留。
两份配置(数据源 = 规范 §4 编号空间总表,逐项对应,不凭印象):
@@ -1,9 +1,11 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""check_ids_new.py — 编号门禁·第二步:只查**新增行**的新编号(零语料、无语料维护)
"""check_ids_new.py — 编号门禁·新增行(**已退役 2026-10-29,用户裁定**;本脚本降为手工报告工具)
背景(docs/编号规范.md §8.5):语义标识已是默认形态,1~6 项全库语料审计的成本高过收益。
本脚本替代它的**唯一实际用途**——拦住"新写一个自造编号":只看 git diff 的新增行。
退役口径:钩子已从 .pre-commit-config.yaml 摘除(YAML 解析条目 52 → 51),编号形态此后
**没有机器面**——靠 docs/编号规范.md §1 的默认答案(一律停发)+ 评审。留档说明 → docs/门禁说明/id-check-new.md。
本脚本与 check_ids.py(2026-10-28 退役的全库八项校验)同处一档:手工复查「这批改动 / 这段历史
里有没有野生编号」时才跑,跑不跑都不影响提交。
判据(三条,都不依赖任何族清单 / 游标 / 属主登记处):
1. 破折形态(形如 前缀-数字,或 前缀-段-数字):首段不在 KNOWN_DASH → FAIL;
@@ -12,11 +14,11 @@
3. 单字母+数字(C12 / U15 / L3 / R3)→ **放行**:元件位号与层次号同形,这是本脚本的已知盲区
(与旧门禁的"裸形盲区"同源,见 docs/门禁说明/id-check-new.md §5)。
用法(仓库根):
python scripts/check_ids_new.py # 查暂存区(pre-commit 用这个)
python scripts/check_ids_new.py --worktree # 查工作区未暂存的改动(自查)
python scripts/check_ids_new.py --range A..B # 查一段提交的新增行
python scripts/check_ids_new.py --self-test # 内建正反例自检(改脚本后必跑)
用法(仓库根;钩子摘除后没有自动调用者,四条都是手工):
python scripts/archive/id_gate/check_ids_new.py # 查暂存区
python scripts/archive/id_gate/check_ids_new.py --worktree # 查工作区未暂存的改动
python scripts/archive/id_gate/check_ids_new.py --range A..B # 查一段提交的新增行
python scripts/archive/id_gate/check_ids_new.py --self-test # 内建正反例自检(改脚本后必跑)
退出码:0 = 通过 / 仅告警;1 = 新增了未知编号;2 = 环境错误。
豁免:行内含 [示例] / [计划] 的行按冻结口径跳过;确需保留的写法在同一行写 [编号豁免]。
"""
@@ -33,7 +35,8 @@ for _stream in (sys.stdout, sys.stderr):
except (AttributeError, ValueError):
pass
REPO_ROOT = Path(__file__).resolve().parent.parent
# 归档位置比原位置深两级(scripts/archive/id_gate/)→ 上溯到仓库根要 parents[3]
REPO_ROOT = Path(__file__).resolve().parents[3]
# --- 破折形态:首段白名单(活族 + 标准编号;新增族要先登记到这里,这就是"允许用号的唯一口子")
KNOWN_DASH = frozenset({
@@ -79,6 +82,9 @@ KNOWN_BARE = frozenset({
"SFT",
# UART 采样模式位名(OVER8)
"OVER",
# 录波段文件名:固件生成的 100 个号轮转(WAVE00 到 WAVE99 的 .BIN,App/algo/wave_store.c 拼名
# FTP 根下 /wave/ 目录;文档与日志里都要写这个字面量,2026-10-29 登记)
"WAVE",
})
# --- 前缀后面接 -数字 其实是算术(SIZE-2 / LEN-1),不是编号
@@ -95,7 +101,8 @@ EXCLUDED_DIRS = (
)
EXCLUDED_FILES = frozenset({
"scripts/check_ids_new.py", # 本脚本自带正反例白名单,不能自我拦截
"scripts/check_ids_new.py", # 本脚本自带正反例白名单,不能自我拦截(归档后整目录已在
# EXCLUDED_DIRS 的 scripts/archive/ 里,这行只是历史留笔)
})
EXCLUDED_SUFFIX = (".svg", ".png", ".jpg", ".jpeg", ".gif", ".bin", ".map", ".htm", ".html",
".tsv", ".log", ".o", ".axf", ".hex", ".ico", ".ttf", ".woff", ".pyc",
@@ -245,7 +252,8 @@ def main(argv=None):
if args.verbose:
print(" %s" % text)
print(" → 语义标识是默认形态:改写成短语(docs/编号规范.md §1);")
print(" 确属设备名/协议名/位号,就把前缀登记进 scripts/check_ids_new.py 的白名单。")
print(" 确属设备名/协议名/位号,就改形态(写语义短语)——本门禁已于 2026-10-29 退役,")
print(" 不再是提交钩子;要再拿它当尺子就手工跑 scripts/archive/id_gate/check_ids_new.py。")
return 1
print("[OK] 新增行无未登记编号%s"
% ("(%d 处停发族提示)" % len(warns) if warns else ""))
@@ -355,7 +355,7 @@ P-6 号必须能反查到定义(属主登记处得存在)· P-7 编号不语
| 日期 | 变更 | 说明 |
|---|---|---|
| 2026-10-28 | **编号门禁第三步收口:全库语料审计退役(钩子 52 → 51)** | 用户裁定跳过观察期直接做。`check_ids.py` 与两份语料(`id_registry.json` 87.6 KB / `id_aliases.json` 187 KB)+ 债务台账整体移入 `scripts/archive/id_gate/`(附归档 README,含"为什么退役 / 现在用什么 / 怎么手工跑");`id-check` 钩子摘除,现役编号门禁只剩 `id-check-new`(只查新增行)。连带改:`rename_ids.py` 的别名表路径指向归档、新门禁排除面加 `scripts/archive/`、`doc-links` 跳过 `.mnemon/` 与 `ci-artifacts/`(本地状态与草稿,非项目文档)、`id-check.md` 加退役横幅、`门禁说明/README` 与 `AGENTS` 的钩子数三数对齐(声明 51 / commit 阶段 50 + gitlint 1)。归档脚本从新路径实跑:811 文件 / 8,051 字面量、`--strict` rc=0。 |
| 2026-10-28 | **编号门禁第二步落地:新增行拦截(零语料)** | `scripts/check_ids_new.py` + 钩子 `id-check-new`:只看新增行,破折形态未知前缀 FAIL、已停发族只 WARN、单字母+数字放行(元件位号同形,见该门禁 §6 盲区)。白名单是**前缀级**两张表(活族 11 条 / 器件与协议约 90 条),不是字面量账本——后者会退化成 `id_aliases.json` 的老路。调参依据:最近 80 笔真实提交回放,未知形态 15 种(12 种是设备与协议名、3 种是停发族),调好后误报 0;自检 5 正例 + 29 反例。与 `id-check` **双跑**一个观察期后再按 `docs/编号规范.md` §8.5 ③ 退役旧语料。 |
| 2026-10-28 | **编号门禁第二步落地:新增行拦截(零语料)** | 脚本(今在 `scripts/archive/id_gate/check_ids_new.py`)+ 钩子 `id-check-new`:只看新增行,破折形态未知前缀 FAIL、已停发族只 WARN、单字母+数字放行(元件位号同形,见该门禁 §6 盲区)。白名单是**前缀级**两张表(活族 11 条 / 器件与协议约 90 条),不是字面量账本——后者会退化成 `id_aliases.json` 的老路。调参依据:最近 80 笔真实提交回放,未知形态 15 种(12 种是设备与协议名、3 种是停发族),调好后误报 0;自检 5 正例 + 29 反例。与 `id-check` **双跑**一个观察期后再按 `docs/编号规范.md` §8.5 ③ 退役旧语料。 |
| 2026-10-28 | **编号门禁减负第一步:两根护栏转报告制** | 用户裁定「编号门禁每次浪费很多时间」→ 先摘掉语料审计的强制面。护栏 1(可判定比例基线)与护栏 2(不可判定绝对数上限)自此**只打印、不拦提交**;实测把基线调到 99.9%、上限调到 1 处,退出码仍为 0。硬拦只剩校验 1~6 的台账外新账(同一实测:新文件里写一个自造前缀 + 数字,校验 1 与增量拦截照旧 FAIL)。退役路线 ①②③ 写进 `docs/编号规范.md` §8.5;减负依据 = 近 80 笔提交有 61 笔被编号体系牵连、语料共 99 族(78 族已冻结)。 |
| 2026-10-28 | **变更记录行里已停发/作废族的示例编号改形态描述;并用门禁自身计数器把「这一笔能不能压下不可判定绝对数」钉死为零** | 用户指令:把变更记录行里已停发族的那几枚示例编号改成语义形态描述,并确认它让不可判定引用绝对数净减、不是只算自己这一笔。**实测裁定:净减 = 0**。门禁把「表格首格是日期」的行整行豁免于编号判定(registry 侧的变更记录豁免,本笔前全库已豁免 198 处站点),本表的示例编号从来不进引用总数分母,改它必然不动绝对数——改前改后同一个计数器均为 **1003**(上限 1166;可判定 87.43%,三项都是 2026-10-28 本回合实测)。唯一移动的是那行豁免计数本身(本文件少 1 处站点),把它当清退成果就是把自记账成全局减量,正是本笔要排除的错法。本文对该计数器的全部贡献 **6** 处,逐文件集合差实测:全是「非编号」判定栏里既定的噪声名与裸形盲区(哈希算法名、总线名、严重度档位、硬件位号),不是编号,不清。本笔动的 3 处只是写法:作废的网络条目孤儿号(F 前缀 + 模块码段 + 数字序号三段)与已删报告的 UI 簇(字母 U 紧跟一位数字,区间两端即该簇首尾两枚);事实本体仍在别名表、registry 游标备注与 git 历史,一处没丢。刻意不动:硬件位号形态的举例(判非编号)、保留现存号族的冻结游标数字(冻结水位的证据本体)、其它文档与注册表里的同名字段(各自写域)。`docs/编号规范.md` §5.5 同步写死该例外的硬口径。零代码、零编号增删、两根护栏基线均未调整。 |
| 2026-10-27 | **批次五:「数据可信」任务卡号整族清退 + 注入验证卡销项删行** | 用户指令「数据可信.md 已经完成的内容请进行销项删除,去除相关编号」。实测 **288 站点 / 56 文件**(代码与测试 191 / 文档 56 / 门禁配置与本文 41)全改语义短语;`docs/编号规范.md` §5 表首列由「序」改「标识(任务名)」、14 个旧号进 §9.3 换算表;顺带按属主文档判语义清掉同形态的悬空引用 4 处(「UI 补齐」波次的 `[comm]` 段前置项)。门禁面:编号字面量与不可判定绝对数**零变化**(中文前缀不在语料),收口复跑 `check_ids.py --strict` 与 `check_doc_links.py --all --sections-strict` |
+1 -1
View File
@@ -993,7 +993,7 @@ def selftest_board_frames(clf):
def selftest_refs(clf):
"""仓库黄金参考(60 张)逐帧分类自检:每张图的期望值 = 它的文件名。
"""仓库黄金参考(66 张)逐帧分类自检:每张图的期望值 = 它的文件名。
这一组是**语义正确的基线**(模拟器与板端同一份 UI 源码),用来把"分类器错了"与
"留档帧本来就是走歪的"分开——两类失败含义完全不同,混在一起就只能靠猜。
+2 -2
View File
@@ -339,8 +339,8 @@ def main(argv=None):
ap.add_argument("--selftest", action="store_true", help="正例照得出 + 反例不误报 + 基线机制有效")
args = ap.parse_args(argv)
if not os.path.isdir(os.path.join(REPO, ".git")):
print("[ENV] 仓库根定位失败:%s 里没有 .git" % REPO)
if not os.path.exists(os.path.join(REPO, ".git")):
print("[ENV] 仓库根定位失败:%s 里没有 .git(目录或 worktree 的 gitdir 文件都算)" % REPO)
return 2
print("=== 块注释嵌套检查 check_nested_comment.py(注释体内出现 /* = ARMCC 诊断 9-D)===")
+61 -5
View File
@@ -78,7 +78,11 @@ def subsystem_of(obj):
return RTOS_HEAP
if n in _KERNEL:
return "其它"
if n.startswith(("app_", "adc_", "prot_", "phasor", "sample_ring",
# 应用 = App/ 其余(台账 §2 口径)。新增 App 目录/前缀必须同步这里,
# 漏登记不会报错,只会被静默算进「其它」——unattributed_app_objects() 是兜底信号。
if n.startswith(("app_", "adc_", "prot_", "protect_task", "phasor", "sample_ring",
"wave_", "meas", "freq", "run_par", "iec104", "soe_",
"task_prof", "boot_stats", "vol_idle_sync",
"sys_", "cfg_", "dbg_", "console_log", "task_watchdog",
"sha256", "tpafe", "sd2506", "test_task", "time_sync",
"default_task")):
@@ -86,6 +90,56 @@ def subsystem_of(obj):
return "其它"
# 兜底:源文件在 App/ 却落进「其它」= 前缀表漏登记。2026-10-29 实测这样隐身了
# 12 个对象 / 9,445 B(wave_ring 5,296 起),配额表完全看不见录波与 SOE 支路。
_APP_SRC_DIR = REPO_ROOT / "App"
_APP_STEMS = None
def _app_stems():
"""App/**/*.c 主干名集合(扫一次缓存);目录读不到就返回空集 = 兜底自动失效。"""
global _APP_STEMS
if _APP_STEMS is None:
try:
_APP_STEMS = {p.stem.lower() for p in _APP_SRC_DIR.rglob("*.c")}
except OSError:
_APP_STEMS = set()
return _APP_STEMS
def _obj_base(obj):
return obj.rsplit("\\", 1)[-1].rsplit("/", 1)[-1].lower()
def unattributed_app_objects(objs):
"""[(对象, B)]:归进「其它」但源文件在 App/ 的对象,按字节降序。"""
stems = _app_stems()
if not stems:
return []
out = []
for obj, nbytes in objs:
if subsystem_of(obj) != "其它":
continue
base = _obj_base(obj)
if base.endswith(".o") and base[:-2] in stems:
out.append((obj, nbytes))
return sorted(out, key=lambda t: (-t[1], t[0]))
def warn_unattributed(info):
"""打印未归类告警(软提醒,不拦);返回条数。门禁与 --write 都调,别让人静默隐身。"""
missing = unattributed_app_objects(info["objs"])
if not missing:
return 0
total = sum(n for _, n in missing)
print("[WARN] %d 个 App/ 对象未登记进 subsystem_of() 前缀表,被算进「其它」而不是"
"「应用」(台账 §2:应用 = App/ 其余),合计 %d B:" % (len(missing), total))
for obj, nbytes in missing:
print(" %-28s %6d B" % (_obj_base(obj), nbytes))
print(" 修法:补 subsystem_of() 前缀 -> 重跑 @build -> --update / --write 回填台账")
return len(missing)
def collect(map_path):
"""解析 .map → {'regions': {name: r}, 'subsys': {name: bytes}, 'top': [(obj, B)]}。"""
data = ram_report.parse_map(str(map_path))
@@ -96,11 +150,11 @@ def collect(map_path):
subsys = {s: 0 for s in SUBSYSTEMS}
for c in comps:
subsys[subsystem_of(c["object"])] += c["rw_data"] + c["zi_data"]
top = sorted(((c["object"], c["rw_data"] + c["zi_data"]) for c in comps),
key=lambda t: (-t[1], t[0]))
top = [t for t in top if t[1] > 0][:TOP_N]
objs = [(c["object"], c["rw_data"] + c["zi_data"]) for c in comps]
objs = [t for t in objs if t[1] > 0]
top = sorted(objs, key=lambda t: (-t[1], t[0]))[:TOP_N]
return {"regions": regions, "region_list": data["regions"],
"subsys": subsys, "top": top}
"subsys": subsys, "top": top, "objs": objs}
def region_pct(r):
@@ -238,6 +292,8 @@ def cmd_gate(args):
if newest and newest > map_path.stat().st_mtime:
print("[WARN] .map 早于最新源码——数字来自旧构建,建议先 @build 再提交")
warn_unattributed(info)
ir, cc = info["regions"].get("RW_IRAM1"), info["regions"].get("RW_CCM")
print(f"RAM 预算门禁 PASS:RW_IRAM1 {region_pct(ir):.1f}% / RW_CCM {region_pct(cc):.1f}%"
f"(阈值 {THRESHOLD_PCT:.0f}%)")
+2 -1
View File
@@ -12,4 +12,5 @@ date code ro rw zi er_irom1 er_pct iram1 iram1_pct ccm ccm_pct top_rwzi
2026-10-27 235372 26392 1572 136924 261764 25.0 81072 61.9 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4055;default_task.o=2736
2026-10-28 236456 28124 1876 137084 264580 25.2 81536 62.2 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4055;default_task.o=2736
2026-10-29 238936 29140 1932 141396 268076 25.6 85904 65.5 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;sb_link.o=4364;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4055
2026-10-30 239064 29156 1932 141396 268220 25.6 85904 65.5 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;sb_link.o=4364;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4055
2026-10-29 243552 28784 1972 145388 272336 26.0 89936 68.6 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;wave_ring.o=5296;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4055
2026-10-30 246160 29816 2036 149700 275976 26.3 94312 72.0 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;wave_ring.o=5296;sb_link.o=4364;ch395f.o=4162;console_log.o=4132
1 date code ro rw zi er_irom1 er_pct iram1 iram1_pct ccm ccm_pct top_rwzi
12 2026-10-27 235372 26392 1572 136924 261764 25.0 81072 61.9 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4055;default_task.o=2736
13 2026-10-28 236456 28124 1876 137084 264580 25.2 81536 62.2 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4055;default_task.o=2736
14 2026-10-29 238936 29140 1932 141396 268076 25.6 85904 65.5 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;sb_link.o=4364;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4055
15 2026-10-30 2026-10-29 239064 243552 29156 28784 1932 1972 141396 145388 268220 272336 25.6 26.0 85904 89936 65.5 68.6 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;sb_link.o=4364;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4055 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;wave_ring.o=5296;ch395f.o=4162;console_log.o=4132;sys_log_mcu.o=4055
16 2026-10-30 246160 29816 2036 149700 275976 26.3 94312 72.0 57376 87.9 heap_4.o=57376;lv_mem_core_builtin.o=16384;lftpd.o=7884;ui_net_sink.o=6770;ui_port.o=6420;nand_ftl.o=6216;wave_ring.o=5296;sb_link.o=4364;ch395f.o=4162;console_log.o=4132
+13 -13
View File
@@ -1,25 +1,25 @@
{
"built_at": "2026-10-30T00:21:57+08:00",
"fingerprint": "1cbc1bc0c030169d1851e6303e0d643ae1f01632f03883215557416e7f3eb4ee",
"fingerprint_files": 1458,
"built_at": "2026-10-30T01:06:44+08:00",
"fingerprint": "1ed4267c77f65e357f631ef775aef15a784757ae2ffecf15cb3838b5e2ce1fb5",
"fingerprint_files": 1466,
"fingerprint_source": "git-index",
"gated_regions": [
"RW_IRAM1",
"RW_CCM"
],
"git_head": "9c6d150261caacd1a3ff835d2830f706e9de2bf7",
"git_head": "f405c8994fd0123b7b8ad1d449a372508a5276ac",
"map": "MDK-ARM/STM32F407-Demo/STM32F407-Demo.map",
"map_mtime": 1793290914,
"map_mtime": 1793293592,
"pct": {
"ER_IROM1": 25.58,
"ER_IROM1": 26.32,
"RW_CCM": 87.89,
"RW_IRAM1": 65.54,
"RW_IRAM1": 71.95,
"UNINIT_CCM": 18.75
},
"regions": {
"ER_IROM1": {
"max": 1048576,
"size": 268220
"size": 275976
},
"RW_CCM": {
"max": 65280,
@@ -27,7 +27,7 @@
},
"RW_IRAM1": {
"max": 131072,
"size": 85904
"size": 94312
},
"UNINIT_CCM": {
"max": 256,
@@ -37,10 +37,10 @@
"schema": 2,
"scope_note": "\u540c\u7801\u51ed\u8bc1\uff1a\u6307\u7eb9\u8986\u76d6\u56fa\u4ef6\u4f53\u79ef\u76f8\u5173\u6e90\u7801\uff0c\u53e3\u5f84\u89c1\u672c\u811a\u672c docstring",
"sizes": {
"code": 239064,
"ro_data": 29156,
"rw_data": 1932,
"zi_data": 141396
"code": 246160,
"ro_data": 29816,
"rw_data": 2036,
"zi_data": 149700
},
"threshold_pct": 92.0,
"worktree_dirt_at_stamp": 0,
+110 -45
View File
@@ -1,12 +1,12 @@
{
"files": {
"App/algo/adc_cal.c": {
"func_rate": 1.0,
"func_rate": 0.9412,
"funcs_covered": 16,
"funcs_valid": 16,
"line_rate": 0.986,
"funcs_valid": 17,
"line_rate": 0.9463,
"lines_covered": 141,
"lines_valid": 143
"lines_valid": 149
},
"App/algo/adc_health.c": {
"func_rate": 1.0,
@@ -88,6 +88,22 @@
"lines_covered": 15,
"lines_valid": 15
},
"App/algo/wave_ring.c": {
"func_rate": 1.0,
"funcs_covered": 15,
"funcs_valid": 15,
"line_rate": 0.9956,
"lines_covered": 225,
"lines_valid": 226
},
"App/algo/wave_store.c": {
"func_rate": 1.0,
"funcs_covered": 29,
"funcs_valid": 29,
"line_rate": 0.9612,
"lines_covered": 446,
"lines_valid": 464
},
"App/cfg/cfg_file.c": {
"func_rate": 0.963,
"funcs_covered": 26,
@@ -369,12 +385,12 @@
"lines_valid": 75
},
"Drivers/BSP/UI/ui_data.c": {
"func_rate": 0.9767,
"func_rate": 0.8235,
"funcs_covered": 42,
"funcs_valid": 43,
"line_rate": 0.9637,
"funcs_valid": 51,
"line_rate": 0.8692,
"lines_covered": 372,
"lines_valid": 386
"lines_valid": 428
},
"Drivers/BSP/UI/ui_net_sink.c": {
"func_rate": 0.7692,
@@ -397,10 +413,10 @@
"modules": {
"adc_cal": {
"files": {
"App/algo/adc_cal.c": 143,
"App/algo/adc_cal.c": 149,
"App/cfg/cfg_file.c": 689
},
"lines_total": 832,
"lines_total": 838,
"ok": true
},
"adc_health": {
@@ -471,7 +487,7 @@
},
"iec104": {
"files": {
"App/algo/adc_cal.c": 143,
"App/algo/adc_cal.c": 149,
"App/algo/freq.c": 130,
"App/algo/meas.c": 64,
"App/algo/phasor.c": 55,
@@ -485,7 +501,7 @@
"App/protocol/iec104/iec104_link.c": 405,
"App/protocol/iec104/iec104_pts.c": 255
},
"lines_total": 2365,
"lines_total": 2371,
"ok": true
},
"iec104_serv": {
@@ -586,14 +602,14 @@
},
"prot_dim": {
"files": {
"App/algo/adc_cal.c": 143,
"App/algo/adc_cal.c": 149,
"App/algo/freq.c": 130,
"App/algo/phasor.c": 55,
"App/algo/prot_elm.c": 122,
"App/algo/prot_set.c": 179,
"App/algo/sample_ring.c": 41
},
"lines_total": 670,
"lines_total": 676,
"ok": true
},
"prot_elm": {
@@ -624,11 +640,11 @@
},
"run_par": {
"files": {
"App/algo/adc_cal.c": 143,
"App/algo/adc_cal.c": 149,
"App/algo/run_par.c": 129,
"App/cfg/cfg_file.c": 689
},
"lines_total": 961,
"lines_total": 967,
"ok": true
},
"sb_led_map": {
@@ -706,10 +722,10 @@
},
"ui_data": {
"files": {
"Drivers/BSP/UI/ui_data.c": 386,
"Drivers/BSP/UI/ui_data.c": 428,
"Drivers/BSP/UI/ui_w_soe.c": 62
},
"lines_total": 448,
"lines_total": 490,
"ok": true
},
"ui_sink": {
@@ -739,6 +755,29 @@
},
"lines_total": 73,
"ok": true
},
"wave_ring": {
"files": {
"App/algo/wave_ring.c": 226,
"App/algo/wave_store.c": 464
},
"lines_total": 690,
"ok": true
},
"wave_store": {
"files": {
"App/algo/wave_store.c": 464
},
"lines_total": 464,
"ok": true
},
"wave_trig": {
"files": {
"App/algo/wave_ring.c": 226,
"App/algo/wave_store.c": 464
},
"lines_total": 690,
"ok": true
}
},
"note": "主机单测覆盖率基线。口径与工具链限制见 docs/测试说明/主机单测覆盖率口径.md。门禁判据:files[].lines_covered 与 funcs_covered 只增不减,下降即拦提交。",
@@ -755,6 +794,8 @@
"App/algo/run_par.c",
"App/algo/sample_ring.c",
"App/algo/sb_led_map.c",
"App/algo/wave_ring.c",
"App/algo/wave_store.c",
"App/cfg/cfg_file.c",
"App/cfg/cfg_file_store_mcu.c",
"App/cfg/prot_set_store.c",
@@ -796,16 +837,16 @@
],
"totals": {
"files_generated_excluded": 5,
"files_tested": 49,
"files_untested": 166,
"func_rate": 0.9324,
"funcs_covered": 552,
"funcs_valid": 592,
"line_rate": 0.9009,
"lines_covered": 7349,
"lines_valid": 8157,
"modules_ok": 44,
"modules_total": 44
"files_tested": 51,
"files_untested": 172,
"func_rate": 0.924,
"funcs_covered": 596,
"funcs_valid": 645,
"line_rate": 0.9016,
"lines_covered": 8020,
"lines_valid": 8895,
"modules_ok": 47,
"modules_total": 47
},
"untested_sources": [
{
@@ -816,10 +857,22 @@
"code_lines": 689,
"path": "Drivers/BSP/GD5F2GQ5UE/gd5f2gq5ue.c"
},
{
"code_lines": 525,
"path": "App/task/ui_task.c"
},
{
"code_lines": 466,
"path": "App/task/default_task.c"
},
{
"code_lines": 420,
"path": "App/app/ui_data_feed.c"
},
{
"code_lines": 369,
"path": "App/task/adc_task.c"
},
{
"code_lines": 353,
"path": "Drivers/BSP/UI/ui_w_setview.c"
@@ -832,10 +885,6 @@
"code_lines": 300,
"path": "Drivers/BSP/UI/ui_content_page.c"
},
{
"code_lines": 286,
"path": "App/task/default_task.c"
},
{
"code_lines": 265,
"path": "Drivers/BSP/UI/ui_w_editor.c"
@@ -845,12 +894,12 @@
"path": "Drivers/BSP/SD2506/sd2506.c"
},
{
"code_lines": 263,
"path": "App/task/adc_task.c"
"code_lines": 248,
"path": "Drivers/BSP/UI/ui_page_wave_play.c"
},
{
"code_lines": 253,
"path": "App/task/ui_task.c"
"code_lines": 230,
"path": "Drivers/BSP/UI/ui_data.h"
},
{
"code_lines": 218,
@@ -864,10 +913,6 @@
"code_lines": 206,
"path": "Drivers/BSP/CH395F/ch395f.h"
},
{
"code_lines": 206,
"path": "Drivers/BSP/UI/ui_data.h"
},
{
"code_lines": 205,
"path": "Drivers/BSP/UI/ui_page_net_cfg.c"
@@ -888,6 +933,10 @@
"code_lines": 152,
"path": "Drivers/BSP/UI/ui_page_runreport.c"
},
{
"code_lines": 150,
"path": "App/algo/wave_store.h"
},
{
"code_lines": 150,
"path": "Drivers/BSP/UI/ui_page_password.c"
@@ -901,7 +950,7 @@
"path": "App/app/app_main.c"
},
{
"code_lines": 134,
"code_lines": 142,
"path": "App/task/protect_task.c"
},
{
@@ -964,6 +1013,10 @@
"code_lines": 77,
"path": "Drivers/BSP/dbg_log.h"
},
{
"code_lines": 75,
"path": "App/algo/wave_ring.h"
},
{
"code_lines": 69,
"path": "Drivers/BSP/UI/ui_page_dc.c"
@@ -1056,6 +1109,10 @@
"code_lines": 40,
"path": "Drivers/BSP/UI/ui_page_deadband.c"
},
{
"code_lines": 38,
"path": "Drivers/BSP/UI/ui_page_wave_manual.c"
},
{
"code_lines": 36,
"path": "Drivers/BSP/ScreenLink/sb_proto.h"
@@ -1084,6 +1141,10 @@
"code_lines": 33,
"path": "Drivers/BSP/UI/ui_page_action.h"
},
{
"code_lines": 32,
"path": "App/algo/adc_cal.h"
},
{
"code_lines": 32,
"path": "App/util/boot_stats.h"
@@ -1092,10 +1153,6 @@
"code_lines": 32,
"path": "Drivers/BSP/RS485/rs485.h"
},
{
"code_lines": 31,
"path": "App/algo/adc_cal.h"
},
{
"code_lines": 31,
"path": "App/protocol/iec104/iec104_pts.h"
@@ -1376,6 +1433,14 @@
"code_lines": 11,
"path": "Drivers/BSP/UI/ui_page_view_word.h"
},
{
"code_lines": 11,
"path": "Drivers/BSP/UI/ui_page_wave_manual.h"
},
{
"code_lines": 11,
"path": "Drivers/BSP/UI/ui_page_wave_play.h"
},
{
"code_lines": 11,
"path": "Drivers/BSP/UI/ui_page_yx.h"