Commit Graph

32 Commits

Author SHA1 Message Date
super_agent_bot ad7338365c feat(sntp): 板端 SNTP 校时接入——coreSNTP 序列化器 + [sntp] 段 + 设置页(#73)
CI / 静态门禁 (pre-commit) (push) Failing after 6m14s
CI / 主机侧单测 (MSVC) (push) Successful in 54s
CI / 静态门禁 (pre-commit) (pull_request) Failing after 4m35s
CI / 主机侧单测 (MSVC) (pull_request) Successful in 47s
- vendored coreSNTP v2.0.0 序列化器(MIT,仅 serializer+LICENSE,零堆),
  48 字节报文编解码在库,节奏与准入判据在本方(RFC 4330 §10 调研口径)
- App/sync/time_sntp.c 挂 timeSyncTask 的 8888 事件循环,等待切片 ≤50 ms,
  不饿任务狗与 IWDG;懒建 UDP socket,代际变化/禁用/死错误码即关闭归还
- 防伪 = OriginTimestamp 逐位等于发出时 T1(含低 16 位随机小数位);
  mode/stratum/闰秒指示/KoD 按 RFC 拒收;DENY·RSTR 换服务器、RATE 只退避
- 主备轮换 + 失败指数退避(5 s 起、60 s 封顶)+ 首轮 1~5 分钟随机错峰;
  成功恢复 poll_min 周期(1~1440 分,出厂默认 60,默认不启用不发包)
- 钟面 = 本地时间:UTC+8 固定偏移落 sys_clock_set_unix(§1.1 时基裁定,
  第三个写入口,装置仍不存时区);|offset|<2 s 只记日志不步进,冷启动或
  更大偏差步进并回写 SD2506,留痕 [SNTP] step 与 syslog OPER
- 首个校验通过的同步置 SYS_EVT_TIMESYNC_READY(就绪位,消费方按需 NoClear)
- [sntp] 配置段(enable/server1/server2/poll_min)属主 sntp_cfg.c,
  注册在 net_cfg_load();UI 页 31「SNTP 设置」(密码叶):启用开关 +
  主/备服务器 octet 编辑 + 周期(分) + 保存,复用 net_cfg_save_request 链
- 测试与门禁:test/host/sntp 新套件(报文/防伪/KoD/退避周期/阶跃域/配置
  注册表)、net_cfg 与 time_sync 套件补 fake、黄金参考 66→74 张零漂移、
  字符集 228 字、Keil 0 错 0 警(RO +5,848 B 含字体)、覆盖率基线回填
- 文档:墙钟维护说明 §16、网络配置说明 [sntp] 节、配置文件设计说明变更记录、
  产品需求 FR-TIME-3 与 8.3/9.1.2 台账、UI 补齐规划/UI补齐 31 叶口径、
  登记簿销项并登记「SNTP 校时真机判据」等台架(PC 时间源 192.168.31.161/.13)
2026-11-04 16:20:22 +08:00
wandering1 e4d70f9fcb docs(真值): 勘查 13 条文档/代码不一致全部处置(10 改 3 核实)+ 补 3 处
证据源 = 主树 ci-artifacts/archify/architecture-dtu-overview-20261030-095132/
evidence.md §11。该目录不入库,故把每条的判据与实测源抄进正文,别让证据只活在
一台机器上。处置口径:能改的改成与代码同源,核实后确认文档没问题的明确写「不改」。

判停点与就绪屏障(条 1、条 3)
- AGENTS 原写 `protect_task.c:98` 直接停走判据:`:98` 是 `s_prev_cal_lock` 变量,
  判停点是 `App/task/protect_task.c:268 if (adc_cal_prot_blocked() != 0u)`,
  判定本体在标定层 `adc_cal_prot_blocked()`、protectTask 只是消费者 → 改引用,
  同步 `ui_task.c:240` 页面注释与 `docs/任务规划/数据可信.md` 的同一处行号。
- `SYS_EVT_FTP_READY` 有生产者(`Src/freertos.c:490`,注释自陈预留)无消费者;
  `SYS_EVT_TIMESYNC_READY` 全仓无生产者也无消费者(只有定义与测试桩)。
  AGENTS、`sys_events.h` 位注释、屏障配图(生成器 + 产物)三处从「四个就绪位
  并列」改成「bit0/bit1 在用 + bit2/bit3 预留」,并指向
  `docs/架构设计/项目启动顺序管理.md` §3.2 的逐位对照表。ftpTask 实际等的是
  `NET|STORAGE`(`Src/freertos.c:477-479`,WaitAll|NoClear,100 ms 分片喂狗)。

/log 不是「三本」(条 5)
- `App/log/sys_log_mcu.c` 的 `s_paths[]` = run / selftest / accid / alarm /
  start / oper / yk 七本 64B 定长文本 + `soe.log`(64B 定长二进制)+ `wdev.log`
  (变长取证行,`App/fs/vol_lock` 侧投,不走定长格式)。
  → AGENTS 两处、总览 §2.1 与 §4 的「三本」改成「七本 + SOE(+ wdev 取证行)」。

主机单测 44 套 → 47 套(条 2,两把机器尺互证)
- `scripts/check_test_coverage.py --list` 打印 47 行;`ls -d test/host/*/` = 48 个
  一级目录,唯一没有 `run_unit_test.py` 的是 `common/` ⇒ 47 套。
- 差额三名 = 屏板链路套件:`sb_proto`、`sb_link`(2026-10-29 入库)、
  `sb_led_map`(2026-10-30 入库)。专属钩子仍是 22 根 ⇒ 无专属钩子的从 22 套变 25 套。
- 同步面:AGENTS、`docs/门禁说明/README.md`、`host-unit-tests.md` §6 台账(名单补
  三名)、`docs/代码规范/pre-commit使用说明.md`、`主机单测覆盖率口径.md`(含耗时句)、
  `scripts/README.md`、总览目录树、`.pre-commit-config.yaml` 三处注释、
  `test/host/sys_log_mcu/sys_log_mcu_test.c` 一处注释。
- 带日期戳的历史测量值按纪律冻结不动:28 套、41 套 ~105 s、40 套/18 套那三处。

本仓 LVGL 版本(条 6)
- vendored 版本 = `Lib/lvgl/lv_version.h:9-11` 的 9.3.0;总览两处「LVGL v9.2」与
  `gen_arch_svg.py` 图内文字改 v9.3 并重跑产物(脚本与产物同一笔,`generated-fresh`
  逐字节核)。
- **刻意不动**:`docs/内存管理/RAM使用分析与优化方案.md` 两处「LVGL v9.2 文档」+
  GitHub `release/v9.2` 分支 URL ——那是对外游某分支文档的引用,不是本仓版本声明。

触发口径与栈值(条 4、7、9、10)
- ADC 映射 §1「ADC1 为软件触发」是旧口径:`Src/adc.c:53` 实为
  `ADC_EXTERNALTRIGCONV_T3_TRGO` → 改成 TIM3 TRGO,并补一句「TIM3 与 TPAFE 的
  CONVST 之间没有硬件耦合,仍不构成共同采样触发」,缺陷结论本身不变。
- 同文档 adcTask 栈 512 → 640 words(`Src/freertos.c:159 .stack_size = 640 * 4`)。
- `docs/UI设计/UI_设计架构.md` 的 uiTask 栈「16384 words」是单位错:
  实为 4096 words = 16384 B(`Src/freertos.c:218`),顺手补上行号。
- `App/app/app_main.c:197` 注释「DE = PD0」陈旧:`:198` 实传 `ST_DIR4_*`
  (V0.1 实板 PA15,V0.0 才是 PD0)→ 注释改指 V0.1 网表报告的引脚迁移表。
- 两处已退役编号 `N-18`(ADC 映射、V0.1 网表报告)换成登记簿条目名
  「双转换器无共同采样触发」。

核实后确认「文档没问题」的三条(条 8、12、13)
- 黄金参考「菜单 8 状态 + 内容页 66 张」:`simulator/tests/ref/` 实测 66 个
  `shot_*.bin`,与 `ui-golden` 钩子显示名一致 → 不改。
- `App/task/rs485_task.c` 存在但 `Src/freertos.c` 不创建它(grep 无 rs485):
  AGENTS 与总览都已写明「尚未接线 / 暂缓」,图侧画成「实现待接线」→ 不改。
- 104 端口 `:2404` 是工厂默认、可经 `/config.ini` `[comm]` 改 → 总览索引表补
  「默认」二字;「uiTask 10 ms 节拍」核实 = `ui_tokens.h:65 UI_TASK_TICK_MS 10` ✓。

并行勘查会话的同族发现(它扫「文档声明数 vs 真值」,逐处独立复验后采纳 3 处)
- `App/protocol/iec104/iec104_link.h` 头注释写「端口:TCP 2404(§1.5 B0 定义)」,
  同文件下方已写「服务端口真源已迁 [comm] 段」= 自相矛盾 → 补「工厂默认」并指回
  [comm] 与「下次重 bind 即生效」。
- `scripts/gen_task_table.py` 的 iec104Task 描述「:2404 监听」→「工厂默认 :2404
  监听」,`--write` 重生成 README 任务表(AGENTS 表无描述列,实测未被改写)。
- `App/log/README.md` 五行写入点行号全漂:事故 181→188、告警 184→191、启动
  176→183(`App/task/protect_task.c`);操作 `iec104_pts.c` 574/602→582/610、
  `default_task.c` 242→266、`sys_log_mcu.c` 646→682;遥控 573/576/582/586/596/
  598/609 → 581/584/590/594/604/606/617(宿主 `sim_syslog.c:245` 原值正确、未动)。
- **撤销一条**:我早先记的「`docs/算法/继电保护功能复现规划.md:225` 声称记录本已
  有消费者」与原文不符——:225 实为规划表里「动作/SOE 记录 | 复用 `sys_log`」一行,
  属能力复用口径、不是当前态断言 → 不改。教训:**改引用前逐处读现文,别照自己
  上一轮的笔记盲替**(这条比改中的每一处都值钱)。
- 同一批勘查还报了约 12 处「`2404` 缺『工厂默认』限定词」(AGENTS、`App/protocol/
  README.md`、`Src/freertos.c` 注释、5 篇 docs、`test/host` 工具,含一张配图生成器
  要连产物同批重跑)与 `测试开发标准流程.md`「像素层 60 内容页」、
  `.pre-commit-config.yaml` uinav 注释「快检档 18 张黄金参考」(后者写时为真、
  描述的却是钩子现有行为):**本笔刻意不做**,另开任务空间处理——那批要同时动
  AGENTS.md 与 `.pre-commit-config.yaml` 两处单写者面,与并行会话撞车的代价更高。
- 端口生效语义(用户裁定 2026-10-30):产品基线写「公共地址与端口可配…改后需重启
  生效」,代码 `App/task/iec104_serv.c` 是「ca 改后要重启;port 下次重 bind 才生效」
  ——裁定**按代码语义要改**处理(改了端口应立刻重 bind),属固件行为变更,另开任务
  且需真机验证;`.serialtest/config.json` 写死 `i104: listening on 2404` 必检锚点
  是同题(现场改端口会让串口回归假失败),一并留给那条任务。

自查(任务树内)
- `check_doc_links.py --sections-strict`:12 个改动 .md 逐个 rc=0;
  `check_mermaid.py` 改动 .md 全 rc=0;`check_generated_fresh.py` PASS
  (25 个生成器 / 21 一致 / 4 存量基线);`check_nested_comment.py --all` PASS
  (449 文件,新发 0、存量 2);`check_bom_drift.py --all` 99 个名单文件无漂移。
- 编译:`.dsh/skills/keil-build` 退出码 0(0 错误 0 警告),
  Program Size Code=246720 RO=29836 RW=2052 ZI=149708 —— 与本树凭证同码,
  证明这批改的确实只有注释与文档。
- 字节体检:23 个文件无 CR / U+FFFD / 行尾空格 / 缺末行换行;`ui_task.c` 被编辑后
  丢的 3 字节 BOM 已补回(bom-guard 复验通过);5 处「三连空行」逐文件与
  HEAD 比对确认是存量(Python 生成器的 PEP8 双空行与个别 C 文件原有空行)。
- 一次性工具 `ci-artifacts/fix_docs2.py`:断言式规则表,按文件读一次、在演化文本上
  逐条替换、一次写盘。第一版写成「每条规则各自从启动时快照起算」,同一文件后一条
  把前一条整体覆盖,只有每文件最后一条活下来——靠「改完再全仓复扫旧形态」当场抓到,
  这条判据本身已值得写进流程。
- 待办:`git add` 后需重跑 `ram_baseline.py --update`(体积凭证按 git 索引内容生成,
  未 staged 的文件不在凭证里,`check_size_gate.py --local` 现在因此报红)。
- 未 commit、未 push(AGENTS.md 边界:提交属 Ask first)。
2026-10-30 14:19:35 +08:00
wandering1 f8e62a9ba2 feat(门禁): 新增 mermaid-syntax 钩子,围栏内确定性语法提交前必拦
- scripts/check_mermaid.py(纯标准库):R0 围栏未闭合 / R1 图类型头缺
  错 / R2 -. 后直接跟管道(确定性语法错误形态)/ R3 subgraph 与
  sequence 块的 end 计数配对;--all / --selftest(5 形态)/ --prune;
  排除面与 doc-links 同口径;零语料空基线
- 接线 .pre-commit-config.yaml(doc-links 后),docs/门禁说明/
  mermaid-syntax.md 专篇(八段结构含限制与盲区),README 索引与
  AGENTS.md 计数 51→52、提交期实跑 48→49
- 门禁说明 README 顺带修正两处历史矛盾:gitlint 实际就在本配置
  (commit-msg 阶段),旧文「52−3−gitlint」与「gitlint 不在配置里」
  均过时——锚定口径 52 = 47 pre-commit + 3 manual + 1 commit-msg,
  加钩后 48 + 1 = 49;三处 grep 争执例句改抽象表述(例句里的数字
  自己会过时)
- docs/子系统设计/屏板链路设计说明.md:38 修复触发本钩子的坏图:
  -. 后直接跟管道不是合法边 operator,改为 -.->|label| 形态

实测:YAML 解析 52 / commit 阶段枚举 48 行全 Passed(含新钩子)/
check_mermaid --all 29 文件 60 块围栏 0 命中 rc=0 /
check_doc_links --all rc=0(215 文档)/ 六文件无 BOM/CR/U+FFFD。
2026-10-30 11:03:58 +08:00
wandering1 f754d59218 docs(测试说明): 按用途分六个子目录并同步全库引用
分层:流程与规范/ 单元测试/ 板级测试/ 专项验证/ 测试工具/ 测试数据/,
顶层只留新增的目录导航 README.md(归层判据 + 硬约束 + 本次处置记录)。

- 搬迁 28 个路径:测试数据三个目录 58 个文件为纯改名(R100,内容逐字节不变)
- 全库引用同步 124 个文件:AGENTS / docs 索引 / skills / 门禁注释 / scripts
- 门禁面:scripts/check_test_traceability.py 的 glob 改 rglob
  (分层后不递归扫描=追溯门禁直接瞎掉)
- scripts/rename_ref.py:收尾的 ℹ 提示在 GBK 代码页抛 UnicodeEncodeError,
  让进程以退出码 1 收场而改写其实已落盘(RC 与真实结果相反);改为把
  stdout/stderr reconfigure 成 UTF-8,与 check_doc_links.py 等同法
- docs/文档规范.md §1.1 补「子目录文件过多时再分一层」;§3.6 补 rename_ref
  搬整目录的两个实测坑:① 会改写目录内部文件的内容 ② 内部文件的 ../ 出链
  不补层级(本次 23 个被误改的证据文件已按 HEAD 原始字节逐字节还原)
- docs/README.md §6 改为与六个子目录一一对应,并补登原先漏登记的
  「启动日志原子性复验流程」一行
- .cubemx_survival_baseline.json:App/util/task_watchdog.c 的注释路径也随分层更新,
  该文件是存活审计的 watchdog-module 漂移锚点,按脚本自己的提示跑 --write 重建基线
  (实测重建后仅 watchdog-module 一条哈希变化)
- 铁律 4 例外(本次在任务树里改了单写者文件):AGENTS.md 与
  .pre-commit-config.yaml 只被 rename_ref 改写路径字面量(后者全在注释行),
  任务表块与钩子声明一字未动

验证:check_doc_links.py --sections-strict 覆盖全部 88 个改动 .md 全绿;
check_test_traceability.py 输出与主树逐行一致;196 个文本文件无 BOM、无新增
CR、无 U+FFFD、无行尾空白;陈旧引用面由主树 25 处降到 6 处(无新增断链)。
2026-10-30 07:16:07 +08:00
wandering1 51d89cf9d3 gate: 按用户裁定整体退役编号门禁 id-check-new(钩子 52 → 51)
配置:摘掉该钩子,原位置留一条退役注记(不复述数钩子数的字面量)。
YAML 解析口径实测:声明 51 / 带 manual 3 / 提交期实跑 48。

脚本:git mv 进 scripts/archive/id_gate/check_ids_new.py,与已退役的
check_ids.py 同档;docstring 改退役口径,REPO_ROOT 因归档位置深两级
改取 parents[3],失败提示与自述路径同步改写。从归档位置实测:
--self-test 5 正例拦下 / 29 反例放行 rc=0;--worktree 与暂存区模式 rc=0。

文档(七份):AGENTS.md 六处——总数、加钩流水(顺带补上 2026-10-29
漏记的 skill-size 一笔)、枚举项删除、本行相加数、提交期实跑、门禁索引
与主题表两行;门禁说明 README 八处——声明数、实跑数、计数流水、grep
陷阱的举例数、§2 标题、姿态表「只查新增」行、两行索引状态;编号规范
七处——引导块改「本文即唯一事实源」、族总表一处、§8 标题与正文、
§8.5 补第④步、④ 之后无机械牙那段、速查;门禁说明 id-check-new.md
整篇重写为退役留档(查什么 / 落地前的噪声回放 / 退役五条理由 / 手工
跑法 / 此后靠什么 / 认下丢了什么);门禁说明 id-check.md 与归档目录
README、check_ids.py 里「现行门禁 = id-check-new」的指针同步改写。

技能(三份):id-family-semantic-migration 一行、stale-doc-count-sweep
的 pitfalls 与 steps 各一行改手工跑法(steps 第 5 条那笔历史计数例不动)。

此后编号形态没有机器面:判据只剩 docs/编号规范.md §1 三句自问、§4.1
族总表与人工评审;2026-10-14 那类"销项删行后号被重新取走"不再有提交期
警报——这条代价已写进留档,别当成"检查没了随便写"。

纯文档与门禁配置,未跑 @build。全程未 push。
2026-10-29 20:22:47 +08:00
wandering1 557f1d042a docs(计数): 录波落地后的全仓计数同步(套数/钩子/黄金/菜单/字库)
机器面先定真值,再逐处对齐文档;带日期戳的取数行只加「当时」不改数。

六个数(每条两个以上独立机器源互证)
- 主机单测套数 41 → 44(find test/host -name run_unit_test.py / 覆盖率总闸 --list /
  基线 modules 条目三源一致;目录数 46 = 44 + common + __pycache__,两个数分开写)
- 有专属钩子 22 根(YAML 解析 -unit-test 后缀)⇒ 无专属钩子 19 → 22 套,并把
  wave_ring / wave_store / wave_trig 逐名列进门禁台账 §6 第 4 条,18 / 19 / 22 三个数
  改标「裁定当时 / 2026-10-28 / 2026-10-29 现值」
- 内容页黄金参考 60 → 66 张(simulator/tests/ref/shot_*.bin 实数 / PAGES 条目 66,
  其中 2 个分页 → 页面 64);钩子显示名与门禁索引表成对改
- 菜单 42 → 43 行(9 菜单 + 34 叶)、已绑 28 → 30、未绑 4(ui_menu_tab.h 宏 +
  g_menu_tab[] 末行 / ui_page_registry.h 的 UI_PAGE_MAP_COUNT + #page= 计数剔示例行)
- 中文字库 218 → 224 唯一字、313 → 319 字形(清单唯一码点 / .bitmap_index 条目数
  含 notdef;224 + 95 = 319 成立)
- 钩子口径 52 声明 / 49 提交期实跑:只核不改,核对 AGENTS 与 YAML 解析一致

Lead 追加四处(wave-algo 按「AGENTS 只核不改」的指令交回我裁的部分)
- AGENTS.md 提交门禁节:41 套 → 44 套(两处)、19 套 → 22 套(两处,并把「与录波
  三套」写进括注)、ui-golden 条目 60 张 → 66 张;52 / 49 的口径叙述与历史括号原样
- scripts/board_ui_nav.py 的自述 docstring:60 张 → 66 张
- test/host/sys_log_mcu/sys_log_mcu_test.c 注释:全量门禁 41 套 → 44 套(纯注释)
- 产品需求 FR-UI-2:需求原文「42 节点」保留不动,在实现行注「2026-10-29 实到 43
  节点,42 是 V0.1 立项数」——需求基线不由实现方回改

刻意不动的(冻结面)
- 带日期戳的实测行(自动化测试流程、字库差集门禁、覆盖率口径里的 67 s / 25 s /
  45 s / ~105 s 四个耗时)、保留变更记录的文档历史行、页面补齐规划里自写「完成即
  冻结」的立项快照表、2026-10-28 那份分工说明、级联框总览.svg(42 节点时代所画,
  无生成器,重画另开一笔)、三处伪命中(字体数据行、芯片手册、m2/m3 数据目录)

自查(真实退出码):check_doc_links.py --all RC=0(215 个文档、章节引用可判定 80 %,
合并后第一次全库零红);check_generated_fresh.py RC=0(22 张图 17 一致 / 5 条既有
BASELINE 豁免,生成物零改动);编号门禁 add 后复扫 RC=0;17 + 4 个改动文件字节体检
全绿(无 BOM / LF / 无 U+FFFD / 无尾随空白 / 单个尾换行)。
2026-10-29 20:04:24 +08:00
wandering1 15bcfc7c92 merge: task/wave-record 合入 v2-on-ui(故障录波数据面与单通道回放页)
冲突两处与处置
- docs/子系统设计/故障录波设计说明.md §5.2:上游把这张表交给格式化器重排,多出一列
  空列,并把「FA_WRITE 竖线 FA_OPEN_APPEND」里的竖线当成分隔符打断,标志位写法已损坏。
  取我方四条陷阱版(含实现期复核新增的第四条:搬段途中环被解冻甚至已换段 → 关档后
  复检环侧身份判废),并把标志位里的竖线转义(与 运行与自检记录设计说明.md 同一写法)。
  上游在表后新增的「取窗竞态的原因」配图不是本任务内容,原样保留未删。
- scripts/size_attestation.json:不手工拼接,改为合并后在主树重新构建再重盖凭证。

顺手修一处上一轮我引入的排版断行
- docs/任务规划/数据可信.md §4.6.5「跨转换器相位」那一行少一个分隔符,三列表渲染成
  两列;同时把引用从 §7 精确回 §7.1(链路分段)。合并面 68 个文档、46 张表逐张核对
  列数一致,命中 0。

合并态权威构建(主树,本次凭证的来源)
- 0 错误 0 警告;Code=243,552 / RO=28,784 / RW=1,972 / ZI=145,388;RW_IRAM1 89,936 B
  (68.6%)/ RW_CCM 57,376 B(87.9%)——与任务树逐项相同:上游自 merge-base 起对代码
  只改了 sample_ring 的注释与函数头,故台账数字无需重排,仅重盖同码凭证。
- 上游 14 个提交带来的门禁与技能改造(skill-size 钩子、五个技能正文外置)与本波正交,
  真重叠只有 docs/门禁说明/README.md 与 docs/测试说明/主机单测覆盖率口径.md 两处,
  按 hunk 距离自动并上,已逐项核对。

状态与后续
- 台架三条判据(注 1 V/50 Hz 对表、FTP 拉回比对、与 meas 及 104 同表读数)按用户裁定
  保持未完成,卡片不销项;本笔交付的是软件闭环。
- 全仓计数清扫(主机单测 41 → 44 套、无专属钩子 19 → 22 套、黄金 60 → 66 张、提交
  钩子数口径、两处钩子显示名)另开一笔,不与本笔混编。
- docs/任务规划/** 本应在主工作树改,本波由用户在任务树显式豁免、随本笔合回。
2026-10-29 19:32:26 +08:00
wandering1 d64bbdc57f feat(wave): 故障录波数据面、接线与单通道回放页(软件闭环交付)
数据面(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 条仍全过
2026-10-29 19:23:15 +08:00
wandering1 c63bd029a9 feat(门禁): 新增 skill-size 钩子——SKILL.md 不得超插件写侧上限 65536
dsh-mnemon 的 MAX_SKILL_BYTES = 65536 只在写侧校验,加载侧从不检查,
所以正文越界的技能照常加载、却永远生成不出草案:同日两次卡死
(83194 字节与 72601 字节)都是这个形态,复位台账无效,只能瘦身。
故把上限机械化,越界与悬空指针在提交期就拦下。

- scripts/check_skill_size.py:纯标准库(裸 python 也能跑,故不解析
  .venv);FAIL >65536、FAIL reference/ 指针悬空、FAIL UTF-8 BOM、
  WARN ≥49152(75%——实测一次「采纳」把主文从 49821 顶到 62806);
  总是全树扫,只拿 reference/x.md 触发的提交正是漏网场景;
  --root 可复指到用户级 ~/.dsh/skills;--selftest 五形态(干净 0 /
  临界 0+WARN / 超限 1 / 悬空+BOM 1 / 根不存在 2)全过
- .pre-commit-config.yaml 加 skill-size,files: ^\.dsh/skills/
- 新增 docs/门禁说明/skill-size.md,含盲区:拦不住插件自身的采纳写盘、
  用户级技能目录不在触发面、不解析 frontmatter、不查 U+FFFD
- 计数同步 51 -> 52(实跑 48 -> 49,索引 28 -> 29 篇):AGENTS.md 与
  门禁索引,另 7 处文档旧计数改写、CI 指南带日期实测行只加注

本笔先落地,技能正文的渐进展开拆分在下一笔。
2026-10-29 15:02:23 +08:00
wandering1 41670a1cc6 docs(gates): 主机单测套数复点同步——41 套 / 无专属钩子 19 套
第 41 套 boot_stats 由 728d6067(2026-10-27 11:29)入库,全仓写的
「40 套 / 18 套无专属钩子」从那天起过期;本轮按实测复点同步。

真值双源互证:test/host/*/run_unit_test.py 实数 41(43 个目录,除
common 与 __pycache__)= scripts/check_test_coverage.py 自报
suites=41/41。专属钩子 22 根(YAML 解析 id 以 -unit-test 结尾,
22 条全对得上有 runner 的目录)⇒ 无专属钩子 19 套 = 41 − 22。

改当前态共 18 处:AGENTS.md 提交门禁节三处、.pre-commit-config.yaml
test-coverage 注释、docs/门禁说明/host-unit-tests.md §6 第 4 条六处
(无钩子名单首位补 boot_stats、目录数 42→43、裁定句改「裁定当时
18 套,2026-10-28 现值 19 套」)、docs/门禁说明/README.md、
docs/代码规范/pre-commit使用说明.md 两处、docs/编号规范.md、
scripts/README.md、docs/任务规划/分工说明-20261028 一条、
docs/测试说明/主机单测覆盖率口径.md 追加 2026-10-28 = 41 套 ~105 s
新实测点、test/host/sys_log_mcu/sys_log_mcu_test.c 注释行。

刻意不动:带日期戳的历史耗时与套数行(只追加新的实测点,不覆写)、
host-unit-tests.md 里「22 根 / 40 套 / 18 套无专属钩子」这句复核原文
(只在后面追加更正)、scripts/archive/id_gate/ 留档两处、
同数不同义的五处(40KB 级 / −20~40% / 不到 40 行 / 18 断言点 /
板端 RTC 套件)。钩子数 51、专属 22 根、提交期实跑 48 根本轮实测
未变,相关句一字未动。

门禁:doc-links --all --sections-strict / id-check-new --worktree /
no-mojibake / bom-drift / validate-config 全 rc=0,
test/host/sys_log_mcu 单测 rc=0;改后复扫「40 套」仅剩 3 处
(1 处刻意保留 + 2 处留档)、「42 个目录」0 处、「18 套」仅剩 2 处
(都带「当时」口径)。
2026-10-29 00:58:23 +08:00
wandering1 295eb9911f ci(gates): 覆盖率总闸与全量 cppcheck 移到远端 CI 强制(提交期实跑 48 根)
用户裁定 2026-10-28:慢钩子不再压在每个 git commit 上,由远端
CI 强制;本地等价入口 = scripts/ci_local.py 的 manual 段。

实测三根耗时:cppcheck 20.5 s、test-cppcheck 38.1 s、
test-coverage 105.2 s,合计 ~165 s ≈ 一次带代码提交耗时的
三分之二(test-coverage 的 files: 覆盖 App/,改一行就跑光 40 套)。

- .pre-commit-config.yaml:cppcheck / test-cppcheck /
  test-coverage 加 stages: [manual] + 理由注释;替换掉
  test-coverage 上方「没写 stages → 所有阶段都跑、输出出现两次」
  的旧坑注释(固定 manual 后不再有这一坑)。
- .gitea/workflows/ci.yml:static-gates job 在静态门禁步之后
  新增「手动阶段门禁(覆盖率总闸 + 全量 cppcheck)」步,
  if: always(),逐根 --hook-stage manual(pre_commit run 不支持
  多 id),日志 ci-artifacts/manual-stage.log + 归档 + STEP_SUMMARY,
  rc≠0 即失败;run 块纯 ASCII。
- scripts/ci_local.py:新增 MANUAL_STAGE_HOOKS 与 run_manual_stage()
  (静态段之后默认跑),删 run_coverage() 死代码,--coverage
  降级为兼容别名。
- AGENTS.md + 12 篇 docs/scripts/README:三数同源口径改为
  声明 51 / 提交期 --all-files 实跑 47 / +gitlint = 48,
  其余 3 根在 manual 阶段;历史测量数字只加「当时」不回改。

验证:pre-commit run --all-files = 47 Passed / 0 Failed rc=0;
manual 三根 Passed(test-coverage line 89.8% func 93.2% 41/41 套);
ci_local.py --static-only 全绿;check_doc_links --all
--sections-strict rc=0、mojibake / bom-drift / id-check-new rc=0;
ci.yml yaml.safe_load 通过。未改任何 .c/.h,故未跑 @build。
2026-10-28 23:04:59 +08:00
wandering1 4ba02212eb docs(门禁): 钩子计数与门禁索引同步到实测口径(51 / 50+1 / 22 / 28 篇)
实测口径(三数同源):
- YAML 解析后的 hook 条目数 = 51(不是文本 grep 声明行)。
- gitlint 未声明 stages(实测 stages = None)→ 按默认属全阶段计,
  pre-commit 阶段 50 + commit-msg 阶段 gitlint 1 = 51。
- 带 -unit-test 后缀的专属钩子实测 22 根(AGENTS 的 Lead 裁定 2026-10-27:
  不补第 23 根)。
- docs/门禁说明/ 下除 README 外实测 28 篇(上一轮加钩子没同步篇数)。

逐处:AGENTS.md 补齐 2026-10-25 道E 三根钩子的逐项枚举(补齐后该行
各项相加才等于 51);docs/代码规范/pre-commit使用说明.md 两阶段表
49/50 → 50/51、§5 文件表 40 → 51 并注当日 51 → 52 → 51 净零;
docs/门禁说明/gitlint.md 的 --no-verify 跳过面 39 → 50(= 51 减自身);
docs/门禁说明/README.md 索引 27 → 28 篇、grep 自查口径改为锚定行首的
实测结果、硬拦截行 16 → 22 个主机单测;test/host/README.md 16 → 22 两处;
docs/环境与部署/并行任务工作树方案.md 30 / 40 → 51;
docs/测试说明/测试开发标准流程.md 那条 2026-10-11 审计的「18 个钩子」
加「当时」锁口径、不臆改成现值;两份 skill 正文里的 id-check 说法改为
「已于 2026-10-28 退役、现行只查新增行」。
2026-10-28 15:37:02 +08:00
wandering1 599f05be22 refactor(编号): 测试验证层级 L0/L0.5/L1/L2/L3 → 语义名(批次 3d·文档层)
这族是验证层级:静态门禁 / 主机侧纯逻辑单测 / 板端测试套件 / 主机侧回归 / 人工目检。
实测它出现在 **97 个文件**(40+ 个 test/host 的 run_unit_test.py、.gitea workflow、
ci_local.py 的阶段标签、以及十来篇文档)。本批只做**文档层**,代码层单列一批(见下)。

改动:10 篇文档 110 行 + 三处收尾——
  测试开发标准流程 / 实机测试实施指南 / 主机单测覆盖率口径 / 门禁说明 README 与
  host-unit-tests / CI README 与远程CI完整指南 / docs README / 测试与架构专项 /
  pre-commit 使用说明。
映射:L0 → 静态门禁、L0.5 → 主机侧纯逻辑单测、L1 → 板端测试套件、L2 → 主机侧回归、
L3 → 人工目检;`L0b`(ci_local 的内部阶段标签)在文档里写成「提交信息门禁」。
测试层级那张表的「层级」列被删掉(名称列已承载同一信息,留着就是两列重复)。

**未做(代码层,单列批次 3d-2)**:`scripts/ci_local.py` 的阶段标签、`.gitea` workflow、
`test/host/*/run_unit_test.py` 的输出前缀、以及代码头注释里的 L0/L0.5 —— 那些是**程序标识**,
改名要连带 CI 日志格式与文档里对 `[SUMMARY] L0: ...` 的引用,属跨端改动,需单独验证。

验证:三篇主文档的层号残留 = 0;doc-links 通过;mojibake / git diff --check 干净;
表格列数已收敛为 3 列(名称 / 载体 / 抓住什么)。
2026-10-28 13:20:28 +08:00
wandering1 1668842d61 chore(id-check): 退役全库编号语料审计(钩子 52 → 51)
第三步(用户裁定跳过观察期直接做)。第一步 bf2a5c21 把两根护栏转报告制,
第二步 a5832788 立起只查新增行的新门禁,本笔把旧的全库语料审计整体退役:
语义标识已是默认形态,这套 99 族语料不再有人需要维护。

移动(保留可复现性,不再进提交门禁):
- scripts/check_ids.py → scripts/archive/id_gate/check_ids.py
- id_registry.json(87.6 KB,99 族)/ id_aliases.json(187 KB)/ id_known_backlog.json
  一并归档;新写 archive README:为什么退役、现在用什么、怎么手工跑、归档纪律。
- 归档脚本改了自定位(仓库根往上 4 层、语料与脚本同目录)与一行退役横幅;
  从新路径实跑:811 文件 / 8,051 字面量,--strict rc=0。

钩子:删 id-check(52 → 51)。现役编号门禁只剩 id-check-new(只查新增行、零语料)。
声明数 51 = commit 阶段 50 + gitlint 1,三数已对齐(AGENTS / 门禁索引 / YAML)。

连带改动:
- rename_ids.py 的别名表路径指向归档(改名工具本身没退役);
- check_ids_new.py 排除面加 scripts/archive/(语料里全是编号字面量,天经地义);
- doc-links 跳过 .mnemon/ 与 ci-artifacts/(本地记忆状态与草稿,非项目文档)——
  语料搬家后这些目录里的旧路径引用会假红,它们本来就不该参与文档门禁;
- 全库 .md 里的旧路径引用改指 scripts/archive/id_gate/(含两份 skill 手册);
- id-check.md 加退役横幅并保留原文作留档;门禁索引把该行标成已退役;
- 编号规范 §8 改成「现行只有一道门禁」+ §8.1~§8.4 标为退役留档 + §8.5 ③ 置已完成;
  各加一条 2026-10-28 变更记录行。

验证(实测):YAML 口径 51 个钩子、id-check 不在其中;doc-links --all --sections-strict
通过(194 文档);mojibake / bom-guard / coding-standard / git diff --check 全 rc=0;
新门禁自检 5 正例 + 29 反例仍全过。
2026-10-28 12:38:38 +08:00
wandering1 a5832788e9 feat(id-check): 编号门禁第二步——新增行拦截(零语料)
背景:第一步(bf2a5c21)把两根护栏转成报告制,但全库语料审计仍在跑。
它真正的用途只有一个——拦住「新写一个自造编号」;这件事不需要 99 族语料。
所以本笔落第二步:只查 git diff 的新增行,判据收窄成两张前缀表。

新增 scripts/check_ids_new.py(241 行,零语料):
- 破折形态:首段不在 KNOWN_DASH(活族 + 标准名,11 条)→ FAIL;
  在 RETIRED_DASH(已停发族)→ 只 WARN,提示改语义短语。
- 裸形态:前缀不在 KNOWN_BARE(外设/器件/协议/点号,约 90 条)→ FAIL。
- 单字母 + 数字一律放行(元件位号与层次号同形,显式盲区)。
- 算术排除(SIZE-2 / LEN-1 这类是减法不是编号);跳过 [示例]/[计划] 行;
  行内 [编号豁免] 为最后手段。默认查暂存区,另有 --worktree / --range / --self-test。

接线:新钩子 id-check-new(钩子数 51 → 52,AGENTS 与门禁索引已同批改),
与 id-check 双跑一个观察期;观察期后按 docs/编号规范.md §8.5 ③ 退役旧语料。
旧门禁的排除面加上新脚本(它必然写着示例令牌,否则自己拦自己)。

白名单是按真实数据调出来的,不是拍脑袋:回放最近 80 笔提交,未知形态只有 15 种,
其中 12 种是设备/协议名(RS232、RS485、OVER8、YT/YH 点号等,已进白名单)、
3 种是已停发族(P-8、N-1、F-NET-*,只 WARN)→ 调好后回放误报 0。

自证(实测):
- 自检 5 正例全部拦下、29 反例全部放行(含 TC-NET-204 / TRAP-ADC-01 / TPAFE5160 /
  GD5F2GQ5UE / C12 / U15 / L3 / SIZE-2 / GPIO_PIN_5)。
- 端到端:暂存一个自造前缀 + 数字 → 钩子 FAIL;清理后 Passed。
- 反向:本页文档里举的反例自己也被拦过一次,改成带 [示例] 标记后才过——
  这条正好证明它没有「文档路径」的例外面。
- 两条门禁互不干扰:old-gate rc=0、new-gate rc=0、doc-links 通过(211 文档)。
2026-10-28 12:27:57 +08:00
wandering1 94b0d79026 feat(ui)+chore(docs): UI 补齐清单清空;数据可信销项与「卡」号清退
本笔含两组收尾工作(同一工作区内交错在 6 个共享文档/门禁配置里,
拆开会产生"文档声称的页数与树里黄金数不一致"的中间提交,故合为一笔):

一、UI 补齐(清单清空)
- 新建 6 个内容页模块:ui_page_accident / oper / alarm / start / yk
  复用 ui_w_records 共享组件(分页、空态"无记录"、按实例读盘缓存),
  记录层与五个写入点已由道F task-10 / 道G task-12 落地,本批只补页面;
  ui_page_runreport 为 13 行 2 页只读统计,四个数逐个挂范围标签
  (自电池周期 / 本次开机),boot_ready=0 显 "--" 不显 0。
- 数据面:ui_data_info_t 尾部追加 9 字段,ui_data_feed 用
  boot_stats_get() + iec104_serv_get_stats() 纯搬运;模拟器填确定值假数据
  (差异登记 docs/测试说明/模拟器差距清单.md §2.3 两行)。
- 接线:菜单树 6 叶绑 #page=,绑定叶 22→28、UI_PAGE_MAP_COUNT=28;
  字库 185→218 字 / 280→313 字形;双端注册 uvprojx +30、CMakeLists +6。
- 回归:内容页黄金 53→60(含 runreport_p2 真拍第 2 页),文本断言
  425 正向 / 36 反向;存量 53 张逐字节零漂移;记录 5 页各用独立空目录
  (模拟器把操作留痕写进 cwd 的 sim_oper.log,共用 tmp 会让空态拍不到)。

二、数据可信销项 + 「数据可信」任务卡号整族清退
- 删除已闭环的"已知电压注入验证"行与闭环结论块(证据在
  docs/硬件平台/ADC通道映射说明.md §8.1 与
  docs/测试说明/ADC前端注入验证流程.md §5~§7),§5 标识列改语义短语。
- 卡 0/0b/1~12 共 14 个号全仓 288 站点 / 56 文件清退成语义短语,
  代码注释、测试、门禁配置与文档一并改;换算表入 docs/编号规范.md §9.3。
  这一族是中文前缀,不进 check_ids 语料,刻意不入 id_aliases.json。

验证(实测)
- @build 0 错 0 警:Code=236456 RO=28124 RW=1876 ZI=137084;
  RAM +464 B(RW +304 / ZI +160),RW_IRAM1 62.2% / RW_CCM 87.9%,
  体积同码凭证与 RAM 台账已回填。
- check_menu_rows 8 状态 rc=0(池 5368/5448 常量未动);
  check_content_pages 60 页 rc=0;check_font_charset / registration /
  coding-standard / bom-drift / mojibake / doc-links --all / layer-deps /
  nested-comment 全 rc=0;check_ids --strict 无错误;主机单测
  ui_data 295 / boot_stats 21 / sys_log_mcu 141 / soe 32 / soe_store 27。

未做(不是遗漏)
- 六页真机判据(真记录翻页、掉电保持、清除后归零、boot_count 自增、
  拔 RTC 电池落 RESTARTED、IWDG 复位落 rst_cause、主站连一次 conn_up+1)
  已登记 docs/任务规划/登记簿.md §7;模拟器结构上照不到。
- docs/产品需求/产品需求设计文档.md 属另一条在飞改动,本笔不含;
  其中我已同步 6 处现状数字(28 叶 / 60 页 / 218 字),随该笔入库。
2026-10-28 07:23:16 +08:00
wandering1 a275539c17 docs(全仓): 内容页黄金 47 → 53 的当前态同步——含钩子显示名,登记簿口径另笔
task-9 让内容页黄金从 47 涨到 53(通讯设置页六态),本笔只做**当前态陈述**的同步;真值全部本轮实测:
`simulator/tests/ref/*.bin` = **53**;`git diff 31ca4a1f..HEAD` 对该目录 = **
6 个新增、零修改** ⇒ 存量 47 张
逐字节未变(这条是关键:新增页不该让旧页重生成,否则回归基线就失去意义)。

**四类命中各走各路,这是本笔的全部难点**(分类比替换重要得多):
· 当前态 → 改,25 处页数,落在 16 只文件(AGENTS、钩子显示名、导航器 docstring、`lvgl-simulator` s
kill、
  门禁索引与 `ui-golden` 详解、UI 自动化流程、内容页架构、页面补齐规划与扩充方案、数据供给、自动化测
  试流程、覆盖率口径、测试开发标准流程、模拟器两份 README);
· 变更记录历史行 → **一条不动**,另在其下一行插入当日「47 → 53」新行 6 条(含判据与零漂移证据);
· **同数不同义 → 不动**:覆盖率口径里的「47 个 .c」「47 = 13+5+29」、ram_report 的表行号 47、`#47-D`
  诊断号、LSI 47kHz、47,360 栈字数、像素哈希 3476/3474 —— 一并替换就会毁掉六个不相干的事实;
· 带日期戳 / 自declare 冻结的快照 → 不臆改(数据供给篇那句上一笔已加「当时」,页面补齐规划里那张
  「2026-10-25 复核…剩 21 叶」的表自带「完成即冻结不回改」声明)。

复扫残留当前态 47 = **0**。⚠ 顺手纠一条**会教错方法**的陈旧:naive 计数 `grep -c '#page='` 上一笔写的是
22,现在真值是 **23**(文件头示例行也算一次)——旧文档里那个 22 **恰好等于新的正确 bound 数**,不改的话,
下一个人用错算法还能碰巧对上,比错更糟。

⚠ `AGENTS.md` 里本次有两件事同行相邻(本笔的内容页 53 页 + 批次三那句 `TC-*` 停发),**分两句说明**:
前者是计数同步,后者是昨天那条「批次三不坐」裁定的入口文案,二者不是同一件事。

钩子显示名改在 `.pre-commit-config.yaml`(47 → 53)。**这条必须与代码同批入库**:配置脏而未 stage 时
pre-commit 会直接报错挡住全仓任何提交(今天已实测两次),所以本笔先落它,把后面几笔的路清开。

自查:`check_doc_links --all` rc=0(203 篇)、`check_ids --strict` rc=0 且不可判定绝对
数 **979 未变**(新增
文本里的提交号与 `#page=comm` 没推高它)、`gen_task_table --check` 0、`check_bom_drift`
 0、18 只文件 noBOM /
LF / U+FFFD=0;行数变动 +49/−47 全部可归属(插 6、删 2、并 1),其余为 1:1 等行替换。登记簿销项与叶数
(`UI补齐.md` + `docs/任务规划/README.md`)**不在本笔** —— 那是口径变更不是计数同步。
2026-10-27 13:54:05 +08:00
wandering1 31ca4a1faa docs(计数): 内容页黄金参考 40 → 47 页全仓同步,登记簿剩余项与顺序一并更新
上一笔 UI 落地时我把「文档计数与真值同源」这件事留在了别人身上(setpage 的移交项写得很明白:内容页 40→47
的全仓计数改写由 Lead 派)。这一笔把它做完,**只改当前态陈述,历史不动**:

· **改成 47 的判据**:simulator/tests/ref/ 实测 47 张 .bin(7 张新增、存量 40 张逐字节零漂移),共 1
6 处当前态
  陈述跨 11 只文件同步——含 AGENTS 的 ui-golden 条目、**钩子显示名**(.pre-commit-config.yaml)
、门禁索引与
  ui-golden 详解的标题与正文、UI 自动化流程的页数与 PASS 文案与快检张数、内容页架构回归段、覆盖率口径的
  「不做 UI 单测」理由、启动自动化流程回归段、导航器脚本 docstring。
· **不改的两处,理由写明**:5 只文件里的历史变更记录行「27 → 40 页」是当天事实,原样保留,只在各文件
  变更记录顶部加一行 2026-10-27 的 40 → 47;UI_界面制作流程 的「< 40KB」是绘制缓冲红线,与本数无关,
  属扫描误报,不动。
· **一处加限定语而不是改数**:UI_自动化测试流程 的「文本断言 310 条、覆盖 40 页中的…」带 2026-10-26 实跑
  日期戳,那是那天的测量口径 ⇒ 改成「覆盖**当时** 40 页」,310 条不臆改,等下一次实跑回填真值。

顺带同步 docs/任务规划/README.md(登记簿销项,用户授权):开篇「第一项是实现 param_request 写路径、然后做
整定 4 页」早已完成 ⇒ 改为剩余三项「通讯设置 → 记录 5 页 → 运行报告」;§2 顺序表「按 §1 的 1→5 推进」改为
「剩余 3 项按 1→3 推进(原第 1、2 两项已落地)」,与上一笔 UI补齐.md 的销项结果对齐。

三数同源自查:AGENTS 钩子数 51(YAML 解析口径)、内容页 47 页、门禁索引 27 篇均与配置一致;
check_doc_links.py --all exit 0、check_ids --strict exit 0 且不可判定绝对数 **1,156
 未变**(本笔没吃余量、
没新增编号引用);13 只文件全部 noBOM / LF / U+FFFD=0 / 结尾换行齐。本笔零固件源,不改构建产物。
2026-10-27 07:16:32 +08:00
wandering1 1d39571114 feat(门禁): 第 51 条 nested-comment——把 ARMCC #9-D 的按包含者刷屏拦在提交前
动机是今天一天复发三次的同一形态:在块注释里写作用域路径,那个 `/*` 被 ARMCC 当第二次注释起点(诊断 9-D),
而且**按包含者数量刷屏、只在重编译那个 TU 时才暴露**——本仓的诱因就是「注释里写 Drivers/BSP/UI/**」。
AGENTS 早就写了这条铁律(写全目录或用尖括号),但它一直是纯口头纪律,所以同一天还是复发三次。

新脚本 scripts/check_nested_comment.py:纯标准库、只读、五状态机(代码 / 行注释 / 块注释 / 字符串 / 字符
字面量),**只有块注释体内的 /* 才算问题**——字符串里的、行注释里的、未闭合判定都不误报。口径上刻意与钩子
的 types: [c] 对齐(403 个 .c/.h 同面),避免「手跑面 ≠ 提交面」这类我们今天就踩过的错位;零第三方依赖是
刻意的,为了让 generated-fresh 那天的解释器假红不长第二遍(实测 .venv 与机器级 C:Python314 两种解释器结论
一致)。

存量口径:全仓实扫**新发 0、存量 2 处**(test/host/common/ch395f_fake.h:7 与 fatfs_fake.h:9,同一形态
「注释里写作用域 test/host/**」)。两份假件头不参与 MCU 构建所以今天不报,一旦被 include 进板端 TU 就会
按包含者刷 9-D——属 test/ 写域,作者**没代改**,而是钉进 BASELINE 走只减不增,**其余零豁免**。

自证有一条必须写清的诚实边界:作者想「拿旧字节回放今天那三处真复发」,实测**做不到**——近 150 个提交里被
改过的 281 份 .c/.h 旧字节**零命中**,因为那三处同类从来没有一处在 HEAD 里留过字节(全靠人工编译后清掉)。
于是改测**形态**(这是能证的部分):10 项形态电池 10/10,含把已入库的尖括号写法退回星号形态 → 命中 1 处;
另用现存两份真字节做双跑:空基线 → 2 条 [NEW] + exit 1,加基线 → exit 0,证明**基线只决定算不算新的,
不掩盖有没有**。编译器侧原文(run_par.c(267) #9-D)冻结抄进新文档 §2.1——构建日志每次 @build 被覆盖且不入库,
所以文档里刻意没写「最近一次日志里仍有」这种会过期的话。

计数三处同批:AGENTS「共 **51** 个钩子」、门禁索引「51 个 hook → 27 篇 + 1 指针 + 1 外置」、配置声明;并记
文本 grep「 - id:」= 52 的成因(第 65 行被注释掉的 clang-format 候选),收紧行首口径 = 51。作者顺带自打了
一次:在配置注释里复述了那个 grep 字面量 → 文本计数当场虚高 1,已改写并把「配置注释里别复述字面量」写进
README §2 与 AGENTS。

同笔带上 task-28 的裁定句(AGENTS 一只文件里两卡改动天然混在一起,拆开会多两次改写与一次风险):不补第
23 根 ui-sink 专属钩子——22 根的唯一意义是秒级归因,而 ui_sink 失败面全落在 test-coverage 总闸必跑路径、
失败照样拦;读「这套跑没跑」去看总闸输出,别数钩子。

实测与本笔自查:validate-config = 0;nested-comment --selftest 4/4、--all = 403 / 新发 0 /
存量 2 → exit 0;
doc-links --sections-strict(4 篇)= 0;gen_task_table --check = 0;generated-fresh
PASS(5 处存量走 WARN);
check_ids --strict exit 0,**不可判定绝对数全程未被本闸吃掉**(作者开工 1,162、写完新闸与新文档仍 1,162;
现 1,156 是队友还清的);全部改动文件 noBOM / LF / U+FFFD=0。未跑 pre-commit --all-files(只跑本闸)。

**本笔使用 --no-verify 的凭证(唯一允许的两条之一,按 MEMORY 台账例外口径)**:把本批 6 只文件单独
staged 后跑 `pre-commit run --files <这 6 只>` → **13 条 Passed / 1 条 Failed**
唯一失败的是 `mem-budget`
(RAM 92% 阈值,**全树检查**)。本批**零固件源、零 .map 变更**,该红来自其他队友在飞的固件改动造成的 .map
漂移(当前树 Code=231,952 / RW=1,528 / ZI=136,264,在库台账 231,712 / 1,504 / 136,216
差 = run_par setter
与 vol_lock 计数两笔,均未提交);台账回填由我在树能编后统一 `--write`,不在分支上跑(避免多分支同改受管表)。
gate: only mem-budget pending lead ledger backfill。字节卫生本笔自查:6 只文件均 noBOM / L
F / U+FFFD=0,
新脚本纯 ASCII 输出路径无关,AGENTS 与索引两处计数与配置 YAML 解析口径 51 一致。

另收一条今天反复出现的元教训(Lead 与作者各错过一次、方向相反):**`pre-commit run` 与 git 钩子不是同一根
探针**——config 处于 modified-unstaged 时只有后者 [ERROR] 拒绝,前者与 validate-config 都 Passed
。它与「stash
只覆盖已跟踪未暂存」「未跟踪文件永不进 stash」同族:手跑的探针不能替真提交的探针作证。
2026-10-27 03:44:18 +08:00
wandering1 b24b2b5f31 docs(计数): 内容页黄金参考 27 → 40 全仓同源改写,含钩子显示名这最后一处不同码
CI / L0 静态门禁 (pre-commit) (push) Failing after 49s
CI / L0.5 主机侧单测 (MSVC) (push) Failing after 45s
UI 三页落地后机器真值变了,文档却还写着 27 页——这不是笔误,是会骗人的现在时。
作者(batch-auditor)先自己从机器面取数再动笔:git ls-files 里 ref/*.bin = 40、
PAGES 40 项、TEXTS 37 页 310 条、ABSENT 16 页 29 条、池 5448 B 与常驻堆 5368 B 未变、
字库 183 字未扩。**它还纠了我一个数**:我报 ABSENT +19,实测 11 → 29 = +18;作者按
实测写文档,并且不在文档里写 ABSENT 总数,免得把我这个差 1 的数固化成第二真源。

改写面(现在时陈述,共 12 + 3 处):AGENTS.md 的 ui-golden 半句、门禁说明 ui-golden.md
(标题与「拦不住什么」段)与索引行、simulator/tests/README.md、simulator/README.md 两处、
UI_自动化测试流程.md(310 条 / 40 页 / PASS 文案 / 覆盖面)、内容页架构.md、页面补齐规划.md、
主机单测覆盖率口径.md、自动化测试流程.md、测试开发标准流程.md,外加
.pre-commit-config.yaml 里 ui-golden 的显示名——那是「声明 / 文档 / 实跑」三数同源的最后
一处不同码:AGENTS 与门禁说明都已 40,配置里还写着 27。

两条纪律作者都自证了,不是口头:
· **历史数字一律保留**:8 处变更记录行里的 27 / 242 / 24 / 11 原样未改;两处带日期的
  验证记录只加限定语(「该下限此后已扩至 40 页,双次逐字节一致需按同口径重跑回填」),
  没有把 27 改成 40 去造连续性。
· **同名不同义的数字不许全局替换**:页面补齐规划.md:12 与 :157、页面扩充详细方案.md:649
  里的「27」是**空叶子口径**,与黄金参考数无关——三处故意没动。这条比改对更值钱。
· 余量自证(回退名下 12 文件复跑同一扫描器):refs +0 / dec +0 / und +0 / 比值 +0.00pp /
  错误 +0,本笔零消耗,也未新增任何编号引用;simulator/tests/ref/ 下 40 个 .bin 零改动。

闸线现状照实挂着:id-check 不可判定 1,162 / 上限 1,166,**余量只剩 4**(吃进者是今天
UI 那笔的注释引用,账在 Lead)。清账之前任何人新增编号都可能直接撞闸。
2026-10-27 00:16:07 +08:00
wandering1 7d9db33a25 chore(门禁+文档): 生成器幂等钩子落地,文档真值与 UI 清单销项同步
新增 generated-fresh 钩子(scripts/check_generated_fresh.py,只读):把 gen_menu.py、
中文字库链、tools/arch_diagram/gen_*.py 拷进系统临时目录重跑,与工作区逐字节必须
一致;钩子本身不写仓库、不 stash 别人在飞的改动。实证起点是上一笔 0f7b5a87 改了
模板文字却没重跑生成物,接线前实测另有 5 张 docs/images 配图已漂(文档挪目录只改了
生成器里的路径)——那 5 张按既有范式钉成只减不增基线,业务生成物零豁免面。

计数三数同源核查:文本 grep 配置得到 51 是把第 63 行**注释掉的** clang-format 候选
算进去了,口径统一为「YAML 解析后的 hook 条目数」= 50(实跑 49 + gitlint = 50),
AGENTS 与 docs/门禁说明/README.md §2 用同一条自查命令。顺带更正「主机侧单测 23 个
(含 ui-sink)」:实为 22 个,test/host/ui_sink 有 run_unit_test.py 却没有 per-module
钩子,只有覆盖率总闸跑得到它(已另立待办,不当既成事实写进文档)。

文档真值一批(都按脚本/仓库实测取数,不抄旧文档):内容页黄金 11/18 页 → 27 页
(8 处,含 ui-golden 钩子显示名)、文本级断言 50 条 → 242 条、池容量 4784/4864 →
5368/5448(含菜单页面设计.md 与同文档 1.5 节自相矛盾的那处)、页面补齐规划的立项
快照加限定语(日期按该文档自身标题 2026-10-23,不臆造现值)。变更记录里的历史数字
(11 页、50 条、老基线时代的绝对峰值)一律不改;无法实测的绝对峰值改成增量口径并
标注「待按新基线重测」。

销项(用户裁定 2026-10-26):UI补齐.md 与 README §1 删除「param_request 写路径」
与「整定 4 页」两行并重排序号,叶数口径 12/21/16 改 16/17/12;定值项数按
App/algo/prot_set.h 的 PS_ID_COUNT 更正为 40(原写 31 是旧口径);「主站地址白名单」
移入当前不做并写明理由:CH395F 单连接 socket 上「拒绝即 close+重 listen」等于给扫描
风暴开门,且该值现在没有任何既有消费点。

台架证据入库(像 = 77779d49,仓外 detached worktree 只读出像):启动日志、仅复位不
重烧日志、104 定值写读腿、控制台交错一手字节证据与四张板照,boot_log_data 台账登记。
.gitignore 兜一条 %SystemDrive%/:子进程环境缺 SystemDrive/ProgramData 时 UV4 会按
字面量在仓库根建字体缓存目录,本会话实测复发两次,不兜住某次 git add -A 就进历史。

自证:改前后编号门禁 refs / 不可判定 / 比例 / 错误级逐项差值为 0(未把可判定引用改成
散文);check_doc_links --all 无法判定 0;文档路径检查通过 177 篇。

本笔不含三条在飞源码道与板端导航脚本修复,它们各自单独一笔。

为什么本笔走 --no-verify(按仓库既有约定,非偷懒):本笔内容是**纯文档 + 门禁脚本/配置 +
台架证据**,不含任何业务代码;而工作树里同时压着三条在飞源码道(UI 装置维护 3 页、
[comm] 配置段、控制台行级原子性)。pre-commit 跑钩子前会 stash 未 staged 改动,那
等于把别人未完成的代码算进本笔账——console_log 套件的属主自己就报告过「当前还没跑过
该套件」。逐条相关门禁已单独实跑:check_doc_links --all(无法判定 0)、check_ids
(余量差值为 0)、generated-fresh 用 .venv 解释器直跑 PASS(4 项 / 一致 3 / 存量基线
1 / 报错 0)、validate-config 0、BOM 漂移与 mojibake 干净、YAML 解析条目 50 与文档
及实跑三数同源。唯一会红的是 mem-budget:磁盘上的 .map 含上述在飞代码,与 HEAD 台账
不同码;台账与体积凭证由我在源码道全部落地后统一重建回填。证据文件:
ci-artifacts/commitA2.log(上一次尝试的完整钩子输出)。

另记一条本笔实测到的坑(已写进 AGENTS「Python 环境」与 docs/门禁说明/generated-fresh.md
§4):钩子 entry 的裸 python 会被 pre-commit 解析成机器级解释器(本机 = C:\\Python314,
无 fontTools)→ 字体链生成器报 No module named fontTools、generated-fresh 假红。修法
是脚本内自己按「显式 var > 当前解释器 > 仓库 .venv > PATH」解析并做探针校验(装了
pre-commit 不等于装了 fontTools),但 entry 不写死绝对路径,否则门禁被绑死在一台机器。
这与 scripts/ci_local.py 文件头记的 2026-10-11「L0 全灭」是同一族问题的第二次发作。

台架证据补两行:板端 UI 导航脚本修复的真机冷启动闭环 PASS(首帧待机页 UNKNOWN →
按 e → 9 步到 view_set,终帧墨量与黄金 shot_vset 一致),存证同目录;该脚本本身的
改动留给下一笔。
2026-10-26 18:26:47 +08:00
wandering1 e771a8ea21 docs(门禁计数): 钩子 48→49、单测行 16→22、uinav-selftest 上索引
navtool 合入(3e03375)带进第 49 个钩子 uinav-selftest(快检档,专篇待补、
指针指向 UI_自动化测试流程 §7.3 正文);门禁 README 索引头 42/25 系批 2
两批钩子未追平,本次一并核账为 49/26+1 指针,主机单测行 16→22(含批 2
六新套);AGENTS 两处计数与新增括注同步。纯计数与索引,无口径变化。
2026-10-25 18:10:44 +08:00
wandering1 7099c56c34 chore(ledger): pages 批 1~4 合入后回填凭证/覆盖率并同步黄金参考计数
task/pages-ui 合入(merge dea7591 + 修复 498cc60):三页回炉 + SOE 页 +
四查看页 + 遥信 33 行页 + ui_data 三通道 + soe_store 只读 API + 字库与
门禁配套共 12 笔。凭证重盖(Code=224,688 / RW_IRAM1 78,992 B=60.3% /
CCM 87.9%);覆盖率基线 39/39 套件复算。ui-golden 黄金参考 11→18 页
随批 4 扩容,AGENTS 门禁行/索引行与门禁说明两处、覆盖率口径一处同步;
两篇新详解(bom-guard/setview-check)已由道E 交付、索引去"待补"。
memset 隐式声明一条教训:分支树增量构建"0 警"不覆盖未重编文件,
done 主树全量重编才是终判。
2026-10-25 15:49:42 +08:00
wandering1 fa80b17d5f docs(门禁说明): 补 bom-guard 与 setview-check 两篇详解
票面:task-20 合入后 README 索引上挂着我名的两篇(Lead 指定挂批 4 MR)。按本目录八段结构写,
「拦下过什么真事」一栏用同日实测,作者自己的也算。

- bom-guard.md:立项依据是 2026-10-25 一天内 5 次(道E 4 次 + 道B 1 次);症状 #870-D / #8 /
  #274 一类**假语法错**,位置不指向真因;MSVC 与既有钩子全照不出来;"人工逐文件比 HEAD"只防得
  住记得做的人。两条刻意不报的边界(新文件无 BOM、反向加 BOM)+ 一条刻意不做(不自动补,整文件
  重写会把可修的丢 BOM 变成不可修的 U+FFFD)+ 三处互指防漂移,各写清理由。也记了本门禁自己的
  立项提交被 gitlint 拦过(正文一行 92>80,量出来仍按了提交)——这一栏只挑别人的事写就等于暗示
  写门禁的人不需要门禁。
- setview-check.md:立论点是"分层边界制造的物理盲区"——BSP 不得 include App 头,行表 id 只能是
  裸数字 + 注名,编译期无法自证;像素断言又只看可见 8 行,40 项分 5 页,错位一行时第 1 页可能
  看着完全正常。另收两条脚本自身实测坑:\w+ 吃不下带引号的单位导致**整行静默跳过**(故加行数
  硬闸)、打印中文时 CP936 半路崩(门禁脚本崩在半路 = 一条都没检查)。退出码 1 与 2 分开:把
  "我没读懂"报成"你写错了"是检查类脚本最坏的一种失败。
- README.md:索引加两行;"那 46 个钩子" → 48、"40 个 hook → 23 篇" → 42 → 25 篇(不同步就是在
  让索引说谎)。AGENTS 里"两篇待补"那句已过期,但 AGENTS 是单写者文件,留给 Lead 收。

跳过的门禁(三条同族):mem-numbers / mem-budget / size-gate(L0c),与本笔无关,等台账回填。
2026-10-25 15:33:46 +08:00
wandering1 42b47aa5ac chore(ledger): runpar 合入后回填台账/凭证/覆盖率并同步计数
task/runpar-par 合入(merge 7bbcc9c):卡10 运行参数段 [run_par] 9 键 +
104 映射 0x8030~0x804F + 死区真源收编 + SYS_EVT_RUN_PAR_SAVE 落盘链。
@build 0/0:Code=219,620 / RO=22,036 / RW=1,280 / ZI=132,864;
RW_IRAM1 76,720 B(58.6%)、CCM 87.9%。Flash +1,912 B、RAM +8 B 与
lane-d 申报一致,--no-verify 欠账清。meas.c 静态更名越界照准(同 TU
撞名 C2369 的最小修)。run_par.c 入覆盖率基线(39/39 套件);钩子
45→46、单测钩子 21→22、总闸 38→39(AGENTS + 门禁 README)。
2026-10-25 13:21:39 +08:00
wandering1 adeef7d21b chore(ledger): meas 与 n17 两笔合入后回填台账/凭证/覆盖率并同步计数
task/meas-snap 合入(merge 9c2653c,meas 快照层,分支树冲突由 lead 并集
手工解:id_registry 三族 UIDATA/VOLSYNC/MEAS 共存,JSON 校验过;该合并
提交按 mem 域例外 --no-verify,理由=合并树 .map 滞后,回填本笔兑现)。
task/n17-probe 合入(merge 969fc5c,drop 路径异步化 Flash +16 B/RAM 0)。
合并后 @build 0/0:Code=217,828 / RO=21,600 / RW=1,264 / ZI=132,840;
RW_IRAM1 76,664 B(58.5%)、CCM 87.9% 不变。覆盖率 38/38 套件基线登记
(meas.c 入账);凭证按最终 .map 重盖。计数:钩子 44→45、单测钩子
20→21、总闸 37→38 套(AGENTS + 门禁 README)。
2026-10-25 10:37:05 +08:00
wandering1 b746a1ff00 chore(ledger): ui-data 合入后回填台账/凭证/覆盖率并同步门禁计数
task/ui-data-feed 合入(merge 98664a1):ui_data 三通道快照 +
ui_data_feed 装配 + ui_w_soe 显示名 + 字库 +4 字(采/样/恢/效,
179→183)。合并后 @build 0/0:Code=217,204 / RO=21,504 /
RW=1,256 / ZI=132,680;RW_IRAM1 76,512 B(58.4%)、CCM 87.9%。
lane-e 分支侧 --no-verify 欠账清;覆盖率基线登记 ui_data.c
(37/37 套件、tested 41);凭证重盖(L0c 恢复序列)。
AGENTS/门禁 README 计数 42→44 钩、18→20 单测钩子(n22+ui-data 两笔带进来)。
2026-10-25 10:07:15 +08:00
wandering1 c4edf352fe refactor(UI): 记录页改注入式 reader,layer-deps 基线 6->3(道B task-6)
B-6 分层收紧(UI_数据供给设计说明.md §7.2 契约原样落地):
- ui_w_records:删 #include "sys_log.h",改 ui_rec_reader_t 只读函数表 +
  ui_w_records_bind() 模块级注入(sys_log 读 API 本为全局,函数表共享、
  实例读盘缓存仍各自独享——切页陈旧行防御不变);log_id 换不透明编号
  UI_W_REC_LOG_RUN/SELFTEST;缓冲容量宏本地化 UI_W_REC_TS/DESC_LEN
  (20/29,与 sys_log 契约下限同宽;读失败退化空行防御保留)
- ui_page_runlog / ui_page_selftest:去 sys_log include,实例改不透明编号
- 两端薄包装适配层(编号→syslog_id_t 显式映射,错误码 0/-1/-2 直通不改写):
  App/task/ui_task.c 与 simulator/main.c(无头+窗口两个 init 点),均在
  ui_menu_init 之前 ui_w_records_bind;未绑定窗口组件按空态防御不读野
- scripts/check_layer_deps.py:BASELINE 6→3(--prune 实测恰 3 条 UI 记录
  边消失后写回;剩 NETCFG×2 + lftpd_io 与 UI 无关)——道B 独占收紧口径
- 文档同步:门禁说明 layer-deps.md §1/§6/§9 与 README 计数 6→3;
  UI_数据供给设计说明.md §7.2 加落地注记、§14"计划削减"改"已兑现"
- 首提被 id-check 拦下:注释/文档里自造"批卡编号"(B-6/道B-3)命中
  "未登记前缀"增量拦截——已全数改回 task-6/道B 普通指称(编号不回收、
  禁自造,教训入本提交);id-check 复跑 RC=0(S10 告警为存量非本改动)

验证:
- 模拟器 0 警告;菜单 8 状态 + 内容页 11 页黄金参考逐字节 PASS
  (记录页数据流经 reader 后像素与基线一致,无基线更新提交)
- cppcheck/coding-standard/bsp-err/font-charset/no-mojibake 单跑全绿;
  layer-deps 复跑:6 处反向 include = 豁免 3 / 基线内 3 / 新增 0,
  --prune 显示"基线无需收紧(3 条存量全部仍成立)"
- doc-links --all 的 35 处告警全为本仓检出路径含空格误扫 SDL2 自带 md
  (环境问题、非本改动引入;提交门禁按暂存文件名过滤不受影响)
- @build 0 Error 0 Warning(终树复跑 BUILD_OK);uvprojx 无 UV4 抖动、
  无新文件不涉注册;其余 38 钩全绿(ui-golden/font-charset/coding-standard/
  bsp-err/id-check/cppcheck…单跑复验 RC=0)

增量(A/B 同树 .map,基线 = 合入 c1b425d 后 HEAD):
- Flash:Code +104 B、RO +8 B(两端薄包装代码 + reader 函数表 const)
- RAM:RW +4 B(s_reader 指针)/ ZI +4 B(两页实例 struct 枚举改 uint8
  本应 -8 B,链接段对齐后净 +4 B);RW+ZI 合计 +8 B

gate: only mem-budget/mem-numbers pending lead ledger backfill
- pre-commit run --all-files 实测仅这两条失败(台账/RAM 文档 vs .map 漂移,
  根因即上列 Code +104/RO +8/RW +4/ZI +4),其余 38 钩全绿;按 Lead 裁决
  (task-4 口径"以后照此办理",含 Flash/RAM 漂移同例外)--no-verify 提交,
  合并后请主树回填台账(scripts/ram_baseline.py --write 由 Lead 侧执行)
- 手工自查通过:5 个 BOM 文件 BOM=EF BB BF 齐全、docs/py/main.c 保持无 BOM,
  全部 10 文件 CR=0、U+FFFD=0
- 台账增量供回填:Flash Code +104 B、RO +8 B;RAM RW +4 B、ZI +4 B
2026-10-25 05:21:05 +08:00
wandering1 744a1cb086 ci(gates): 接线 test-coverage 覆盖率总闸(FAIL 语义),并修三处已成假话的门禁文档
用户裁定 2026-10-24:缺 mscoverage 组件时**失败**,不做 skip。于是 P1 之后那个
"钩子只挂 16/28 套"的缺口关闭了。

为什么挂这一根而不是补 12 根 per-module 钩子:本闸跑**全部 28 套**,并且守
"已覆盖行只增不减"的基线台账。这是 per-module 钩子结构性做不到的——删掉一套
测试,它那根钩子只会因为"没有文件要检查"而静默跳过(Skipped 不等于失败)。
实测接线代价:45 s(28 套,含 28 次 MSVC 编译与插桩运行)。

FAIL 语义已按本仓"合成自证"的纪律验证(不是只测绿的那一半):把
DTU_MS_COVERAGE 指到一个不存在的文件 → 钩子 Failed、脚本退出码 2、并打印可
执行的 [ENV] 提示(说明该 exe 装在哪、怎么覆盖)。脚本对显式环境变量刻意
"不做自动探测回退",所以指错会被点名,而不是悄悄换一份工具跑出另一本账。

顺手修掉三条**现在已经不成立**的文档说法(门禁文档最贵的就是骗人):
- 口径 §7 第 8 条:原写"只有 BuildTools 且没勾代码覆盖率工具的机器会退出码 2"。
  实测本机 Community 18.10 与 BuildTools 18.9 **两份安装都自带**该 exe(mtime
  2026-09-15 02:30 / 2026-09-05 16:17,都是各自安装当日,不是后来补勾)→ VS 18
  的 BuildTools 默认就带它。真实风险面只剩:裸 MSVC 无 VS 的机器、环境变量指错、
  以及靠 PATH 兜底的环境。
- 门禁说明 host-unit-tests.md 盲区第 4 条:原写"没有对应钩子的模块 = 零回归"——
  如今 12 套新模块由总闸兜住,这句话已经不成立,改成两种口径并写清触发面。
- 同篇第 6 条:原写"无覆盖率统计"。行/函数覆盖**已有**度量(本闸出 Cobertura 并
  守基线),仍无的只是分支覆盖——那是用户裁定 2026-10-23 记下的**已接受缺口**,
  不是待办,改口时把这个区分写清楚。

钩子计数同步(新增 1 根 → 声明 40 根 / pre-commit 阶段 39 根 + commit-msg 的
gitlint,已用脚本核对,不是手数):AGENTS.md(总数、枚举、索引表)、
pre-commit使用说明.md(66 / 91 / 234 三处,含清点日期)、门禁说明 README
(正文与索引标题,另加一行索引指向口径文档——23 篇不变,同一事实不在两处维护)、
门禁说明 gitlint.md(--no-verify 跳过的"其它 38 个"→39)、并行任务工作树方案。

自查:end-of-file-fixer 与 trailing-whitespace 复跑 Passed(首轮 --all-files 只
因末行空行红过一次,已按钩子自身规范化);doc-links --all --sections-strict 通过
(178 个文档);id-check --strict 零台账外新账;8 个改动文件 U+FFFD = 0、无 CRLF。
零代码改动,故未跑 @build。未 push。
2026-10-24 07:50:53 +08:00
wandering1 6822726b2c docs(门禁说明): 手册 §2 收敛为通用机制与查号表,逐项详解归一到 23 篇
用户一句"现在门禁都在干什么,我一概不知"引出的收尾。原手册 §2 有 27 个逐钩子小节,只回答
"拦了什么、怎么配",回答不了"什么时候会骗我";docs/门禁说明/ 已把逐项详解(含"限制与盲区"
一节)建好,本笔做收敛:同一事实只留一处(docs/文档规范.md 的要求)。

**先搬后删**(否则收敛等于丢事实):旧 §2 里独有条目逐篇折回,共 18 处插入、15 篇受益。折回的
东西包括:六套主机单测的来历与用例规模(13/36/82/46/32/149 断言,含 nand-port 的"与旧算法
对照")与"改动公共骨架 unit_test_harness.py 会同时触发 16 个钩子";UI 页面**两层注册**(构建
注册 vs 框架注册:枚举 + s_defs[] 描述符表)与"豁免不整目录一刀切";lv-conf-sync 首次落地清掉
26 个 LVGL 9.3 不存在的选项、3 处重复定义、10 项隐式开关显式化,以及 ALLOW_DIFF 端专属白名单
与必须穿过 lv_conf_internal.h 里那层 KCONFIG 包裹;cubemx-survival 的 16 项清单、断言前先剥
C 注释(本仓注释刻意引用历史代码,不剥就恒定误报)、旧手册"自造标记区"建议与看门狗文档实测
教训之间的优先级;id-check 顺带收编 check_test_traceability.py、裸形同字母多义属**显式承认的
盲区**、--update-baseline 只许涨;layer-deps 的注入自证与报错时三条修法(注入回调 / 上层递数据
/ 才谈 ALLOW);coding-standard **nand_ftl.* 也在排除清单**(我先前那篇漏了);test-suite-switch
的剥注释判定与派生宏白名单;mem-budget 两类软提醒不拦、退出码 2 是解析失败不是通过;doc-links
的排除目录与状态词 ±40 字符距离;task-table 改栈三步;gitlint 报错样例;no-mojibake 的修复路径。

**顺带抓到旧文档两处错**(记进文档,不悄悄改):一是 check-added-large-files 的阈值旧手册写
"单个文件 > 1MB",按本机安装的钩子源码实测是 --maxkb 默认 **500**(500 KB)——已更正,并把
"本目录任何默认值都以实测或安装的钩子源码为准"写进 end-of-file-fixer 当反面教材;二是
**ui-golden 在旧手册里连小节都没有**,只活在配置注释里:除了"有基线不等于有门禁",这是另一种
失踪——有钩子、没文档。

手册 §2 改写为三节:迁移说明 / **旧编号 → 新文档 查号表**(历史引用靠它读,旧号按"冻结历史不
回改"保留)/ **跨钩子通用机制**:两阶段与换机必须重装 hooks 才带 commit-msg、stash 陷阱、
always: true 已废、改写型与只读型豁免不对称、增量拦截三段式且刻意没有 --write、没有 .map 是
"跳过"不是"通过"、改配置的验收是看目标钩子出现在输出里且不是 Skipped、新增门禁三步必须做
注入自证且"限制与盲区"不许留空,另有快速自查入口。手册 707 行 → 273 行。

引用**按内容**重指(只核编号存在与否不够,同号小节会被当本文自引用静默放过):编号规范、
scripts/README(顺带更正那里过时的 warn-only 说法,早已关闸为增量拦截)、RAM 使用分析与优化
方案、测试开发标准流程、lvgl-simulator skill、AGENTS 文档表(拆成"每门禁一篇详解"与"通用
机制"两行)、.pre-commit-config.yaml 头注释、docs/README.md 描述、手册自身 §5.5 与 §6 的两处
内部引用。另:表格里的裸节号会被 doc-links 判成本文自引用,查号表统一写成不带 § 的形态。

写说明过程又被自家门禁拦一次:gitlint 篇里引用报错样例时写了两个规则号字面量,被判形态不合规
→ 改成中文描述,没有往台账里塞 reason 解决。

验证:纯文档与注释改动,不动代码,Program Size 不变,故不跑 @build/@test;
check_doc_links --all --sections-strict **171 篇 0 问题**;id-check 增量拦截通过;
pre-commit run **RC=0 / 13 项 Passed**;28 个改动文件字节卫生 **0 异常**(无 BOM、无 CR、
无 U+FFFD、均 LF、无行尾空白)。
2026-10-23 11:44:21 +08:00
wandering1 dc44c1e54e docs(门禁说明): 补齐 23 篇逐项门禁文档,每种门禁一篇含限制与盲区
用户诉求原话:"现在门禁都在干什么,我一概不知。" 原有文档回答"有哪些钩子、怎么配",回答不了
"这一条到底在拦什么、什么时候会骗我"。本目录按**每种门禁一篇**补齐 23 篇(39 个 hook id 全覆盖:
16 个主机单测是同机制 16 实例合一篇;cppcheck 与 test-cppcheck 是同工具两套范围合一篇),
文件名用 hook id,与提交输出里的名字一致、可 grep。

八段固定结构:查什么 / 为什么要它(拦下过什么真事)/ 触发面 / 报错怎么读 / 好处 /
**限制与盲区** / 豁免与基线口径 / 改门禁本身要注意什么。最后一节是这批文档存在的理由——
只看"拦了什么"的文档会让人以为绿就是对的;本仓三个增量拦截门禁(layer-deps 6 条、bsp-err 38 条、
id-check 台账 640 处)的绿灯含义只是"没比上次更差"。README 另立"三种拦截姿态"一节:改写型 /
硬拦截 / 增量拦截,分清才知道报错时该改代码还是该还基线。

有实证的地方全部带数字,没实证的地方直接写"预防性、未记录到实际拦截案例"(不编故事):
· cppcheck:把 simulator/ 纳入受检后立刻揪出 sim_syslog.c 真实空指针;test/ 曾有 s_rx_buf
  使用先于声明;**并记入两条实测负结果**——它对 14 处丢弃 HAL_SPI_* 返回值与"未初始化局部量
  进 P_FAIL 判定"一条不报(这正是 consume-result 的由来)。
· lv-conf-sync:漂移导致 64,576 B 死代码入库(旧镜像的 23.5%),且 golden 跑的是模拟器那份配置。
· cubemx-survival:2026-09-29 一次重生成覆盖 4 处定制(P0×1+P1×2+P2×1),且不报编译错。
· registration-check:rs485_task.c、lftpd_log.c 两处都没注册 = 从不参与编译的死代码;第四类
  "页面描述了但没接进 s_defs[] 表"编译链接全过,前三类完全照不出。
· test-suite-switch:实测已提交的 HEAD 里 TEST_SUITE_CH395F 就是开着的,.map 含 34 处 test 代码。
· task-table:2026-09 两张表都比源码落后一大截(写 2048/4096/…/16384,实际 1024…512)。
· mem-numbers:2026-09-26 复核,文档写 82,048 B / 62.6%,实际 87,040 B / 66.4%;Flash 写
  249,432 / 23.8%,实际 261,932 / 25.0%。
· ui-golden:注入 .top_y +3 像素 → golden FAIL 点名"1366 px 差异"、退出码 1;并把"有基线
  ≠ 有门禁"与"逼人 --no-verify 的门禁等于没有门禁"两条选型依据写进去。
· check-yaml:本仓已移除的 always 键只告警 Unexpected key(s) 然后忽略——配置"看起来生效其实没
  生效"而本门全绿,所以验收方式是实跑看目标钩子是 Passed 还是 Skipped。
· no-mojibake:types: [c] 只管 C/H,**文档侧乱码无人管**——覆盖面与需求错配定性写进限制一节。

盲区写法示例(每篇都要求写真实限度,不留空):layer-deps 只查直接 include、按 basename 匹配、
不查是否真的用到;font-charset 管不到运行期拼出来的字符串与配置文件里的字;host-unit-tests 用宿主
编译器、桩是第二份真相、include_dirs 手写、没有对应钩子的模块等于零回归;mem-budget 的 92% 是管理
阈值不是安全余量、.map 缺失即"通过式跳过";registration-check 不看条件编译与注册指向是否正确;
coding-standard 的 CODE-RULE-17 在无配对头时跳过、规则编号 14 作废不回收。

写文档过程自己被自家门禁拦了两轮,都按规矩改而不是绕过:
① doc-links 拦下我自己——我在解释"写 §数字 而没紧邻文档名会被判成本文自引用"这段话里,正好
   就犯了这个写法(两处),另有一处示例输出未标记;改成正例写法 + [示例] 标记。
② id-check 拦下 7 类新账:示例报错行里的号、档号引用未紧邻文档名、说明"裸形不合规"时自己写了
   裸形。全部改成平实描述或补文档名、给样例加 [示例],没有一条是往台账里塞 reason 解决的。
这两次本身已写进相关篇目的"限制/变更记录",是这套文档最实在的注脚。

同步:手册 pre-commit使用说明.md 的 §2 顶部加指针(逐项详解已迁往本目录;两处收敛为"通用机制 +
总览 + 指针"排在 docs/门禁说明/README.md §4 的下一步,并注明收敛要按内容重指既有引用——只核编号
存在与否不够);README 索引 23 行状态全部置为已写、文档列改为可达链接。

验证:纯文档,不动代码与构建产物;check_doc_links --all --sections-strict **171 篇 0 问题**
(新目录 24 个文件的内部链接与跨文档引用都纳入判定);id-check --strict 增量拦截通过;本次受影响
文件 pre-commit run **RC=0**;24 个文件字节卫生 0 异常(无 BOM、无 CR、无 U+FFFD、均有尾换行)。
2026-10-23 10:54:33 +08:00
wandering1 3488617bc9 docs(门禁说明): 新建逐项门禁文档目录,先落索引 README 与 bsp-err 首篇
用户的原话是:"现在门禁都在干什么,我一概不知。" 现有文档只回答"有哪些钩子、怎么配"
(docs/代码规范/pre-commit使用说明.md),回答不了"这一条到底在拦什么、什么时候会骗我"。
故新开一个目录,**每种门禁一篇**,八段固定结构:查什么 / 为什么要它(拦下过什么真事)/
触发面 / 报错怎么读 / 好处 / **限制与盲区** / 豁免与基线口径 / 改门禁本身要注意什么。

**最后一节是这批文档存在的理由**:只看"拦了什么"的门禁文档会让人以为绿就是对的。而本仓
三个增量拦截门禁(layer-deps 6 条、bsp-err 38 条、id-check 台账 640 处)的绿灯含义只是
"没有比上次更差"。

索引按 39 个 hook → 23 篇规划(16 个主机单测是同机制 16 实例,合一篇;cppcheck 与
test-cppcheck 是同工具两套范围,合一篇),文件直接用 hook id 命名,与提交输出里的名字
一致、可 grep。README 另有一节"三种拦截姿态"——改写型 / 硬拦截 / 增量拦截——分清这三类,
报错时才知道该改代码、还是该还基线。钩子清单、files 范围、pass_filenames 全部从
.pre-commit-config.yaml 实测解析(39 个 id:官方 5 + gitlint + local 33),不是手抄。

本次交付:索引 README + 首篇 bsp-err.md。首篇里把今天踩过的坑全写进"限制与盲区",共 10 条,
例如:只扫 Drivers/BSP(App 层同类问题仍无人管);consume-result 只认单行整句的裸调用,
跨行写的调用按正则形状测不到;must-use 名单靠"返回类型 + 注释关键词"启发式,注释不写
"错误码/失败"就漏、改名就能绕开规则;HAL 族是固定清单,清单外的返回 HAL 状态的函数不在
名单里;return-doc 的判据是"注释块里出现『返回值』字样",**散文里出现这三个字也会放行**
(本仓真发生过两条靠函数说明里的关键词误判通过);基线键带出现序号,--prune 只报"消失"、
不会报告某处只是搬了家;改标签名等于改基线键,必须原子完成。在册数量与构成按当前基线
逐条数出来写(38 = consume-result 37:gd5f2gq5ue.c 28 含 14 处 HAL 丢弃 + 14 处自家原语、
ui_net_sink.c 6 全为 net_close、rs485.c 2、nand_ftl.c 1;err-type 1 为 bool
ui_content_page_open())。

同步指向:AGENTS.md 提交门禁一节改为"每种门禁一篇详解 → docs/门禁说明/README.md",通用
机制仍指 pre-commit使用说明.md;docs/README.md §7.1 增加索引行;.pre-commit-config.yaml 的
bsp-err 注释块顺手更正(原文还写着"三条规则""现 1 条""只能靠书写约定兜着",均已过时)。
迁移状态用索引表的"状态"列跟踪;全部写完后 pre-commit使用说明.md §2 收敛为通用机制 +
总览,同一事实只留一处(docs/文档规范.md 的要求)。

验证:纯文档与注释改动,未触碰构建产物;check_doc_links --all --sections-strict 149 篇
0 问题(新目录的相对链接、跨文档章节引用都能判定);bsp-err 仍 38/38/0;本次受影响文件的
pre-commit 全绿 RC=0;两份新文档字节卫生 ok(无 BOM、无 CR、无 U+FFFD、有尾换行)。
2026-10-23 09:48:26 +08:00