d64bbdc57f
数据面(App/algo,纯逻辑,双端编译) - wave_ring:8 路 × 320 点列优先环(1 kHz,预触发 160 + 后触发 160),adcTask 唯一写者;触发/冻结/封存/冷却四态,冻结持续到落盘回执才解冻,滞留 2 s 自弃 兜底——下一次真故障无波可录比丢一段更贵 - wave_store:段头编解码 + 拉模式打包游标 + 自带无表位运算 CRC-16/MODBUS(带 锚点自检)+ 段名与整段长度等式;格式不依赖平台类型宽度 - 段头只存原始码值与封存瞬间生效系数,工程量只当单位标签、不进任何算式 - 三套主机单测(环 113 / 编解码 170 / 触发状态机 110),全部无桩、生产源原样 纳入;新文件补 stddef 是 ARMCC 与主机差异,主机侧照不出这条分叉 - test/host/wave_read.py 是按 §6.2 的独立第二实现(dump/fft/shape/plot),92 条 自洽断言;三份合成段互读双校验全过、哈希钉死,格式面双向闭合 - 三套新单测不加专属钩子,由覆盖率总闸全量真跑(沿用既有裁定) 接线(任务层) - adc_cal:新增生效系数的 32 位定点原值入口(与既有浮点入口共用生效视图), 段头按最低有效位精确记账,不经浮点回算 - adcTask:每拍压 8 路语义原始码值并推进状态机,封存那一拍同拍交棒封存瞬间事实; 台架定周期自抓走双层编译门,产品镜像里零存在;串口新增一条 wave: 周期行 - defaultTask:卷空闲后一次心跳整段搬完(try 锁 + 256 字节分片 + 一次完整开档到 关档),成败都回执;失败先删半成品再计错,段号只在成功时推进;持锁超 50 ms 补一条告警并记历史峰值(喂狗余量可核) - Lead 复核补第四道并发陷阱:采集任务优先级高于落盘道,搬段中途它可能正好把滞留 超时的本段自弃、甚至封出下一段——数据区校验和是对「实际读到的字节」算的, 半新半旧的段照样自洽,故关档后复检环侧身份判废:删文件、不补账、段号不推进 - Lead 复核抓到触发挂号不是原子操作(旧实现分三个字节写,消费者可在窗口里读到 上一段的触发源与元件号):已把载荷压进一个字节,越界当场拒且不记任何计数; 段文件字节布局零改动,三份合成段哈希逐字节不变 - protectTask:保护启动上升沿同点请求录波,一拍一次、元件号取最低位;判据本体 零改动 人机(160×160 单色屏) - 菜单树节点 26「手动录波」绑页面 + 记录查询组末新增「录波回放」叶,重跑生成器 得 43 节点 / 34 叶 / 30 已绑,页面映射 28 → 30 - 回放页一屏一路、触发点前后各一周波共 40 点、每点 3 像素阶梯线(只用水平与 垂直两种线段——单色屏斜线会被阈值裁掉);零点虚线、触发光标、窗口峰值、 单位徽标与形状受限徽标;空态与坏段各一句显式文案,绝不用半截波形冒充数据 - ui_data 新增录波注入通道(六件操作表、三态返回);执行侧胶水带段头缓存、 手动请求后连缓存一起作废、逐点走全仓唯一的码值换算入口 - 模拟器接真实环与编解码合成两段(含坏段与空态旗标),6 张新黄金参考,既有 60 张逐字节零漂移未用更新模式;字库 218 → 224 字 / 319 字形 - 两份图形配置里图表组件仍为关;零堆分配;页面池水位不变 - 回放读路径的 uiTask 阻塞上界按实码写清:一次渲染 = 段表刷新 + 未缓存段头最坏 22 次小读;已验段只剩一次开窗读 + 40 点解码;无实测数不编,实测归台架、 仪器用已在跑的单轮工作耗时探针,不新加埋点 台账与文档 - 内存台账:录波环与落盘/回放静态逐条入册,三档对照 81,536 → 88,296 → 89,936 字节(62.2% → 68.6%),累计 +8,400;预估 5.9 KB 与实测 +6,760 的差额点名; 散列文件头注释同步;任务栈表核对后无需抬栈;体积趋势行与同码凭证由权威构建 重打(0 错误 0 警告,四项体积与上一轮相同——本轮改动只有注释与声明位置) - 设计说明:§5 补第四条并发陷阱;§6.3 定字段口径(两份独立实现的共同依据); §7 回填实测;§9 周期行写实;§10 台架判据改两段式且不比绝对相位;§12 补读路径 风险行;抬头状态改成「代码面已交付、未做完的只有板级那一轮」 - 卡片:软件闭环一栏列证据;台架三条按用户裁定保持未完成,不做虚假销项 - 口径同步:数据可信、UI 补齐、页面补齐规划、产品需求、采集短板评测、任务规划 索引与两份 README;陈旧现状句清扫 16 处(带日期戳的历史取数行一律不动) - 门禁说明:nested-comment 记仓库根探测必须兼容 linked worktree 的 gitdir 文件 形态(修前该钩子在任务树里恒报环境错、静默不可用);coding-standard 记 「函数头注释超过 24 行就把函数功能挤出回看窗口」这条机制与本次现场 - 覆盖率基线登记两个新覆盖模块(套件 41 → 44 套);环单测重打后该文件有效行 227 → 226、覆盖行 226 → 225,比率仍 99.6%,是分母变小不是覆盖率回退 为什么是单一提交:文档链接、双端注册、生成器幂等(菜单与字库)、内存数字与 体积事实源、编号门禁这五道整仓门禁要求代码、页面、菜单树、字库、文档与台账 同处一个提交才自洽,按数据面/接线/人机/台账拆成四笔必然红其中至少四道 编号门禁新增行 14 处命中已按语义改写:魔数常量按字符命名、段名样例改由格式串 生成、频谱表头改 f / 2x / 5x 并加一行图例;改写后自洽断言 92 条仍全过
124 lines
8.6 KiB
Markdown
124 lines
8.6 KiB
Markdown
# 块注释嵌套(nested-comment)— 注释体内不得再出现 /*
|
||
|
||
> 一句话:C 的块注释**不嵌套**。注释体内再出现一个 /* 时,ARMCC 报诊断 9-D
|
||
> 「nested comment is not allowed」。本仓的触发形态极其日常——**在注释里写作用域或通配路径**。
|
||
> 脚本 `scripts/check_nested_comment.py`(纯标准库、只读,2026-10-27 接线)。
|
||
|
||
## 1. 它在查什么
|
||
|
||
逐字节状态机走 代码 / 行注释 / 块注释 / 字符串 / 字符字面量 五个状态,
|
||
**只有在块注释体内**看到的 /* 才算问题,报「文件:行:列 + 上下文指纹 + 修法」。
|
||
|
||
| 判定 | 形态(本仓真实写法或自测用例) |
|
||
|---|---|
|
||
| **算** | 注释里写路径通配:`Drivers/BSP/UI/**`、`test/host/**`、`App/algo/*`(那串里的 /* 就是第二次注释的起点) |
|
||
| **算** | 块注释内部某行行首又开一个注释(复制粘贴手滑);块注释里用引号包住 /*;块注释里行注释符之后再来 /* |
|
||
| **不算** | 字符串字面量里的 /*(`const char *s = "/* 不是注释 */";`) |
|
||
| **不算** | 行注释里写 /*(编译器不报,本闸也不报) |
|
||
| **不算** | 本仓既有的尖括号写法 `<Drivers/BSP/UI/ui_w_soe.c>`(**推荐改法**) |
|
||
|
||
## 2. 为什么要它
|
||
|
||
- **只在重编译那个 TU 时才暴露**:改了某个头里的注释,只有编到它的包含者才看得见;
|
||
历史「0 错误 0 警告」不代表现在这份是干净的(与 `bom-guard` 完全同形的坑)。
|
||
- **按包含者数量刷屏**:一处嵌套写在被广泛 include 的头里,每个包含者各打一行。
|
||
本仓实测一例扩散到 **16 条警告**,把同批 10 条**真**警告挤到看不见——
|
||
等于把「能不能看清报错」这件事本身弄坏。
|
||
- 本闸**不需要构建**:提交时就报,不必等 @build,也不必去猜是谁的编译单元。
|
||
|
||
## 2.1 接线当日实测(都可复现)
|
||
|
||
| 测项 | 结果 |
|
||
|---|---|
|
||
| 全仓 `--all` 实扫 | **403 个 .c/.h:新发 0、存量 2 处**(都进基线,见 §7),退出码 0 |
|
||
| 形态电池(10 项,逐条对齐期望命中数) | **10/10**:5 个真形态全照出,5 个不该报的全安静 |
|
||
| `--selftest` 四项 | **4/4**:正例照得出 / 反例不误报 / 基线吞得下 / 只减不增有牙 |
|
||
| **真字节回放(空基线)** | 把 §7 那两份假件头当「今天新提交」跑 → 两条 [NEW]、退出码 **1** |
|
||
| 同一批真字节 + 已登记基线 | 两条 [BASE]、退出码 **0**(基线只决定「算不算新的」,不决定「有没有」) |
|
||
| 形态对照(重建当日那一处) | 尖括号写法 → 0 命中;同一段退回星号形态 → **1 命中,列 29** |
|
||
| 已提交历史回放 | 近 150 个提交里被改过的 .c/.h 共 **281 份旧字节:0 命中** ⇒ 这类问题此前从没被机器拦过,全靠人工在编译后清 |
|
||
|
||
> 编译器侧原文(**冻结引用**)——2026-10-27 02:22 那次 @build 的构建日志:
|
||
>
|
||
> ```
|
||
> ..\App\algo\run_par.c(267): warning: #9-D: nested comment is not allowed
|
||
> ```
|
||
>
|
||
> ⚠ 该日志每次 @build 都被覆盖、且不入库(02:37 已被下一次构建清掉,我写完这段再去查就没了),
|
||
> 所以把原文抄在这里存档;当日那三处同类**没有一处在已提交历史里留下字节**(上表最后一行),
|
||
> 本闸真正第一次拦住,会是「下一次有人在注释里写星号形态」。
|
||
|
||
## 3. 触发面
|
||
|
||
钩子用 `types: [c]`(即 .c/.h),第三方与生成物由配置顶层 exclude 挡掉。
|
||
脚本的 `--all` 与钩子喂进来的文件集**刻意同口径**(2026-10-27 实测 403 个文件)——
|
||
手跑面与提交面不一致,就会变成「两个数」,本仓已经为这种事返工过好几轮。
|
||
纯文档(.md)或纯 Python 的提交不会命中本闸——`types: [c]` 只喂 .c/.h 两类文件,想确认全仓干净就手跑本节的自查命令。
|
||
|
||
单独自查:`& .venv\Scripts\python.exe scripts/check_nested_comment.py --all`
|
||
|
||
## 4. 报错怎么读
|
||
|
||
```
|
||
[NEW ] App/x/y.c:45:17 块注释体内出现 /*(出现 1 次同形)
|
||
上下文:件才能测。 * * ⚠ 仅供 test/host/** 使用,不参与 MCU 构建。 * * 为
|
||
修法:注释里别写 /**(C 块注释不嵌套)——路径写全目录就好(Drivers/BSP/UI/),
|
||
或按本仓既有做法用尖括号包住(<Drivers/BSP/UI/ui_x.c>)
|
||
```
|
||
|
||
- `[NEW ]` = 基线之外的新命中 → **拦提交**(退出码 1)。
|
||
- `[BASE]`(要加 `--verbose` 才逐条打印)= 存量在册,不拦(见 §7)。
|
||
- `[TIGHTEN]` = 某条基线本轮实测已还清,该删了。
|
||
- 退出码:0 通过或只剩存量;1 有新命中;2 用法或环境错误。
|
||
|
||
## 5. 好处
|
||
|
||
- 秒级、**零第三方依赖**(只用标准库)。这点是刻意的:`generated-fresh` 那天栽在
|
||
「提交环境里裸 python 不是 .venv、装不到 fontTools」,本闸不碰第三方库,任何解释器
|
||
都跑得动——不会再造一根依赖某台机器环境的闸。
|
||
- 把「注释里写路径」这种看起来人畜无害的写法变成机器可判,而不是靠 reviewer 眼力。
|
||
|
||
## 6. 限制与盲区
|
||
|
||
1. **只管「块注释体内出现 /*」这一件事**。不判注释是否闭合(未闭合是编译错误,编译器自己
|
||
会拦,不需要一根只读闸替它操心);不判行注释里的 /*(编译器也不报)。
|
||
2. 不做预处理:若把 /* 藏进宏展开里(本仓没有这种写法),本闸照不到。
|
||
3. 基线指纹按**内容**不按行号——存量那几行改了行号仍算在册;反过来,同一文件里换一个新
|
||
形态会算新发(这条有专门的自测项)。
|
||
4. 只覆盖 .c/.h。Python 生成器模板将来若写出 /**,本闸照得到**产物**(产物是 .c/.h),
|
||
但不会指出模板——那段链由 `generated-fresh` 保证「脚本与产物同一笔提交」。
|
||
5. 编译器侧的真实警告仍以 `@build` 为准:本闸只拦「会让 ARMCC 报 9-D 的那一类」,
|
||
编译日志里其他诊断一概不管。
|
||
6. **仓库根探测必须兼容 linked worktree**:脚本原先用「`.git` 是不是目录」定位仓库根,而 `git worktree`
|
||
出来的任务工作树里 `.git` 是**一个文件**(写着 `gitdir: …`)不是目录 → 本闸在任何任务树里恒
|
||
退出码 2「仓库根定位失败」,**静默不可用**。这不是「放过了真问题」,是**根本没跑**——比放过更坏,
|
||
因为调用方看到红字会以为环境有问题、看到跳过会以为干净。2026-10-29 已把该判据从 `isdir` 改成
|
||
`exists`(`scripts/check_nested_comment.py:342`,修复归当日提交)。全仓 `scripts/` 只有它这么探根,
|
||
其余只读闸在任务树里一直正常。**后果要说清楚**:门禁修好之前那批录波改动没被它扫过,lead 手工对
|
||
改动面逐文件扫了一遍、嵌套命中 0,所以没有放过真问题——但那是**人工兜底,不是门禁功劳**。
|
||
通用教训:**门禁脚本按 `isdir(.git)` 探根 = 在 worktree 里自杀**;新增只读闸要么走
|
||
`git rev-parse --show-toplevel`,要么同时接受 `.git` 的文件形态。
|
||
|
||
## 7. 豁免与基线(只减不增)
|
||
|
||
接线当日全仓 `--all` 实扫 **403 个 .c/.h:新发 0、存量 2 处**,都在主机侧假件头里:
|
||
|
||
| 文件:行 | 形态 | 为什么今天不报 | 还法 |
|
||
|---|---|---|---|
|
||
| `test/host/common/ch395f_fake.h:7` | 注释里写作用域 `test/host/**` | 该假件不参与 MCU 构建(换 GCC/clang 的 -Wcomment 就会报) | 改成 test/host 目录 这类语义短语 |
|
||
| `test/host/common/fatfs_fake.h:9` | 同上形态 | 同上 | 同上 |
|
||
|
||
两处都属 `test/` 写域,接线时不由本道代改,按既有范式钉进脚本内 `BASELINE`,
|
||
**除这两处外零豁免**。一旦有人把这两份假件 include 进板端编译单元,就会按包含者数量刷出
|
||
9-D——这正是基线要显式挂着的原因:**不是「没问题」,是「已知待还」**。
|
||
还清一条就删那一行(`--prune` 打台账并点名已还清的)。
|
||
|
||
## 8. 改这套门禁本身
|
||
|
||
- 加判定形态必须同时加**正例与反例**:`--selftest` 四项(正例照得出 / 反例不误报 /
|
||
基线吞得下 / 只减不增有牙)之外,另有 10 项形态电池逐条对齐期望命中数。
|
||
- ⚠ **配置文件注释里不要复述声明行的字面量**:接线当天我在 `.pre-commit-config.yaml` 的
|
||
注释里写了一遍那个 grep 模式,文本 grep 的计数当场虚高 1(口径与自查命令见
|
||
`docs/门禁说明/README.md` §2 首条)。数数交给 YAML 解析,注释只描述。
|
||
- 加/删一条钩子要同批改三处:AGENTS.md 的钩子数、本目录 §2 标题、配置声明,外加索引行。
|