Commit Graph

233 Commits

Author SHA1 Message Date
wandering1 aed842e1f2 Merge branch 'v2-on-ui' into task/archsplit-sw-hw
# Conflicts:
#	docs/架构设计/软件架构与运行时规格.md
2026-10-30 13:32:52 +08:00
wandering1 00fe66a029 docs(架构设计): 系统架构与硬件规格拆为软件与硬件两档,软硬件分治
用户裁定(2026-10-30):合档拆成两部分,软件与硬件不混排。

- 软件侧(新 §1~§6)= 分层 / 任务模型 / 就绪位表 / 启动时序 / 线程通信 /
  工具链与工程约束 → docs/架构设计/软件架构与运行时规格.md
- 硬件侧(新 §1~§5)= 主控内存 / V0.1 引脚表 / 存储器件 / 版本兼容 /
  能力边界 H1~H5 与量纲口径 → docs/架构设计/硬件规格与能力边界.md
- 旧 2.1 的 RTOS / 工具链 / CubeMX 三行迁入软件档 §6.1;旧 2.5 五条工程
  约束归软件档 §6.2,SDIO 一条归硬件档 §5 H5(同事实不再两处并存)。
- 存储器件小节的 BBT / 单写者 / FatFs 三条细则不与权威档重复,改为指向
  存储架构说明与软件档 §2。
- 引用重挂:AGENTS 引脚行→硬件档 §2;docs/README 3 处;需求档 7 处
  (「架构硬件档」别名一分为二「软件架构档 / 硬件规格档」);复刻明细
  2 处;section_aliases.json 两键改四键。
- 两档尾部各留裸号换算注(旧档号不带 §,避免与本文编号体系混淆、且
  doc-links 自引用 strict 必拦);旧档名全仓零引用。

门禁:树内 check_doc_links --all --sections-strict 剩 35 处全部为
simulator/SDL2 联接「名称含空格」假红(主树同命令 rc=0 干净),本笔
文件新发 0;mermaid 预检新发 0;七文件 BOM/CR/U+FFFD 全零。
2026-10-30 13:08:44 +08:00
wandering1 4a4ad6bc5f chore(全仓): @build/@test 旧文档别名清退为技能调用名
现状口径:/keil-build 与 /serial-boot-test 是 DSH 会话的技能调用名,
不是 shell 命令;「名 + 命令行参数」的命令形态改为可执行体
run_boot_test.py 的真实调用。

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

验证:提交期快钩子对 123 文件实跑全 Passed;check_doc_links --all
rc=0(3038 处、无法判定 0);check_mermaid --all rc=0;YAML 解析 52
钩子不变;skill-size rc=0;py_compile 全过;字节卫生零漂移。
2026-10-30 13:03:12 +08:00
wandering1 dc964090ea docs(产品需求): 需求基线拆薄为三档(大厂标准),doc-links 增别名解析
产品需求设计文档.md v1.9 → v2.0(2691 → 1816 行):
- 新增 §2 背景·目标用户·典型场景·成功指标,§3.2 产品级非目标表,
  §4 P0/P1/P2 需求总览(19 行);§9 收窄为缺口清单与推进顺序。
- 拆出 docs/产品需求/参考产品复刻明细.md(803 行):复刻基线 +
  定值/遥测/开入开出/事件/元件/录波/记录/规约逐项差额与完成判据。
- 拆出 docs/架构设计/系统架构与硬件规格.md(215 行):运行时架构
  (就绪位表/机制表/启动时序)+ V0.1 硬件规格;与项目架构总览
  定分工——位表/机制表/时序图/引脚表以新档为准。

引用同步:AGENTS.md 引脚表指针改指系统架构与硬件规格 §2.2;
docs/README.md 目录树与索引四处重写;故障录波三处「录波采样率」
行指针改指复刻明细 §7;PRD §11 补两新档指针。

门禁工具:check_doc_links.py 裸名解析增别名后缀匹配(「见需求档
§5.16」形态),§ 链遇紧邻已登记别名换目标;section_aliases.json
登记 需求档 / 架构硬件档 / 复刻明细(档) / 产品需求设计文档 /
系统架构与硬件规格。

终验:doc --all rc=0(3038 处 / 可判定 80%);mermaid --all 64 围栏
0 命中;改动文件字节卫生全过;新旧逐行差集审计无丢行。
2026-10-30 12:36:31 +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 a157b443cb chore(台账): keyresp 合并后回填 RAM 台账与体积/覆盖率凭证
主干 0cabed0b 合入 task/keyresp-ui-key-latency 后按 C5 链补绿:
- @build 0 错 0 警(Code=246720 RW=2052 ZI=149708,与分支树同码)
- check_mem_numbers.py --write + ram_baseline.py --write/--update
- check_test_coverage.py --update-baseline(47/47,line 90.2%)
- add 后重打体积凭证(check_size_gate.py --stamp,同码免涨)
- check_doc_links.py --all 通过(214 文档 / 2966 引用)

RAM 增量归因见台账:本任务自身仅 ui_port.o +12 B 级,
其余为主干批 3 屏板链路累计(前笔 7708f12c 正文已如实说明)。
2026-10-30 09:56:12 +08:00
wandering1 7708f12c10 fix(ui/screenlink): 按键应答扣到按键后画面,反馈典型 250-450 ms 降至 70-135 ms
按键召唤答的是按键前的旧帧:uiTask 还没消化键答案就发走了,新画面
只能等下一次周期召唤(280 ms/轮)才带得出——真机反馈 250-450 ms 的
主构成(根因账本 docs/子系统设计/屏板链路设计说明.md §7.1)。

改动(用户批准范围 A+B+C;屏板固件未动,决策三不变):
- sb_link:按键召唤改为只入队不起发;uiTask 同拍重绘并组帧成功后交
  凭据(sb_link_key_rendered),TIM3 1 kHz 的 sb_link_ms_tick 以 ≤1 ms
  放行新帧。140 ms 截止(SB_KEY_RESP_MAX_MS,+59.6 ms 线上 <205 ms
  屏板放弃线)保底发旧帧,"一召一答"契约不破;线忙时同旧丢单、
  不留扣件。起发两中断源(USART1 IDLE/TIM3)共用 sb_tx_kick,
  "判忙→占位"在 PRIMASK 临界区原子完成。
- ui_task:排空注键挪到组帧之前,注键→即派即绘→组帧同拍闭环;
  组帧返回 BSP_OK 才交重绘凭据(BUSY 拍帧还没反映按键)。
- ui_port:注键单槽改 8 深环(连按不再互相覆盖,满丢最旧+计数);
  新增 ui_port_service_keys:同拍 lv_indev_read + lv_refr_now,
  省掉 indev ≤20 ms + 刷新 ≤20 ms 两段等待。
- ui_menu_view:菜单移动选中只失效新旧两行带(黄金参考零像素变化),
  滚动/异常回退整框失效。
- simulator:窗口循环 sleep 扣除本轮已耗时(原先无条件睡满
  lv_timer_handler 返回值,叠加 Windows Sleep 15.6 ms 粒度放大观感)。
- 串口 TX 上报新增 dfok/dfold(凭据放行新帧数/超时保底旧帧数):
  dfold 连涨 = uiTask 被饿 ≥140 ms 的直接现场证据。

验证:test/host/sb_link 164/164(新增 18 条:不立刻起发/凭据放行/
140 ms 截止保底/忙时不留扣件/陈旧凭据不放行等边界);菜单 8 状态 +
内容页 66 张黄金像素 PASS;Keil @build 0 错误 0 警告(两次);
BOM 99 文件无漂移、代码规范、doc-links 本次文件零问题、cppcheck PASS。
文档:屏板规划文档已被主干收编进设计说明,延迟账本落
docs/子系统设计/屏板链路设计说明.md §7.1,并同步 §4 口径、§8 接口、
§9.1 单测台账 146→164、§10 坑账本补条。

RAM 台账(分支不跑 --write,并行分支提交约定):本笔盖戳行
RW_IRAM1 94,336 B (72.0%) / RW_CCM 57,376 B (87.9%),较上一台账行
+4,400 B——为距上次台账构建以来分支累计差(含批 3 状态灯等未盖戳
提交),非全部本笔引入;本次自身增量按对象计为 ui_port.o +12 B
(8 深键环+丢计数+indev 指针)与 sb_link/o 数十字节级。
gate: only mem-budget/mem-numbers pending lead ledger backfill
(合并落主干后 Lead 统一 --write 回填受管区)。
2026-10-30 09:50:31 +08:00
wandering1 36f6948544 merge: task/rrfix-rename-ref-dir-move 合入 v2-on-ui
任务 rrfix(1 个提交)经 task-worktree 回收:
- fix(scripts): rename_ref 搬整目录不再改脏目录内部内容,并补齐出链层级
2026-10-30 09:34:53 +08:00
wandering1 1221676272 fix(scripts): rename_ref 搬整目录不再改脏目录内部内容,并补齐出链层级
2026-10-30 测试说明分层那次(28 个路径、209 文件)实测踩到两条,都是
「把不该改的东西改脏」,当时的补救全靠事后从 git 里捞原始字节:

B1 整目录搬迁会改写目录内部文件的内容。「相对引用文件所在目录」这条
    解析规则不检验目标是否存在,于是台架日志里不是路径的斜杠片段被当成
    「旧目录下的子路径」并插上目录名:`1/1 PASSED` → `test_data/1/1 PASSED`、
    `13639/32768`、日期占位 `[----/--/-- --:--:--]` 全中招,连有效的
    `see ../a.md` 也被换成指向不存在的 `see td/a.md`。23 个证据文件是
    用 `git show HEAD:<旧路径>` 逐字节还原才救回来的。
B2 目录内部文件指向外部的 `../` 出链不补层级。emit_dir 取的是
    `new_abs.parent`,整目录搬迁时少算一层,`../images/x.svg` 搬深一层后
    仍指旧层级;图片按文档目录相对(§3.2),check_doc_links 看不见 → 静默断链。

改法(尽量小面):
- resolve_token:按引用文件目录解析时要求目标真存在;根相对写法保持原宽松口径。
- rewrite_text:moved 文件的 emit_dir 改成「本文件搬完实际所在的目录」;
  单文件搬迁走原分支,一字未动。
- 整目录搬迁时目录内部互为相对的引用一律不改(两侧一起搬,改了必错);
  「旧路径是不是目录」必须在搬迁前记进 old_is_dir_global——--apply 是先
  git mv 再改写,那时旧路径已经不存在了。
- glob 形态改成看得见:搬目录时前缀整体跟着搬(本来就该改);搬单文件时
  一条 glob 可能同时盖住搬走与没搬走的两批文件,不猜,只点名列出。
  分层那次有 4 处这种引用是静默漏改、事后手改的。

回归:新增 `--selftest`(在一次性临时 git 仓里跑本脚本的副本,`.gitignore`
先排除 /scripts/ 免得脚本自己进扫描面)。案例 A 守整目录搬迁(证据文件
逐字节不变、出链补层、别人文件的入链照改、glob 前缀跟着搬),案例 B 守
单文件搬迁的层级换算与 glob 提示,18 项断言全绿。反向对照也做了:同一
夹具在改前版本上 B1/B2 都复现,所以断言不是凭空写的。

文档同步:docs/文档规范.md §3.6 第 4/5 条从「现存危害」改写成「已修 +
验收判据」,新增第 6 条 glob 提示,并加「改本体必须先跑 --selftest」;
docs/测试说明/README.md 第 3/5 节口径同步;scripts/README.md 补 --selftest
与任务树 --no-verify 的用法行。顺带修掉分层那笔里我写错的日期:
2026-11-01 → 2026-10-30(文档规范 4 处、测试说明 README 2 处,真值就是今天)。

树内验证:AST OK;--selftest PASS;改动的 3 个 .md 单文件
check_doc_links --sections-strict RC=0(36 处章节引用、可判定 34、无法判定 0);
字节体检干净。未跑 @build(无 .c/.h 改动)。
2026-10-30 09:34:21 +08:00
wandering1 44596f1487 ci(体积凭证): 屏板链路合并后同码凭证更新(@build 0/0 后回填)
主干合并 add61ca2→899e4a6b 后代码 blob 指纹变化(仅注释与文档改动,
Code=246,160 B / RW_IRAM1=94,312 B (72.0%) / RW_CCM=57,376 B (87.9%) 均无增量)。
2026-10-30 09:30:07 +08:00
wandering1 8f5ac7f5d0 chore(台账): 合并后刷新体积同码凭证(代码内容变了、体积未变)
done testdoc 的门禁跑在 @build 之前:这笔合并把 20 个 .c/.h 的注释与文档
路径一起改了,索引指纹由 1ed4267c77f6 变成 172c6c78b8fb,而凭证仍记着
01:15 的那次测量,size-gate 因此报「不同码」。合并后 done 自己跑的 @build
是 0 错 0 警,Program Size 与合并前逐项相同
(Code=246160 RO-data=29816 RW-data=2036 ZI-data=149700),
数字没动,只按脚本自己的提示跑 ram_baseline.py --update 重写凭证。

复验:check_size_gate.py --local rc=0(同码 ✓ 受管区 ≤92% ✓);
主树全库 check_doc_links.py --all rc=0(215 个文档 / 2993 处章节引用)。
2026-10-30 07:22:20 +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 fea4cc7502 docs(架构): 项目架构总览全局更新——同步录波/SOE/屏板并订正串口归属
v1.1(2026-10-14)之后主干前进 59 笔,本总览积累系统性偏差,通读全文后
全局更新(含配图生成器数据同步):

- 串口三分定态:USART1=屏板链路 700 kbaud、UART4=RS-485(B2 未接线)、
  UART5=控制台日志 115200(console_log CON_UART=huart5 实证;
  旧文把 USART1 标成调试口是屏板批 0 迁移前的口径)
- 采集主线补齐:adc_cal 标定折算、meas 200ms 遥测快照(adcTask 唯一
  发布者,104 与 UI 共用同一份上游)、录波环三任务交接(adcTask 写入
  冻结 / defaultTask 游标落 /wave / uiTask 单通道回放 / FTP 取回)
- SOE 事件记录链路入图:protectTask 动作/复归边沿投递(纯 RAM 队列)
  → defaultTask 经 syslog_drain 尾部落 /log/soe.log(64B 定长)
- 配置从 [network] 单段改五段注册制(+ftp/adc_cal/run_par/comm),
  另有 /prot_set.bin(B7 原子写)
- UI 一节按注册表驱动重写:菜单树 61 行、16 个 #P 受保护叶、26 个
  #page 绑定、ui_data 三帧契约(写侧唯一填充 ui_data_feed)、录波
  两页、显存一份三出(屏板主出口/:7003 镜像/模拟器)
- §2.1 任务表按 freertos.c 现值逐行核对;protectTask 如实标注
  「未标定闭锁」现状(产品 required_mask 0x1F7)
- 配图:gen_arch_svg.py 顶部数据(层芯片/串口/删悬空图脚注)重跑,
  脚本与产物同一笔提交;check_generated_fresh.py 按「只减不增、
  还清即删整条」把本次还清的 项目架构总览.svg 基线下架(留出处注)

验证:check_doc_links --all --sections-strict 通过;scripts/ci_local.py
全绿;generated-fresh 单跑 rc=0(无 DIFF/NEW);SVG 无头渲染回读目检
两轮(首轮揪出悬空图脚注);md 无 BOM/CR/U+FFFD;#P 计数剔注释行复核。
2026-10-30 06:53:07 +08:00
wandering1 2533a72a0a chore(台账): done 后重生成凭证,对齐合并态 .map
CI / 静态门禁 (pre-commit) (push) Failing after 44s
CI / 主机侧单测 (MSVC) (push) Failing after 43s
2026-10-30 01:15:07 +08:00
wandering1 b4588108ed merge: v2-on-ui into task/screenlink-bench-serial (wave + screenlink) 2026-10-30 01:08:37 +08:00
wandering1 0b84c43d2e feat(屏板): 状态灯位映射 sb_led_map + 104 RUN 观测口(批 3);附 4-1 并发压测脚本
批 3(LOGO 按用户裁定出局,不实现、sb_proto 的 LOGO 组帧挂待删标注):
- 新增 App/algo/sb_led_map.c/h:业务状态 → 屏板 LED 位掩码的唯一映射表
  (纯逻辑,主机单测可跑)。ID1 运行心跳 500ms 半周期闪(与主板 LED 同拍)、
  ID2 保护动作、ID3 104 链路 RUN、ID4 采样电平故障(不选 sticky——灯要能灭)、
  ID5 保护启动 picked;bit0 与 ID 6~19 恒 0。这张表参考源码里没有,属自定,
  出处 docs/产品需求/产品需求设计文档.md §5.16.3 ①。
- iec104_serv 新增 iec104_serv_link_run()(透传 link 状态机,不另存镜像量)。
- ui_task.c 帧组装块每拍现采四路状态源(均为任意上下文可读观测口)折算后
  传 sb_link_frame_update——替换批 2 的恒 0 占位;掩码变了帧就重组,
  复用 busy/dirty 机制,无新通路。
- 主机单测 test/host/sb_led_map 17/17(位语义/恒零位/闪烁相位/tick 回绕/
  NULL 契约);注册豁免走 SIM_EXEMPT(模拟器无屏板串口)。

批 4 的 4-1 双通道并发回归(真屏板在线实测):
- 新增 test/host/remolcd_pull_test.py:RemoDispBus 拉帧压测客户端
  (INIT→LCDMEM 10 Hz、逐帧 XOR+长度校验、往返延迟统计、--dump PBM)。
- 实测:网络侧两轮 2200 拉帧零错零超时(min 35/avg 63/max 131 ms);
  屏板侧 60 s 隔离窗口 rx +233 全收、drop 零新增、bad=0、off=0、无
  OFFLINE——两侧互不拖。观察项 len=7(断帧尺寸≠6,累计 7 次)出现窗口
  无法归因压测、隔离窗口零新增、有效帧零损失,已挂设计说明 §5.7 待查。

附带:sb_link.h frame_update 注释回填实测耗时(509/688 µs 取代旧估算)。
Keil 0 错误 0 警告;ci_local 全绿(SKIP=nested-comment,主树脚本另查 0 新发);
Code=239,064 B / RW_IRAM1 65.5 % / RW_CCM 87.9 %;覆盖率 90.1 % / 44 套件。
2026-10-30 00:39:57 +08:00
wandering1 98d46e626d fix(内存台账): subsystem_of 补齐 12 个 App 对象前缀并加未归类兜底
按台账 §2「应用 = App/ 其余」自家口径重算归集。此前 wave_、iec104*、
soe_、meas、freq、run_par、protect_task、task_prof、boot_stats、
vol_idle_sync 都不在前缀表里,12 个对象 9,445 B 静默落进「其它」(参考
行、无配额),配额 8 KB 的「应用」行看不见录波与 SOE 支路。补齐后
应用 16,888 → 26,333 B、其它 15,849 → 6,404 B;区域水位与 92% 红线不变
(台账受管区已 --write 回填)。

兜底:App 下的 .c 编出的对象只要落进「其它」,--gate 就逐条 WARN 点名
(软提醒不拦)—— 下一个新增 App 目录不会再静默隐身。台账 §2 口径表、
应用条目、变更记录与 内存内容分配策略 §6 那条「本卡不动,已报 lead」
同步改口。
2026-10-30 00:19:15 +08:00
wandering1 20617a33f7 docs(编号规范): 编号一律停发——§4.1 五族也不再发新号,只读存量
用户裁定(2026-10-29):「啥号都不发」= 任何族都不再新增编号,
含 §4.1 那五个原本"有脚本按字面量匹配"的存量族;既有号只读引用,
族里新增内容一律写语义行名。

规范本体:
- §1 由「先问三句」改成「默认答案:不发号」,三问表换成场景对照表;
- §4.1 由「允许用号的族」改成「存量族」,第四列改「既有号被谁读 /
  新写怎么办」,逐行写明新写怎么做(TRAP 写语义行名、FR 用 §5 行名、
  CODE-RULE / MENU-STATE 先问用户、P-n 只读存量页号);
- 末框四条对照 + 唯一例外入口(确需机器按字面量匹配 → 先问用户);
- 新增族 = 一律不许;批准后顺序:本文 §4.1 → 属主文档 → 才动 registry。

跨文件同步(12 份):门禁说明 id-check-new / id-check / host-unit-tests
(把"校验 5/3 拦新号"这类现状叙述历史化)、两份 TRAP 记录的编号口径、
开机账本用例号说明、AGENTS 两处、id-family 技能与其 steps-alpha 模板、
归档 README 与两份归档脚本 docstring。

AGENTS 主题表那行原写「允许用号的 7 个族」,与规范的 5 行本就对不上,
旧计数一并消掉。

未做:pre-commit 的 default_stages 一行——用户对该项未置可否。

验证:py_compile 与 check_ids_new.py --self-test 均 rc=0;逐篇
check_doc_links.py --sections-strict rc=0(编号规范 70 处引用 /
68 可判定 / 无法判定 0);13 份改动文件表列数与字节体检相对基线零新增。
2026-10-29 21:31:42 +08:00
wandering1 dab0d8ba17 feat(屏板): 帧 B 组帧 + 中断起发 TX DMA + 按键队列 + 离线判定(批 2)
批 2 五项全部落地(docs/任务规划/屏板链路.md §3):
- 2-1 sb_link_frame_update():uiTask 渲染后按需组帧,不留 3200 B 影子
  副本,直接拿活显存与帧内点阵段 memcmp;组完自校验,过了才置 ready。
  静态 4208 B 帧缓冲实测落 RW_IRAM1(0x20006d98),不在 CCM。
- 2-2 空闲中断校完 6 B 召唤帧直接点 TX DMA(sb_tx_kick),不排队不攒批;
  busy 期间再来的召唤丢帧并计数,绝不叠发(屏板收帧一次 IDLE 一包)。
- 2-3 按键走环形队列(中断入、任务出),uiTask 按 §4.3 表映射 UI_KEY_*
  后调 ui_port_queue_key;9/10(RESET/FACTORY)按决策四先丢弃并留痕。
- 2-4 HAL_UART_TxCpltCallback 在 rs485.c 加第三行转发(三个全局回调
  落点收一处,防日后重复定义);busy 冻结帧缓冲,错误中断按 gState
  收拾被打断的 TX,防残留 busy 把链路永久锁死。
- 2-5 连续 >=10 s 无有效召唤帧才判离线(不按 500 ms——屏板约 5000 s
  自复位有 1 s 空窗),恢复即清标志;CRC 错帧静默丢弃并计数。

实测:台架 40 s(PC 顶替屏板,--key-fixed 2 持续改画面)rx=143 ok=143
keys=143 crc=0 / tx=143 done=143 drop=0 abor=0 fb=144 bad=0;脚本一停
10 s 准点出 OFFLINE。组帧耗时 509 µs 典型 / 709 µs 峰值——原 0.3 ms
判据系估算,已按实测在规划文档改口为 1 ms 并给出压降路径(未做)。

附带:rs485_on_rx 补 CODE-RULE-09 文档块(本轮改 rs485.c 触发整文件
重扫被拦);CRC 循环计数改 32 位(消掉 ARMCC 每轮 UXTH);bench 脚本
加 --reply/--key-fixed/--dump,并写明 CH340 收不了 700 kbaud 连续流、
--reply 收不全 4208 B 不是固件问题。

主机单测 146/146 PASSED(+65);Keil 0 错误 0 警告;ci_local 全绿
(SKIP=nested-comment,worktree 限制,主树脚本另查 0 新发)。
Code=238,936 B / RW_IRAM1 65.5 % / RW_CCM 87.9 %。
2026-10-29 20:59:36 +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 7c8669e52a feat(屏板): USART1 700 kbaud + 收中断传输层 sb_link(1-2/1-3)
批 1 的 1-2 / 1-3:把屏板(DTU-LCD)发来的 6 B 帧 A 在 USART1 上稳定收下来。

1-2 波特率:.ioc 不保存任何 UART 的波特率(只有
USART1.IPParameters=VirtualMode),GUI 里改也不落盘,所以只能在
Src/usart.c 的 USER CODE BEGIN USART1_Init 2 区覆盖 huart1.Init.BaudRate
后重调一次 HAL_UART_Init(第二次调用时 gState 已非 RESET,HAL 只重算
BRR、不再跑 MspInit,GPIO/DMA/NVIC 不会被重配)。开机日志实测
BRR=0x0078,与理论值 84 MHz/(16x700 kHz)=7.5 逐位相符,误差 0%。

1-3 收中断:新建 Drivers/BSP/ScreenLink/sb_link.c/h——16 B 缓冲 + IDLE
中断断帧、帧 A 校验、错误中断里按 RM0090 清 ORE/NE/FE/PE、周期统计上报。
HAL_UARTEx_RxEventCallback / HAL_UART_ErrorCallback 是全局单例(唯一实现
在 rs485.c),故只在那里各加一行转发,按句柄过滤放在 sb_link 内。

台架实测(PC + USB 转 TTL 顶替屏板,COM6@700000)撞出两个真问题:
- 错误回调里无条件重挂 -> 出现 err=160 / rearm=160 同步增长,看着像每帧
  都重挂失败。真因是 HAL 把 NE/FE/PE 归为非阻塞型(接收照跑、RxState 仍是
  BUSY_RX),此时 ReceiveToIdle_IT 只会返回 HAL_BUSY。改为仅当
  RxState == HAL_UART_STATE_READY(ORE 那类阻塞型)时才重挂。
- 日志字面量里带中文 -> ARMCC #870-D invalid multibyte character
  sequence。字面量一律纯 ASCII,中文只写注释。

验证:主机单测 81/81 PASSED(test/host/sb_link/,其中按 RM0090 的清除语义
把"必须 SR->DR 顺序才清得掉 ORE"钉成断言);Keil 0 错误 0 警告;台架
rx == 发送帧数、ok == rx、crc=0、len=0、size=6、keys 随按键帧递增;先用
错波特率灌 64 B 垃圾(len=31、bits=0x06)后自动恢复且 rearm=0。
新增 test/host/screenlink_bench.py 作为可复跑的屏板激励(--key / --glitch-baud)。
2026-10-29 20:13:18 +08:00
wandering1 5c64cf0859 merge: task/criteria-462-fix 合入 v2-on-ui(§4.6.2 判据写定 + 编号白名单登 WAVE)
两笔内容提交:05664051(判据四处改写 + 手册侧九处去对照语气)、
9fe8f854(KNOWN_BARE 登记 WAVE 段文件名前缀,自检 5/29 全过)。
与 557f1d04 的计数同步零文件交集,纯文档 + 一行白名单,未跑 @build。
全程未 push。
2026-10-29 20:06:03 +08:00
wandering1 9fe8f8545d gate: 编号门禁白名单登记录波段文件名前缀 WAVE
scripts/check_ids_new.py 的 KNOWN_BARE 加 WAVE(附两行注释说明来源:
App/algo/wave_store.c 拼名、FTP 根下 /wave/、100 个号轮转)。
此前文档里写段文件名只能改成 WAVE<NN>.BIN 绕开裸形态,登记后按字面写。
classify_bare("WAVE00") 由 fail 变放行,--self-test rc=0(5 正例拦下 /
29 反例放行,FOO99 仍 fail)。

docs/门禁说明/id-check-new.md §7 表加一类"固件生成的产物文件名",
并提醒先分清产物名与编号族——加白名单是唯一放宽手段,没有整库豁免入口。
2026-10-29 20:05:43 +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 16048140fd chore(体积): 重盖同码凭证(sb_proto 进索引)
上一条提交漏带 scripts/size_attestation.json。指纹按 git 索引内容生成,
sb_proto.c/h 进索引后指纹从 bfe075e7 变为 df1c01ab,凭证不跟着走就会
判"不同码"。

Code=236,460 B 不变(新模块尚无调用者),RW_IRAM1 81,536 B / RW_CCM
57,376 B 均未动。
2026-10-29 19:17:56 +08:00
wandering1 b25d70e962 feat(屏板): 协议层 sb_proto(帧 A 解析 / 帧 B 组帧 / CRC-16)
批 1 的 1-1:新建 Drivers/BSP/ScreenLink/sb_proto.c/h,纯逻辑、无 HAL 依赖,
可主机侧单测。屏板侧的协议事实源是 DTU-LCD 的 CRC16.c / MODBUS.c / rs485.h。

- CRC-16/MODBUS 用一张 16 位合并表(512 B,与屏板两张 8 位表同量)。可逐项
  验证的关系:s_crc_table[i] == (auchCRCLo[i] << 8) | auchCRCHi[i]——屏板把
  低字节表叫 Hi、高字节表叫 Lo,这正是下面那个字节序陷阱的根源。
- 帧 A 解析:先校 CRC 再看字段。地址/功能码/命令类型不符报 BSP_ERR_PARAM,
  CRC 不符报 BSP_ERR_CRC(调用方据此决定"计数"还是"静默丢")。RT_CMD 带
  非 0 key 不报错、按 0 收——为这一项丢一帧等于丢一次刷新,代价不对等。
- 帧 B 组帧:普通图(掩码小端)+ LOGO(宽高大端 + 魔数 0x89 0x45),整帧
  4208 B 重写(998 B 填充固定 0x00 且参与 CRC),组完即自校验。
  LOGO 容量按字节数判(((w+7)/8)*h <= 3200)而不是像素数:161x159 只有
  25599 像素,却要 3339 B 才装得下。
- 主机单测 59/59 PASSED(test/host/sb_proto/),覆盖率 74/74 行、6/6 函数。
  其中两条向量是屏板自己算出来的线上字节(01 03 01 00 F0 48 与
  01 03 00 09 31 DE),并按屏板 Check_CRC 的口径反查"它会认这一帧"。
- 双端注册:uvprojx 加 File + IncludePath;模拟器侧走 check_registration.py
  的 MCU-only 豁免(纯逻辑,模拟器无消费路径)。
- Keil 构建 0 错误 0 警告;Code 不变——尚无调用者,链接器按未用节丢弃。

文档侧的 CRC 字节序订正见下一个提交。
2026-10-29 19:17:28 +08:00
wandering1 f5161e1567 feat(日志): 控制台迁到 RS232#1/UART5,USART1 让位给屏板链路
批 0 的第 2 项。USART1 是唯一 MCU 引脚直出的 TTL 通道,700 kbaud 的屏板
链路要用它,控制台必须先让开。

console_log.c 加一处端口收口块,换口只改这一段:

  CON_UART / CON_UART_IRQN / CON_UART_CLK_DISABLE/ENABLE / CON_UART_INIT

代码实际改动 4 处:con_tx_bounded 的 huart1.Instance(NULL 判据、counted
回退、赋值)与 con_uart_reinit 全函数体。其余是把描述当前行为的注释里的
USART1 换成「控制台串口」;历史变更记录(2026-10-02 / 10-24)里的 USART1
保持原样,那是当时的实况。

注意事项:UART5 在 APB1、USART1 在 APB2,时钟宏不能照抄;
__HAL_RCC_UART5_CLK_ENABLE 定义在 stm32f4xx_hal_rcc_ex.h。

不改 UART 模式(2026-10-26 裁定:保持 UART_MODE_TX_RX,不动 RX 配置)。
MX_UART5_Init 在 Src/main.c:135,比 MX_USART1_UART_Init 晚几个初始化调用,
该窗口内的日志由 CON_UART.Instance == NULL 短路接住(记 dropped,不崩)。

构建:Code=236,460 RO=28,124 RW=1,876 ZI=137,084(Code 较迁移前 +4 B)。

台架验证(COM3 @115200,RS232#1 经 CN1.10/CN1.12):
- 烧录回读 no difference found;8 个 required 锚点全中,无 forbidden;
  启动到 net init: OK 用时 661 ms
- 连续 10 分钟长稳:1218 行,零 [ERR]、零 dropped、零 tx_fault,
  末行仍在正常 PROF 输出
- USART1 已无任何控制台写入(全文件 grep 只剩历史注释)
2026-10-29 18:45:59 +08:00
wandering1 0c8fb5e1b6 chore(体积): 合并后重盖同码凭证(指纹 d9848eb1,体积零变化)
X-20261029 合入 v2-on-ui 后体积门禁报「不同码」,原因是凭证按 git 索引
blob 计算指纹,纯注释改动也会改变文件哈希,尽管链接产物一字未变。

@build 已在合并提交 c51ac2e8 上跑过 0 错误 0 警告,.map 为 17:50:23 的
产物、晚于最新受管源码,前置条件满足,故按门禁自身给出的修复路径重盖:

  ram_baseline.py --update

check_mem_numbers.py --write 与 ram_baseline.py --write 均报「已是最新」,
tsv 今日行数字相同未变,本次只改凭证四个字段(fingerprint / built_at /
git_head / map_mtime),sizes 与 pct 保持原值:

  Code=236,456  RO-data=28,124  RW-data=1,876  ZI-data=137,084
  RW_IRAM1 81,536 B (62.2%) / RW_CCM 57,376 B (87.9%)

check_size_gate --local 现已通过:同码 + 受管区 <= 92%。
2026-10-29 17:52:33 +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 db5109e41d chore(size): 重打体积同码凭证——补上一笔注释收尾提交的同码缺口
@build 0 错误 0 警告之后跑 ram_baseline.py --update:新增 2026-10-29 趋势行,并由它
自动 --stamp 重打 scripts/size_attestation.json。

数字与 2026-10-28 那行逐项相同(Code 236,456 / RO 28,124 / RW 1,876 / ZI 137,084;
RW_IRAM1 62.2%、RW_CCM 87.9%,红线 92%)——所以缺的不是体积变化,是"这份源码对应
一次真实链接"的同码性:上一笔收尾提交改了保护任务源文件(纯注释)却没有重测,凭证
自那次起一直红着,主干 push 会被它拦下。

现在 check_size_gate --show 与 --local 均判同码通过;本地 CI(含体积步)全绿。
2026-10-29 07:50:33 +08:00
wandering1 21c68521ff feat(task-worktree): 桥接 DSH worktree 插件——补共享联接、锁归属 pw:<name>、修释放不掉
诉求最初是升级 dsh-task-worktree:实测已装 0.4.6 = npm dist-tags.latest,无需升级;
真正的缺口是本仓 skill 看不见插件建的树(.dsh-worktrees/),故按用户追加指令把两套
系统接起来。回收方向刻意不打通:本 skill 永不删插件的树。

脚本 task_worktree.py:新增 plugin 子命令 list/adopt/unadopt,事实源是 git worktree
list(不是插件 manifest,免得被绕过);adopt 只补缺失的 .venv 与 simulator/SDL2
联接,已有联接跳过、实体目录绝不碰;锁归属用 pw:<name> 前缀;new 顺带提示另有 N 棵
插件树、不占活跃上限 3。
一并修一处真 bug:lock release --bench-pass 在任务无台账时先 EnvError 退出、锁释放
不掉,导致每个任务的 done 收口连坐失败;现在改为警告后仍然释放。

keil-build:default_lock_task() 增加 .dsh-worktrees/ 反推分支,插件树内的构建归属
pw:<name> 而不是兜底的 build-cli(主树行为未变,本次 @build 实测仍走 build-cli)。

.gitignore 预先忽略 .dsh-worktrees/,让插件的 ensureIgnored() 找到同一字面量、不再
改写这份受控文件。check_doc_links / check_layer_deps / gen_refgraph 三处扫描面同步
排除:仓里再放一份仓会让 doc-links 假红、并让生成的配图字节漂移到 generated-fresh。

文档:并行任务工作树方案新增 §3.4 两套系统边界对照;SKILL.md 加 §F 共存一节,同时把
§B 从 53 行压到 29 行(净 +39,用户此前在飞的改写已 rebase 保留、未被覆盖)。

验证:@build 0 错误 0 警告;scripts/ci_local.py 48 根提交期钩子与 gitlint 全绿;
check_doc_links --all --sections-strict 通过(2596 章节引用、无法判定 0);id-check-new
通过;改动文件字节体检无 BOM、CRLF 与 U+FFFD。桥接行为在临时 scratch 仓端到端跑过
(adopt 建两个 reparse、unadopt 只摘联接、pw 锁取放、缺台账也能释放、越界 name 退 2)。
2026-10-29 07:50:05 +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 e9cae5fdcd chore(size): 重打体积凭证(合树后同码 @build 0/0,数字未变)
前面几笔(含并发会话那两笔)改动了在册文件,凭证指纹还停在 21:41 的
索引上,体积门禁因此报「代码与测量不同码」。现在按合树后的状态重打:
@build 0 错 0 警,Program Size Code=236456 RO=28124 RW=1876
ZI=137084,与 scripts/ram_baseline.tsv 的 2026-10-28 行完全一致,
所以台账不追加新行(ram_baseline.py --update 自行判定同码不重复登记)。

check_size_gate.py --stamp / --local 均 rc=0。
2026-10-28 22:24:33 +08:00
wandering1 94cce8b615 docs+scripts: 删除测试与架构专项文档并把引用改成就地口径
这是并行的另一路在飞的改动(本会话按用户「全部提交」指示代为落盘):
移除 docs/任务规划/测试与架构专项.md,并把指向它的引用改成就地口径
(app_assert.h / net_socket.c / ch395f_test.h 头注释改指本文件注释或
对应文档,check_size_gate.py 与 ram_baseline.py 的出处改指 CI 文档,
RAM预算台账、暂缓-RS485、采集与算法层设计说明、cubemx-survival、
id-check、两份 README 同步改引)。

如要拆回:git reset --soft HEAD~1 即可把这一笔退回工作区。
合树后 @build 0 错 0 警(Code=236456 RO=28124 RW=1876 ZI=137084)。
2026-10-28 22:00:34 +08:00
wandering1 511fd30cc6 docs: 清理全仓变更记录流水(43 篇整节删 / 23 篇留一行 / 5 篇保留)
用户裁定:文档只写现状,历史流水一律删掉,过程查 git log。

- 43 篇「变更记录 / 修订记录」整节删除:继电保护规划 12.6 KB、产品
  需求 11.8 KB、项目部署环境 5.5 KB、BSD Socket 指南 5.3 KB、架构
  总览 5.0 KB、实机测试实施指南 3.8 KB 等
- 23 篇别处仍有指向:只留节名 + 一行「本文件不再记流水账,过程查
  git log」,节号与锚点不位移(doc-links 不因此断链)
- 5 篇整表保留(被当唯一证据 / 活台账引用):看门狗设计说明、配置
  文件设计说明、RAM预算台账、内容页架构、本地工具路径环境变量方案
- 规范同步:文档规范 §5.1 改新裁定;测试文档模板规范删示例节与
  登记句;测试开发标准流程 / UI 两篇 / 实机测试实施指南 / 四篇单测
  说明 / 并行任务工作树方案 / 编号规范 的「登记变更记录」改「写进
  正文」
- 技能同步:stale-doc-count-sweep / ui-verify / id-family 三个 SKILL
  正文不再要求追加流水行(顺带消掉 SKILL.md:121「产品需求 §12」
  失效引用)
- 修 5 处悬空指针:采样有效性校验目录锚点、BSD 指南「文末变更
  记录」、docs/README 过期描述、网络自愈架构两处指向面

72 篇文档净减 600 余行;check_doc_links --all --sections-strict 可判
定比例 61% → 78%、失效引用 0;静态门禁 passed=50 failed=0;gitlint
10 条历史提交信息 0 failed。

未提交他人在飞改动:.dsh/skills/keil-build/*(%SystemDrive% 守卫)。
2026-10-28 22:00:34 +08:00
wandering1 8f8d97b3d8 docs(编号): 批次六余账文档面——CubeMX 层号、双写疤、采集链旧层名共 61 站点
CI / 静态门禁 (pre-commit) (push) Failing after 8m4s
CI / 主机侧单测 (MSVC) (push) Successful in 27s
- CubeMX 防丢失三层优先级 L1/L2/L3(批次 3c 漏网 30 处):看门狗设计说明 25、
  门禁说明/cubemx-survival 3(含「优先 L1/L2」→「优先写进 .ioc 与搬进 USER CODE
  区」)、ADC通道映射 2。
- 改名遗留的中文重叠双写 14 处:菜单页面设计「一级菜单菜单」×6、「二级菜单菜单」
  ×2;README「语义取数与有效性」重复;存储架构「3字节字节地址」;链路延迟
  「队列往返队列往返」;继电保护「出口出口与记录层」;产品需求「全周傅氏相量」重复。
- 采集链旧层名 5 处:「L2 相量层」→ 全周傅氏相量、「L0 采样驱动」→ 采样驱动层、
  「L2-x 前缀」→ 相量输出标签前缀、「L1 层 v2.3」→ 语义取数与有效性层 v2.3。
- UI 菜单层级 2 处:产品需求「4 级(L0~L3)」→「4 级(主界面 / 一级 / 二级 /
  三级菜单)」、「主界面 (L0)」→「主界面」。
- 登记簿条目改名「L5 队列往返基线待重验」→「队列往返基线待重验」+ 引用侧 5 处
  同步(登记簿 §1/§7、实机测试实施指南 §7.3 与步骤表、编号规范 §1 好例子清单——
  那个混在短语里的 L5 恰恰是个坏例子)。归档里的历史 note 原文不动。
- 归档 §10.3:四族收口记录 + 边界与裁定(peer JSON 键属冻结证据 schema 不改;
  REQ2FIRST / FULLFRAME 不并入 FRAME_RT;L1-3/L1-4 属不可还原死号,就地删号留
  事实;「原 L2 基线 3/10」按上下文读作主机侧回归的早期基线)。
- 判族保留(永久):硬件位号与封装尺寸 27 处(网表 L1~L3 磁珠电感、
  SOT-23_L2.9-W1.3、CRYSTAL-L3.2)、芯片手册原文 3 处双写;伪命中 4 条没删
  (「遥测量 测量值」「已登记登记簿」「谁来监视监视者」×2)——那些是正常词组。
- 门禁:check_doc_links --all --sections-strict 通过(195 篇、章节引用 3292 处);
  git diff --check 干净;逐文件 BOM / U+FFFD / CRLF 与 HEAD 一致。
2026-10-28 18:57:03 +08:00
wandering1 da36f4ba56 refactor(编号): 自愈层号与 timeSync 挂起、CubeMX 三层、采集链层名清号(代码面)
批次六余账之二(代码与脚本面)。四族都是「批次一 / 三c 改了文档、漏了代码」的半改
状态。

- 日志自愈:「L1 文件级自愈」→「文件级自愈」、「L2 错误去重」→「错误去重」(正文
  本来就这么叫,层号纯属多余):App/log/soe_store.c、sys_log_mcu.c 三处、
  test/host/sys_log_mcu 的测试与假件头共 10 处。
- timeSync:「L3 pending 化」→ 挂起请求 / pending 化——这条口径早写在记忆里,
  今天才算全仓一致。App/sync/time_sync.c 3 处。
- CubeMX 防丢失三层优先级:scripts/check_cubemx_survival.py 6 处「由 L3 升级为
  L2」「L2 受保护」「L3 兜底」→ 写进 .ioc / 搬进 USER CODE 区 / 审计兜底;变迁史
  句子按「换号留事实」改写、日期原样保留。
- 采集链旧层名:App/README.md「采集与算法层(L1/L2/L3)」→「采集与算法层」;
  protect_task.c/.h「(L3 板端接线,B5)」→「(板端接线,B5)」。
- phasor 断言文案 19 处:改为 ASCII 的 phasor-in ring(C 字面量必须纯 ASCII)。
  改前先证明这些串无耦合——全仓只有本文件含它们、harness 只看 returncode 与汇总
  标记;改后 phasor 57/57 与基线同数。
- 零行为:剥注释 + 套登记表后与 HEAD 逐字节 / AST 相同;sys_log_mcu 141/141、
  phasor 57/57、watchdog 47/47、freq 46/46 均与动手前基线同数。
- 同一四族的文档面(CubeMX 30、采集链 5、菜单层级 2、双写 14)由下一笔收。
2026-10-28 18:52:37 +08:00
wandering1 842d711ed6 refactor(编号): 测试验证层级去号——CI job / 门禁输出 / 命令行旗标换语义名 + ASCII 段名
用户裁定「我不想看到编号」。测试验证层级这一族的整族清退分三道并行:本笔是**代码与 CI 道**
(CI 步骤与门禁输出面),代码注释面另走、文档面由文档道走。

口径(旧 → 语义名 → ASCII 段名,段名只进日志/旗标/job id/文件名):
  L0 静态门禁 static | L0a 钩子解释器预检 preflight | L0b 提交信息门禁 commitmsg
  L0c 体积门禁 size | L0.5 主机侧纯逻辑单测 host-unit | L0.5c 覆盖率 coverage

- scripts/ci_local.py 43 站点:段标题与 [SUMMARY] 标签改 ASCII 段名(static: /
  host-unit:),函数 run_l0/run_l05 → run_static_gates/run_host_unit_tests,
  收尾「已跑:」列表用段名。旗标改 --static-only / --host-unit-only,**旧旗标
  --l0-only / --l05-only 保留为 argparse 别名**(肌肉记忆与既有脚本片段不断档,
  实测 --help 两名列出)。
- .gitea/workflows/ci.yml 42 站点:job id l0-gates → static-gates、
  l05-host-unit-tests → host-unit-tests;步骤名与 step-summary 标题改语义名;
  日志名 l0-pre-commit.log → static-pre-commit.log、l05-<模块>.log →
  host-unit-<模块>.log;::error::/::notice:: 文案同步。yaml.safe_load 核过
  两个 job id 与步骤名。
  host-unit-tests;步骤名与 step-summary 标题改语义名;日志名 l0-pre-commit.log →
  static-pre-commit.log、l05-<模块>.log → host-unit-<模块>.log;::error::/::notice::
  文案同步。yaml.safe_load 核过两个 job id 与步骤名。
- 门禁脚本 18 站点:check_registration(登记簿理由串 7)、check_test_coverage 5、
  README 8、check_generated_fresh 2、ram_baseline 2、check_size_gate 1、
  ci_find_python.ps1 2、ci_runner_bootstrap.ps1 2、.pre-commit-config.yaml 2、
  requirements.txt 1(保持纯 ASCII)。
- skills 7 站点:task-worktree(含 [SUMMARY] 样例两行)、mem-budget、ui-verify、
  task_worktree.py 的实跑标签。
- AGENTS.md 3 站点:CI 段「只跑静态门禁 + 主机侧纯逻辑单测」、自查命令段、
  「2026-10-11 静态门禁全灭」事件名。
- 归档:编号治理历史.md 新增 §10 换算表 + **撞族警示**(同形 L0/L1/L2/L3 还属 UI 设计
  令牌层 / UI 菜单层级 / 采集链 / 链路时延段 / CubeMX 三层 / 硬件位号与 FTP 应答字面量
  等六个族,其中 6 处在字符串字面量里,改了就是改行为——故全程只按行内置换、先判族)。
- docs/产品需求 §7.4 测试分层表:去号 + 顺带修掉上一批**错族替换疤**(该表 L1/L2 行曾被
  采集链层名「语义取数与有效性 / 全周傅氏相量」「保护判据」顶替,现按内容改写为板端测试
  套件 / 主机侧回归两行)。同文档 §1.5 G5 判据行同步。

门禁:ci_local --help 两面旗标并列;py_compile 7 个 .py 全过;yaml 解析通过;
check_ids_new --worktree rc=0;git diff --check 干净;17 个改动文件 FFFD=0、无 CR、
BOM 与原文件一致(含 requirements.txt 纯 ASCII)。本族无机器识别面(单字母+数字是
新增行门禁的自述盲区),口径来自自建逐行扫描器,复扫本族形态归零。
- 交接说明:文档道 teammate 在改 CI 指南时中断,剩余 9 处双写疤与 29 处 CI 标识
  (job id / 日志名 / 汇总行字面量)由 Lead 接手改完,逐处仍走断言式行内置换。
2026-10-28 17:46:52 +08:00
wandering1 dc214e1426 docs(UI): 内容页黄金参考当前态改报「60 张」,三数按双源实测同步
三数实测真值(每项两个独立来源互证):
- 张数 60:simulator/tests/ref/ 入库 shot_*.bin 实数 60 =
  check_content_pages.py 的 PAGES 条目数 60(id 逐一对齐)。
- 已绑 28 叶 / 未绑 5 叶:ui_page_registry.h 的 UI_PAGE_MAP_COUNT 28 =
  ui_menu_tree.txt 剔掉文件头注释示例行后的 #page= 实数(不剔是 29)。
- 字体 218 唯一字 / 313 字形:ui_cn_chars.txt 唯一码点 218(ASCII 区 0
  个,ASCII 0x20~0x7E 由生成器子集参数另计、不算进字数);
  ui_font_cn_12.c 的 .bitmap_index 条目 314 条含 notdef,剔掉 notdef →
  313 = 218 + ASCII 95。

口径更正(数字一律不动):当前态计数单位由「页」改报「张」——张数 =
页面个数 + 分页页多拍的第 2 屏(runreport_p2 / sparam_p2 两张),两个数
不许互相冒充。同日先前那行「53 → 59 页」是页面个数口径、与判据本体
不同源,原文冻结不回改,只在各文件变更记录末行追加当日更正。

历史一律冻结:变更记录里的 27 / 40 / 47 / 53→60 / 59 与字库 122/217、
179/274、185/280、183/278 都是当日快照,只追加、不回改。

夹带说明:.pre-commit-config.yaml 一并入本笔——pre-commit 要求配置本身
已 staged 才允许提交;该文件的改动是 ui-golden 显示名(60 页→60 张)与
一条钩子计数口径注释(同日 51 → 52 → 51 净零,属另一类,已在此点名)。
2026-10-28 15:33:42 +08:00
wandering1 593c5d0c84 refactor(编号): 采集链分层 L1/L1.5/L2/L2.5/L3/L4/L5 → 语义名(批次 1)
用户裁定(2026-10-28):L1/L1.5/L2/L2.5/L3 这套层号「谁能看懂」,改用语义名。
映射(同一批定稿,含 L4/L5):
  L1   → 语义取数与有效性
  L1.5 → 标定折算
  L2   → 全周傅氏相量
  L2.5 → 测频与遥测快照
  L3   → 保护判据
  L4   → 出口与记录
  L5   → 动作留痕

实测规模:384 站点 / 62 文件(App/algo、App/task、test/host 六个套件、docs/算法、
产品需求、架构总览、启动顺序、ADC 采样节拍、IEC104 上行、采集短板评测、内存管理、
AGENTS.md、README.md、docs/README.md、.pre-commit-config.yaml 与 scripts 里的注释)。

改法(不是全局替换,逐模式有上下文规则):
- 先吃同位语再落裸词:L1 有效性校验 → 语义取数与有效性校验、L2 相量层 → 全周傅氏
  相量层、L3 保护 → 保护判据、L2.5 遥测快照 → 测频与遥测快照,避免「保护判据保护判据」
  这类重复(第一版就是这么坏掉的,已整体回滚重做)。
- .c/.h 只改注释:先把字符串字面量切出去(引号数为奇数的跨行注释按整行处理),
  C 字符串里的 L2-in ring 之类原样保留——AGENTS 铁律「字符串字面量必须纯 ASCII」。
- 层内条目号(L1-3 / L2-3 这类)**本批不动**,属批次 2;另外三族(UI 菜单层级
  L0~L3、链路延迟分段 L1~L8、CubeMX 防丢失三层)也不动,属批次 3。
- 顺手修的措辞:范围写法 L1~L3 → 「分层(语义取数与有效性 → 保护判据)」、
  CI 段「不含 L1/L2/L3」→「不含采集链分层」、目录地图里同一处并列表述。

验证:@build 0 错 0 警(Code=236456,与改前逐字节同尺寸——纯注释改动);
内存布局配图已按新脚本重生成(自检通过);doc-links --all --sections-strict 通过
(195 文档);mojibake / bom-guard / coding-standard / 新编号门禁自查 全 rc=0;
git diff --check 干净。
2026-10-28 13:04:02 +08:00
wandering1 89b6132c1f docs(编号): 瘦身——58 KB/473 行 → 22 KB/222 行,过程记录进归档
用户裁定 A 方案:这份文档的「规范体系」部分已随门禁退役而死,但四件仍活着的东西
只有这里写着——① §1 政策(默认不发号 / 先问三句);② §3.3 语义标识怎么写;
③ §4.1 族总表 + §4.1.1 已停发栏(现行门禁白名单的机器投影源头);
④ §4.4 这些不是编号(防把 YX15 / 元件位号当垃圾清)。再留 §5.5 销项、
§8 门禁现状与 §8.5 退役路线、§10 速查。

其余 16 节逐字搬进 scripts/archive/id_gate/编号治理历史.md(40 KB):
1.2 / 2 八条原则 / 4.2 / 4.5 / 6 模块码表 / 7+7.1~7.3 / 8.1 基线 / 8.3 批次 /
8.4 台账 / 9+9.1~9.3(含「数据可信」任务卡号换算表),以及原变更记录 17 行流水。
归档文件带「这不是现行口径」横幅 + 归档目录,写清哪些节对应哪段历史。

两处刻意的选择:
- 节号沿用旧编号、不重排——外部文档与脚本引的是 §4.1 / §8.5 这些号,重排等于
  制造一批假链接;文首加「本文范围」说明跳号去哪了。
- 文首那段「机器面才是事实源」改写:现行机器面是 check_ids_new.py 的两张
  前缀级白名单(KNOWN_DASH / KNOWN_BARE),旧的 registry / 别名表 / 八项校验脚本
  已随全库审计退役进归档,只在手工复查存量时才用。

引用重修(6 份文档、10 处):AGENTS 的 §9.3 换算表、数据可信 §9.3 ×2、
门禁说明 id-check 与 host-unit-tests、docs/README 的 §4.5、技能手册的 §9、
以及正文里 §4.2 / §4.5 / §8.1 / §8.3 / §8.4 / §1.2 的裸引用。

验证:doc-links --all --sections-strict 通过(195 文档);mojibake / bom-guard /
git diff --check 全 rc=0;新门禁 --worktree 自查通过;钩子数仍 51。
2026-10-28 12:51:17 +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 bf2a5c21b0 chore(id-check): 两根护栏转报告制——编号门禁减负第一步
背景(用户裁定 2026-10-28):语义标识已是默认形态,编号体系本身不再产生价值,
而门禁每次都花时间。实测拆账:单次运行只有 1.8 s,但 近 80 笔提交里 61 笔 改了
id_registry.json / id_aliases.json / check_ids.py / docs/编号规范.md;语料共 99 族
(78 族已冻结、8 族快照、21 族未冻结),registry 87.6 KB + 别名表 187 KB。
结论:贵在养语料,不在跑检查。故先摘掉语料审计的强制面。

本笔只做第一步(①②③ 路线见 docs/编号规范.md §8.5):
- 护栏 1(可判定比例基线)与护栏 2(不可判定引用绝对数上限)改为 只打印、不影响退出码;
  输出标签由 [比例] 改 [比例·报告],越线打 [报告] 两行并指向 §8.5。
  --update-baseline 保留(只用来把当前值记成新记录基线)。
- 校验 1~6 不动:台账外新账照旧拦提交,这是本次减负的边界。
- 同步改口径文档:docs/编号规范.md §8 表与 §8.1 护栏行 + 新增 §8.5 退役路线,
  docs/门禁说明/id-check.md §1 表 + §6 限制第 7 条 + 新增 §7.6.1,AGENTS.md 门禁段,
  id_registry.json 两条 note,各加一条 2026-10-28 变更记录行。

自证(实测):
- 把 decidable_ratio_baseline 临时改 99.9、undecidable_total_ceiling 临时改 1 →
  两护栏必然越线,实跑 退出码 0,只出 [报告] 两行;字节级还原 registry 后复跑正常。
- 反向自证牙还在:往一个新文件写一个自造前缀 + 数字(让 git 看见该文件)→
  校验 1 报 1 处错误 + 增量拦截 FAIL,退出码 1。
- 全门禁:check_ids --strict 校验 1~6 无错误(可判定 87.15% / 不可判定 1033,仅报告);
  doc-links --all --sections-strict 通过(210 文档);mojibake / bom-guard /
  coding-standard / git diff --check 全 rc=0。钩子数不变(替换口径,不加不减)。
2026-10-28 12:18:00 +08:00
wandering1 f50e74c63b docs+log: 撤销"PA10 未接线"结论,ORE 机理改为"RX 使能却不读 DR"
用户反馈:PA10 这个端口是接线的,当年那个分析应该是错的。

核查确认:console_log.c(文件头与 con_uart_reinit() 注释)和
控制台单写者日志设计说明.md 12 节里的"PA10 悬空 / 未接线"是 2026-10-02 的
归因推断,不是实测,且与用户确认的接线状态相反。

ORE 的充分条件本来就不依赖引脚悬空:RX 使能了却从不读 DR,
线上任意一个字节或一个噪声沿使 RXNE 置位后无人读,下一个事件即锁存 ORE
(常伴 NE/FE/PE);而 ORE 只能靠"先读 SR 再读 DR"清除,所以永不自愈。
引脚悬空只影响发生率,不是必要条件。

当年那场风暴的真因仍待定:接线正常时更常见的是对端波特率不匹配
(适配器不是 115200)或适配器 TX 在 USB 掉线时浮空。下次复现先量
适配器 TX 的空闲电平与波特率,不要再默认"引脚悬空"。

改动:
- console_log.c:函数注释改按正确机理表述;修改记录加 2026-10-28 一条
  说明归因更正。纯注释,Code 236456 B 与上版一致,@build 0/0。
- 控制台单写者日志设计说明.md 12 节:机理段后加更正块,写明观察与缓解
  措施仍成立、只有归因需要改写。
- 产品需求文档:4.2 表 USART1 行改为"PA10 双向均已接线";5.16.2 的
  "PA10 没接线"警示块整段重写为"旧结论已撤销 + 真正机理 + 两条硬要求"
  (屏板链路必须消费 DR 并在错误回调清 ORE;新日志口仍设 UART_MODE_TX);
  9.13 前置阻塞由"两条物理前置"改为"一条物理前置 + 一条实现纪律";
  12 节加 v1.9。
- 屏板链路规划:0 章第 2 行标为已撤销、执行顺序去掉"接 PA10";
  批 0 由 4 项减为 3 项;批 1 第 3 项判据补"拔插 TX 线制造噪声后能自动
  恢复";风险表把"PA10 没接"换成"一次噪声后链路永久静默"。
- 任务规划 README 独立轨道行同步为两条前置。

体积凭证随索引刷新(scripts/size_attestation.json),数字未变。
2026-10-28 10:41:32 +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 03721aafc4 docs: 新增 ADC 采样陷阱台账(TRAP-ADC-01/02)
把 2026-10-27 排查出的两个 ADC 采样陷阱沉淀成正式台账,按
docs/编号规范.md 的 TRAP-ADC-<nn> 编号,属主文档
docs/问题记录/ADC_Trap_Records.md。

TRAP-ADC-01:ADC 使能后闲置数秒才挂 DMA,导致 DMA 乒乓缓冲整体
+2 格相位旋转(槽 i 装的是 rank ((i+1) mod 9)+1)。全程无任何
编译或运行错误,只是数据整体错位两格,表象与「映射表写错」完全
一致,历史上据此误判过三轮。

条目重点记了那条判读陷阱:adcr[CH_i] == adcb[i] 成立不能证明通道
映射正确——它只证明拷贝循环是恒等映射,缓冲整体旋转时拷贝照样
恒等。判映射只能靠按通道号索引的独立真值(无 DMA 单通道读)。
附 9 行同开机对照证据表、5 种固件形态的 A/B 对照、修复方式、
回归判据与未证部分(微架构为何恰好丢 2 拍仍未证)。

TRAP-ADC-02:RTOS 运行期校准被 TIM3 TRGO 打断,adc1_calibrate()
返回 0xFFFF 超时哨兵。记了指纹判读要点(truth=65535 且 min 大于
max 是哨兵,不是满量程)与修法(校准期间屏蔽 EXTEN)。

关联登记三处:
- docs/README.md 7.3 问题记录表新增一行
- 设计文档 4.5 节加反向链接到 TRAP-ADC-01(代码 -> 设计 -> 台账)
- scripts/id_registry.json 的 TRAP 族 cursor_note 补 ADC 域 01~02

纯文档改动,不涉构建。
2026-10-27 20:55:04 +08:00