diff --git a/.dsh/skills/id-family-semantic-migration/SKILL.md b/.dsh/skills/id-family-semantic-migration/SKILL.md index f7aa9e47..f4f2ae84 100644 --- a/.dsh/skills/id-family-semantic-migration/SKILL.md +++ b/.dsh/skills/id-family-semantic-migration/SKILL.md @@ -9,12 +9,12 @@ version: 1.1.0 **动手前先判这一族有没有「机器识别面」**——它决定计数口径的来源与落地去处,两条路的做法**正好相反**: -| 族形态 | 计数口径来源 | 改名手段 | `scripts/id_aliases.json` | +| 族形态 | 计数口径来源 | 改名手段 | `scripts/archive/id_gate/id_aliases.json` | |---|---|---|---| -| 字母+数字,且在 `scripts/check_ids.py` 语料内(`id_registry.json` 有族、族 pattern 能匹配它) | 门禁自身计数(`ck.refs` / `ck.stats` / 报告行) | `scripts/rename_ids.py`(映射表 + 显式 scope + 默认干跑) | **要登记**:死号 `void`、转短语 `retired-to-phrase` | +| 字母+数字,且在 `scripts/archive/id_gate/check_ids.py` 语料内(`id_registry.json` 有族、族 pattern 能匹配它) | 门禁自身计数(`ck.refs` / `ck.stats` / 报告行) | `scripts/rename_ids.py`(映射表 + 显式 scope + 默认干跑) | **要登记**:死号 `void`、转短语 `retired-to-phrase` | | 中文前缀(「卡」+ 数字)、纯散文里的号、圈号 ①②③ | **自建带标签正则扫描器**(门禁看不见它,id-check 报告与本族无关) | 逐处替换 + 断言命中数(`rename_ids.py` 靠族 pattern 驱动,这里用不上) | **刻意不登记**:登记了机器也看不见,只多一张没人核的表;停发只靠规范 + 评审 | -怎么判(三条,任一为否即无识别面):① `grep -nE '"name"|"pattern"' scripts/id_registry.json`,没有任何族 pattern 能匹配该形态;② `./.venv/Scripts/python.exe scripts/check_ids.py --top 0` 的任何校验里找不到它;③ registry 的 `blind_spots` 已明写不判(圈号与正常列举无法机械区分、裸形同字母多义只在属主登记处判)。实测:「卡」+ 数字**没有族**(中文形态只有 `malformed` 里 `陷阱 ?[0-9]` 那条禁令,管的是陷阱编号不是卡号),该族真实站点 288 处 / 56 文件,而门禁对它贡献 0。 +怎么判(三条,任一为否即无识别面):① `grep -nE '"name"|"pattern"' scripts/archive/id_gate/id_registry.json`,没有任何族 pattern 能匹配该形态;② `./.venv/Scripts/python.exe scripts/archive/id_gate/check_ids.py --top 0` 的任何校验里找不到它;③ registry 的 `blind_spots` 已明写不判(圈号与正常列举无法机械区分、裸形同字母多义只在属主登记处判)。实测:「卡」+ 数字**没有族**(中文形态只有 `malformed` 里 `陷阱 ?[0-9]` 那条禁令,管的是陷阱编号不是卡号),该族真实站点 288 处 / 56 文件,而门禁对它贡献 0。 判错的代价是双向的:拿门禁计数当中文字面量族的口径 → 得出「0 处待改」的**假归零**;给无识别面的族登记别名 → 制造「有机器兜底」的错觉,真正生效的两条(§4.1.1 停发行、§9.3 换算表)反而没人写。 @@ -55,7 +55,7 @@ version: 1.1.0 - Mermaid 流程图节点名 → 改语义名但**节点数与连线关系不变**,图结构不动; - 数学记号 → 进噪声表;门禁自身的规则名(gitlint `T2 Title has trailing whitespace`)→ 不改。 分类前先把剩余每处原文打出来看(`grep -F` 逐文件),否则会把硬件资料改坏。 -4. **映射表由属主文档生成**:从属主文档取「编号 → 功能名/语义短语」全表(实测 42 个定义 / 28 个在用),改名走 `scripts/rename_ids.py`(映射表驱动 + **显式 scope** + **默认干跑** + 自动往 `scripts/id_aliases.json` 写 scoped 旧号→新号条目,状态 `renamed` / `retired-to-phrase` / `void`)。**绝不全局查找替换**:同一裸形字面量可能同时属多个族(实测 `S3` 三义),全局替换等于造新撞号。 +4. **映射表由属主文档生成**:从属主文档取「编号 → 功能名/语义短语」全表(实测 42 个定义 / 28 个在用),改名走 `scripts/rename_ids.py`(映射表驱动 + **显式 scope** + **默认干跑** + 自动往 `scripts/archive/id_gate/id_aliases.json` 写 scoped 旧号→新号条目,状态 `renamed` / `retired-to-phrase` / `void`)。**绝不全局查找替换**:同一裸形字面量可能同时属多个族(实测 `S3` 三义),全局替换等于造新撞号。 5. **按写域拆道并行派单**(代码与测试半 / 文档半 / 某功能面各一条道),同笔用 `send_message` 下发**统一改写口径**(措辞、是否动字符串字面量、生成器归属、冻结历史行怎么处理),避免各道自定措辞;口径长就先落成 spec 文件(中文族一节第 5 步的做法同样适用)。看板任务只认 `team_task_update` 的 `task_id` / `expected_revision` / `action=reassign` / `owner` 四个字段。 6. **门禁配置注释也是本族写入面**:`.pre-commit-config.yaml` 的注释里会挂着功能号(实测 `7h) ADC 采样有效性校验(L1-6)`、`7i) 保护定值模型(P1 / L5-1 载体)`、`规划 §3.3 L3-5`)。配置属 Lead 写域,Lead 自己改(注释不占钩子行为、不影响 51 条钩子口径),但**必须计入批次范围并在提交正文写清是 Lead 改的 config**。 7. **每处替换断言命中数**,不做整文件正则批量改写(批量改写会静默漏改): @@ -69,7 +69,7 @@ version: 1.1.0 ``` **token 取最小形态**:文档里被反引号/加粗包住的号,替换单位取反引号形(```T4```)而**不含 `**` 标记**(第 225 行是 `**裸形 `T4`**`,按「裸形 `T4`」替就命中 0)。讲编号的文档改成**形态描述**(如「字母 T 紧跟数字 4」)能把不可判定绝对数还回余量:实测 4 处 → 982 降到 978,且 lesson 不丢。 8. **同步更新门禁侧配置**:`check_ids` 的 `excluded_paths` 与噪声表按第 3 步的分类结果改,使剩余命中不再是「假编号」;新测试套件发号的悬空引用要先定**定义位**: - - 定义位**只能落一处**——注册表族(`scripts/id_registry.json`)或该套件说明文档,**两处并存比没有定义位更坏**;文档真写出来了(含判据与上板清单)就以文档为准、**撤族**; + - 定义位**只能落一处**——注册表族(`scripts/archive/id_gate/id_registry.json`)或该套件说明文档,**两处并存比没有定义位更坏**;文档真写出来了(含判据与上板清单)就以文档为准、**撤族**; - 要建族就照现有同类族克隆(`pattern` / `digit_width` / `owner_docs_glob` / `scope` / `cursor`),别自造字段; - **抬游标前先确认游标是字符串形态**(`'cursor': 'TC-UIDATA-026'`)——整型比较会静默不生效(实测踩坑),用字符串解析或正则取序号再比。 9. **生成器文本改动必须同笔重跑产物**:`tools/arch_diagram/gen_*.py` 里的 docstring/文案会进产物,`generated-fresh` 把生成器拷到临时目录重跑逐字节比对,**只改源不改产物必红**。这类站点整包转给生成器属主,「谁改谁跑生成器」,脚本 + 全部 svg 产物同一笔: @@ -84,8 +84,8 @@ version: 1.1.0 11. **分笔提交走真实 pre-commit 钩子**:`git add` 用显式清单。坑:`git add -- App/algo` 把文档道的 `App/algo/README.md`(26 处)带上车,正文按 48 只文件写就不准了 → 该笔未 push 时 `--amend` 挪到文档笔并补一句归属说明;`git add -A` 会把别道在飞文件卷进来(覆盖率钩子在他编译不过的半成品上报红)→ 撤出他人域后重跑。提交正文每行 ≤80(gitlint B1),别把 ASCII 双引号写成正文首字符。 12. **收口只认门禁自身计数**(**仅限语料内的族**;无识别面族见下一节第 8~9 步),并核**只减不增**: ```bash - ./.venv/Scripts/python.exe scripts/check_ids.py 2>&1 | grep -aE '扫描|可判定 |不可判定引用' | head -4 - ./.venv/Scripts/python.exe scripts/check_ids.py --strict 2>&1 | tail -1 # [OK] 校验 1~6 无错误 + ./.venv/Scripts/python.exe scripts/archive/id_gate/check_ids.py 2>&1 | grep -aE '扫描|可判定 |不可判定引用' | head -4 + ./.venv/Scripts/python.exe scripts/archive/id_gate/check_ids.py --strict 2>&1 | tail -1 # [OK] 校验 1~6 无错误 ``` 报告「字面量 8787→8299→7828」「不可判定绝对数 1161→984→982→978(上限 1166)」「可判定比例 88.14%(基线 86.0%,容差 0.1pp)」。**绝对数与比例两根线都要报**:把可判定引用改成散文会稀释比值,所以另有不可判定绝对数上限。涨点归因见「净室归因」一节。 13. **回写 `docs/编号规范.md`**:§4.1 族表(停发/待清栏)、§4.1.1 已停发栏、§9 存量表与批次结果表(只减不增)、§9 清点数字按最终实测同步;表格若保留动手前的清点数,**明确标注「不是当前存量,是动手前基线」**,否则就是拿旧数当现状。变更记录加一行(含用户裁定原文)。 @@ -97,7 +97,7 @@ version: 1.1.0 ## Steps(中文前缀族:门禁咬不到的那一路) -1. **先确认门禁咬不到,并把这句话写进交付**:`scripts/check_ids.py` 的族 pattern 是拉丁形态、中文前缀不进语料 → **id-check 的 refs / 可判定比例 / 悬空引用与本族无关**;报告开头写「本族不在 check_ids 语料内,口径 = 自建扫描器」。 +1. **先确认门禁咬不到,并把这句话写进交付**:`scripts/archive/id_gate/check_ids.py` 的族 pattern 是拉丁形态、中文前缀不进语料 → **id-check 的 refs / 可判定比例 / 悬空引用与本族无关**;报告开头写「本族不在 check_ids 语料内,口径 = 自建扫描器」。 2. **销项删行前先核证据属主**(这是删行的唯一许可证): - 先取历史口径:`git log --oneline -20 -- <文档>`、`git show :<文档> | sed -n '/^## 5/,/^## 6/p'` 找回被删的卡表与当初「完成即销项删行 / 标 ✅ 保留行」的理由; - 核对判据与实测记录**已完整沉淀进属主章节**(实测:「已知电压注入验证」六项判据全 PASS、斜率 6544.2 码/V、偏差 −0.14 % 全在 `docs/硬件平台/ADC通道映射说明.md` §8.1,执行侧在 `docs/测试说明/ADC前端注入验证流程.md`); @@ -143,7 +143,7 @@ version: 1.1.0 5. **派单前写一份 spec 文件**(`ci-artifacts/card_retire_spec.md`),作为各道唯一口径来源,含五块:① 背景与**用户裁定原文**;② 逐号映射表(旧号形态 → 语义短语 → 属主出处);③ 措辞规则(补短语时括号怎么降级、动不动字符串字面量、生成器归属、悬空引用怎么判);④ 硬约束(BOM 原样补回、行尾由 `.gitattributes` 写死、冻结历史行与原始证据不回改、代码头注释引用的设计约束章节保留、带 BOM 文件名单);⑤ 自检与交付格式(逐文件命中数、删了哪几行、残留数、门禁复跑结果)。`send_message` 只发路径 + 关键裁定,长中文正文不要整段塞进消息(一次串多条长消息会撑爆 120s,发出 1 条后 abort,剩余未发)。 6. **逐处替换断言命中数**(同第 7 步的 `rep(tag, old, new, want)`),且 `old` 串**从原文取、不凭记忆敲**:本仓中文引号与 ASCII 双引号混用(实测某文档里的「中文引号」其实是 ASCII `"`),凭印象写 `old` 必 `got=0`;断言抛错后先 `git status --porcelain=v1 -- <文件>` 自证文件未被别道改动,再回读该行真身重跑。删行类改动单独记 tag 并打印删了几行、行号与原行长度。多道并行时同一文件常被别道改过:`edit` 报 `file changed since it was read` → 重新 `read` 再改;报 `ReplaceFileW EIO (Win32 1175)` → 先自证文件字节完好(BOM / CRLF / `EF BF BD` 三项)再重试同一笔,不要顺手改内容。 7. **落地位置写死(这一族只有这几条兜)**: - - `docs/编号规范.md` **§4.1.1「已停发的族」表加一行**,三列齐全,第三列直写「⚠ **机器面空白**:中文前缀不进 `scripts/check_ids.py` 语料 → 门禁咬不到,只有本表 + §9.3 + 评审三条兜;`id_aliases.json` 刻意不登记(登记了机器也看不见,只多一张没人核的表)」; + - `docs/编号规范.md` **§4.1.1「已停发的族」表加一行**,三列齐全,第三列直写「⚠ **机器面空白**:中文前缀不进 `scripts/archive/id_gate/check_ids.py` 语料 → 门禁咬不到,只有本表 + §9.3 + 评审三条兜;`id_aliases.json` 刻意不登记(登记了机器也看不见,只多一张没人核的表)」; - `docs/编号规范.md` **§9.3 逐号换算表**(旧号形态 → 语义短语 → 现行口径出处;本族实测 14 行 = 0、0b、1~12)+ §9 批次段落 + 变更记录各一行,**写明旧号永久作废、不得重新取走**; - 表内**把形态写成「卡」+ 数字而不复述字面量**:规范本身是门禁语料,复述字面量会把「讲规则的文档」变成自己的引用站点; - **同步叙述**:`AGENTS.md`「文档与图形」的销项条目、`docs/README.md`(例:`数据可信.md = 三项阻塞任务` → 两项)、`docs/任务规划/README.md`、`docs/任务规划/登记簿.md`——「剩余三项」这类旧口径实测归零; @@ -192,7 +192,7 @@ version: 1.1.0 - **`grep 'A\|B'` 空返回当文件干净**:交替竖线在多层 bash 引号里被吃掉,是探针坏不是文件干净 → 反证为空的搜索必须换 `grep -F` 复测。 - **一次 run_code 串 `5 × wait_agent(118000)` ≈ 590s 整段 abort、进度全丢**;且一次串多条长中文 `send_message` 也撑爆 120s(发出 1 条后 abort,剩余未发)。轮询上限 4×118s,长消息拆开发。 - **游标整型比较静默不生效**(字符串形态);抬完用 `--strict` 与 plain 双验。 -- **`git add` 目录路径带进别道文件**、`git add -A` 卷进在飞改动;撤销自己的改动只按文件点名 `git restore scripts/id_registry.json`,不碰同树其它道文件。 +- **`git add` 目录路径带进别道文件**、`git add -A` 卷进在飞改动;撤销自己的改动只按文件点名 `git restore scripts/archive/id_gate/id_registry.json`,不碰同树其它道文件。 - **amend 被 gitlint B1 拦**:正文行 >80,别把 ASCII 双引号写成正文首字符。 - **改「只动注释」要拿机器证据**:`@build` 0 错 0 警且 `Program Size` 与改前**逐字节同数**(本回合真跑,引用历史提交正文自报的数字不算证据),别口头承诺。 - **冻结历史与原始证据不改**:boot 串口日志等采集现场是冻结证据,改了就是篡改;历史「修改记录」行按裁定保持改名后形态(号已全仓退役,留一个查无此号的引用比留改过名的条目更坏)。 @@ -200,7 +200,7 @@ version: 1.1.0 ## Verification -1. `scripts/check_ids.py --strict` 与 plain **均 rc=0**(`[OK] 校验 1~6 无错误`),悬空引用为 0。 +1. `scripts/archive/id_gate/check_ids.py --strict` 与 plain **均 rc=0**(`[OK] 校验 1~6 无错误`),悬空引用为 0。 2. 编号字面量与**不可判定引用绝对数**只降不升、不超 `undecidable_total_ceiling`;可判定比例不低于 `id_registry.json` 基线(86.0%)。 3. 本族剩余站点复扫归零:有识别面族从 `ck.refs` 按族正则过滤字面量逐条打印;除冻结历史/原始证据行外无残留。 4. `pre-commit run generated-fresh --all-files` PASS + 目检 svg diff 只有文案与框宽自适应(只在动过生成器时适用);`check_doc_links.py --all` 通过。 diff --git a/.dsh/skills/task-worktree/SKILL.md b/.dsh/skills/task-worktree/SKILL.md index bf4befbd..bcd92641 100644 --- a/.dsh/skills/task-worktree/SKILL.md +++ b/.dsh/skills/task-worktree/SKILL.md @@ -197,7 +197,7 @@ WT="$MAIN/../_wt/und-attr" # 仓外同级 _wt/ 下;一次 rm -rf "$WT" 2>/dev/null git -C "$MAIN" worktree add --detach "$WT" HEAD >/dev/null 2>&1 || { echo WT_FAIL; exit 9; } git -C "$WT" status --porcelain # 应为空 -"$PY" "$WT/scripts/check_ids.py" 2>&1 | tail -25 # ← TODO 口径:以 .pre-commit-config.yaml 里 id-check 钩子的 entry/args 为准;基线与注入用**同一条命令** +"$PY" "$WT/scripts/archive/id_gate/check_ids.py" 2>&1 | tail -25 # ← TODO 口径:以 .pre-commit-config.yaml 里 id-check 钩子的 entry/args 为准;基线与注入用**同一条命令** ``` - `--detach`(**不要 `-b`**):净室没有分支、不写 `_wt/.state/.json` 台账 → **不占 `MAX_CONCURRENT = 3` @@ -212,7 +212,7 @@ git -C "$WT" status --porcelain # 应为空 for f in "App/log/sys_log_mcu.c" "test/host/sys_log_mcu/sys_log_mcu_test.c" "docs/子系统设计/运行与自检记录设计说明.md"; do mkdir -p "$WT/$(dirname "$f")" cp "$MAIN/$f" "$WT/$f" # 拷进净室;主树那份只读、一字节不动 - echo "== $f =="; "$PY" "$WT/scripts/check_ids.py" 2>&1 | tail -25 # ← 与第 1 步同一条命令 + echo "== $f =="; "$PY" "$WT/scripts/archive/id_gate/check_ids.py" 2>&1 | tail -25 # ← 与第 1 步同一条命令 git -C "$WT" checkout -- "$f" # 只还原净室里自己刚拷进来的那份 done ``` @@ -222,7 +222,7 @@ done 在飞文件,或存在文件间交互项**,不许就此交卷。 3. **定性增量是哪一类字面量**(只有「谁」没有「为什么」= 给不出可执行的改法):同一计数器在 **HEAD 版**与 **在飞版**各数一遍,**差值才是新增行带来的**(存量的不算这条道的账);再对新增行直接 grep。本次 16 处全是 - **裸形 「字母 T 累进数字 4」**(`T` 在 `scripts/id_registry.json` 的 `bare_check_letters` 里,规范形态是连字符形), + **裸形 「字母 T 累进数字 4」**(`T` 在 `scripts/archive/id_gate/id_registry.json` 的 `bare_check_letters` 里,规范形态是连字符形), 全部落进 `skip_bare_unmanaged` —— 到这一步结论才配发给属主。 4. **闭合 + 复验主树一个字节没被污染**: @@ -319,7 +319,7 @@ git -C "$MAIN" status --porcelain | sort # 与测量前**逐行一致**( `ck = ci.Checker(reg, al, verbose=False)` → `ck.run()` → `print(ck.stats)`。别猜键名:先 `print(sorted(ck.stats))` 列出全量计数项,再按精确键取数(顺带 `git diff` 确认门禁脚本自己**没被改过**)。 - **别把「不可判定」当成一个数**(2026-10-27):`id-check` 有两种口径——检查器自己算的**硬不可判定**实测只有 - **2** 处,而门禁红线(`scripts/id_registry.json` 的 `undecidable_total_ceiling`)量的是**派生值** + **2** 处,而门禁红线(`scripts/archive/id_gate/id_registry.json` 的 `undecidable_total_ceiling`)量的是**派生值** `refs_total - decidable`(实测 8,744 - 7,582 = **1,162**,拆开 = `skip_bare_unmanaged` 834 + `noise_allowed` 326 + 硬不可判定 2,**三数精确闭合**)。所以**带属主登记处的族(TC-XXX 这类)加多少引用都算 「可判定」、一点不吃这条余量**,真正吃余量的是**裸形字母+数字**字面量;反过来「把可判定引用改写成散文」才是 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0f3b5bcf..434e75ec 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -667,40 +667,15 @@ repos: files: ^(scripts/board_ui_nav\.py$|simulator/tests/ref/.*\.bin$) pass_filenames: false - # 13) 编号门禁(2026-10-20 加,docs/编号规范.md §8 的 8 项校验) - # 背景:§1.2 用仓内证据列了 10 类编号事故(同字母多义 / 跨文档同号不同义 / - # 销项删行后残留悬空引用 / 自造前缀 / 会话临时号入册…),而 36 个钩子里 - # **只有 TC 一族**有机械检查(check_test_traceability.py,且未挂钩子、正则还漏 [示例] - # `TC-AI-01A` [示例] 这类大写后缀)——E/N/S/B/C/D/A/U/O/gen/Trap 全部裸奔。本钩子把 - # 规范 §8 的 8 项机械化:配置两份 `scripts/id_registry.json`(前缀 → 属主登记处 - # /形态/冻结/游标,逐项来自规范 §4 总表)+ `scripts/id_aliases.json`(旧号→新号, - # 照搬 section_aliases.json 的成功范式)。 - # 判据要点:「定义」= 字面量出现在该族**属主登记处文档**里;于是 §5.5 的 - # 「销项 = 删行 + 清全库引用」只做一半,校验 3 立刻报(销项号被重新取走那类撞号正是这条)。 - # 盲区显式登记在 registry 的 `blind_spots` / `unmanaged_bare`:裸形同字母多义 - # (§1.2:P1 五义 / L1 四义 / UI 状态机号四义)与元器件位号同形(§4.4),机械全库判定 - # 必然一边倒误报 → 裸形族只在属主文档内判越游标、文档外降告警;收口属 §9 阶段 - # 1-② 的迁移批次。**不是「检查通过」,是记在案上的盲区。** - # ⚠ 当前 warn-only(§8 上线节奏:先清 backlog → 清零后 entry 加 --strict 拦提交, - # 与 doc-links 章节校验同一条路径)。校验 8 的两根护栏(可判定比例 / 不可判定 - # 绝对数)**自 2026-10-28 起只报告、不拦提交**(用户裁定,退役路线见规范 §8.5); - # 硬拦的只有校验 1~6 的台账外新账。 - # ⚠ pre-commit 4.x 已移除 `always: true` → files 必须覆盖所有能改编号的触发面 - # (任意 md/c/h/py/yaml/json/txt + 本配置文件);扫描范围恒为全库 - # (悬空/孤儿/重复定义是跨文件判定,pass_filenames: false)。 - - id: id-check - name: 编号门禁(docs/编号规范.md §8 八项校验) - entry: python scripts/check_ids.py --strict - language: system - files: \.(md|c|h|py|ya?ml|json|txt)$|^\.pre-commit-config\.yaml$ - pass_filenames: false + # 13) 编号门禁的历史:2026-10-20 起曾有一版「全库语料审计」(规范 §8 的 8 项校验 + + # 99 族 registry + 别名表)。它 2026-10-28 退役——维护成本高过收益(近 80 笔提交 + # 61 笔被编号体系牵连),脚本与语料整体移入 `scripts/archive/id_gate/` + # (保留可复现性,**不再进提交门禁**)。退役路线与判据替换见规范 §8.5。 - # 14) 编号门禁·第二步(2026-10-28 加):只查**新增行**,零语料 - # 背景:语义标识已是默认形态,上面那套 99 族全库语料审计的维护成本高过收益 - # (近 80 笔提交有 61 笔被编号体系牵连),退役路线见 `docs/编号规范.md` §8.5。 - # 本钩子是新牙:看 git diff 的新增行里有没有**未登记形态**的「字母+数字」标识 + # 14) 编号门禁(2026-10-28 起是**唯一**的编号门禁):只查**新增行**,零语料 + # 背景:语义标识已是默认形态,全库语料审计的成本高过收益(见上条历史)。 + # 判据:看 git diff 的新增行里有没有**未登记形态**的「字母+数字」标识 # (自造前缀直接 FAIL;已停发族只 WARN);白名单在脚本里,按实测普查枚举、几乎不增长。 - # 与 id-check **双跑**一个观察期(老的是全库语料、新的是新增行),观察后再摘掉老的。 # 自检:`python scripts/check_ids_new.py --self-test`;范围自查用 `--range A..B`。 - id: id-check-new name: 编号门禁·新增行(零语料,拦截新造编号) diff --git a/AGENTS.md b/AGENTS.md index c9aa974d..0334bea2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -92,7 +92,7 @@ ## 提交门禁(pre-commit) -- 任一失败即拦截,共 **52 个钩子**(**口径 = YAML 解析后的 hook 条目数**:自查命令与「声明 / 文档 / 实跑」三数同源核对见 `docs/门禁说明/README.md` §2 首条——⚠ 直接 grep 配置里的声明行会多算一条**注释掉的**候选钩子(= 52),不是口径;**配置注释里也别复述那个 grep 字面量**,它会让文本计数再虚高 1(2026-10-27 实测踩过);加一条钩子就同批改 AGENTS 与门禁索引两处计数。2026-10-25 道E 连加 `bom-guard` / `setview-check` / `uinav-selftest` 三条,2026-10-26 加 `generated-fresh` 一条,2026-10-27 加 `nested-comment` 一条;2026-10-28 加 `id-check-new` 一条(编号门禁第二步:只查新增行、零语料,与 `id-check` 双跑观察,退役路线见 `docs/编号规范.md` §8.5);**每种门禁一篇详解(查什么 / 拦下过什么真事 / 限制与盲区 / 基线口径)→ `docs/门禁说明/README.md` 索引**;通用机制与整体口径 → `docs/代码规范/pre-commit使用说明.md`):通用 5 + `gitlint` + `cppcheck` / `test-cppcheck` + `no-mojibake` + `coding-standard` + 文档三件套 `doc-links` / `task-table` / `mem-numbers` + `id-check`(**编号门禁**,`docs/编号规范.md` §8 八项校验;**已关闸为【增量拦截】**:只拦 `scripts/id_known_backlog.json` 台账之外的新错误级问题,存量按指纹豁免、台账只减不增;两根护栏(可判定比例基线 / 不可判定引用**绝对数**上限)**自 2026-10-28 起只报告、不拦提交**(用户裁定:语料维护成本已高过它买到的一致性;退役路线见 `docs/编号规范.md` §8.5),硬拦的只有校验 1~6 的台账外新账(口径见 `docs/门禁说明/id-check.md` §7.6.1))+ `lv-conf-sync`(两份 `lv_conf.h` 特性子集一致)+ `cubemx-survival` + 主机侧单测 **22 根专属钩子**(`-unit-test` 后缀 = 有独立 `files:` 触发面、需要秒级归因的那个子集;2026-10-25 增补 adc-cal / prot-dim / vol-idle-sync / ui-data / meas / run-par 六根)——**这是口径不是缺口**:`test/host/` 实测 40 套带 `run_unit_test.py`,其余 **18 套**(含 `test/host/ui_sink`)没有专属钩子,但每次提交都被 `test-coverage` 总闸全量真跑并守基线回退,**失败照样拦**,只是归因落在总闸输出上;**没有专属钩子 ≠ 没被跑**,18 套台账与补钩子的判据 → `docs/门禁说明/host-unit-tests.md` §6 第 4 条。**Lead 裁定 2026-10-27:不补第 23 根**——读「这套跑没跑」去看总闸输出,别数钩子(原写「23 个 / 含 ui-sink 七个」是双重错:既把 22 说成 23,又宣称 ui-sink 有钩子——配置历史里 `ui-sink-unit-test` 从未存在)+ `test-coverage`(**覆盖率总闸**:跑全部 40 套并守基线回退;缺 mscoverage 组件时按用户裁定 **FAIL**、不 skip,2026-10-24)+ `test-suite-switch` + `registration-check`(双端注册反向校验 + UI 页面描述符表接线,登记簿条目「rs485_task 白名单缺口」)+ `generated-fresh`(**生成器幂等性**:把 `tools/menu_gen/gen_menu.py`、中文字库链、`tools/arch_diagram/gen_*.py` 拷进**系统临时目录**重跑,与工作区**逐字节**必须一致——钩子只读、不写仓库也不 stash 别人在飞的改动;实证 `0f7b5a87` 改了模板文字没重跑生成物,接线前实测另有 5 张 `docs/images/` 配图已漂 → 钉成只减不增基线,**业务生成物零豁免面** → `docs/门禁说明/generated-fresh.md`)+ `nested-comment`(**块注释嵌套**:注释体内再出现 /* 会被 ARMCC 报 9-D,且**按包含者数量刷屏**、只在重编译该 TU 时才暴露;本仓诱因就是「在注释里写作用域/通配路径」,改法是写全目录或用尖括号 ;接线当日实扫 403 个 .c/.h,新发 0、存量 2 处(`test/host/common/` 两份假件头)钉只减不增基线 → `docs/门禁说明/nested-comment.md`)+ `mem-budget`(RAM 92% 预算门禁,登记簿条目「缩堆迁 CCM 后半(暂缓)」)+ `font-charset`(UI 字符集差集检查,防缺字白框)+ `ui-golden`(UI 像素回归,菜单 8 状态 + 内容页 60 页黄金参考)+ `layer-deps`(**分层方向**:`Drivers/BSP/**` 不得 include `App/**` 的头;存量 3 条基线只减不增(2026-10-25 记录 reader 注入削掉 UI 记录 3 条边,6→3))+ `bsp-err`(**BSP 错误码与超时命名约定**:公开 API 不得拿 `HAL_StatusTypeDef`/`bool` 当错误通道、`*_TIMEOUT` 宏不得取负值、非 void 须写「返回值:」、**返回错误码的函数不得裸丢弃返回值**(须接住或显式 `(void)`;实测编译器与 cppcheck 都不报这类,只有这条会响);约定正文 `Drivers/BSP/bsp_err.h`,存量基线只减不增(2026-10-23 首清点 19 条 → 已还 18;`consume-result` 上线又暴露 37 条存量丢弃 → **现 38 条**)) +- 任一失败即拦截,共 **51 个钩子**(**口径 = YAML 解析后的 hook 条目数**:自查命令与「声明 / 文档 / 实跑」三数同源核对见 `docs/门禁说明/README.md` §2 首条——⚠ 直接 grep 配置里的声明行会多算一条**注释掉的**候选钩子(= 52),不是口径;**配置注释里也别复述那个 grep 字面量**,它会让文本计数再虚高 1(2026-10-27 实测踩过);加一条钩子就同批改 AGENTS 与门禁索引两处计数。2026-10-25 道E 连加 `bom-guard` / `setview-check` / `uinav-selftest` 三条,2026-10-26 加 `generated-fresh` 一条,2026-10-27 加 `nested-comment` 一条;2026-10-28 加 `id-check-new` 一条并同批退役 `id-check`(口径 52 → 51:编号门禁换牙——新的只查新增行、零语料,旧的八项全库校验连语料一起移入 `scripts/archive/id_gate/`,路线见 `docs/编号规范.md` §8.5);**每种门禁一篇详解(查什么 / 拦下过什么真事 / 限制与盲区 / 基线口径)→ `docs/门禁说明/README.md` 索引**;通用机制与整体口径 → `docs/代码规范/pre-commit使用说明.md`):通用 5 + `gitlint` + `cppcheck` / `test-cppcheck` + `no-mojibake` + `coding-standard` + 文档三件套 `doc-links` / `task-table` / `mem-numbers` + `id-check-new`(**编号门禁**:只查 `git diff` 新增行里有没有未登记形态的「字母+数字」标识,零语料、零维护;白名单是前缀级两张表,见 `docs/门禁说明/id-check-new.md`。旧的八项全库校验 `id-check` 已于 2026-10-28 退役,脚本与两份语料移入 `scripts/archive/id_gate/`,只在手工复查存量时才跑;退役路线见 `docs/编号规范.md` §8.5)+ `lv-conf-sync`(两份 `lv_conf.h` 特性子集一致)+ `cubemx-survival` + 主机侧单测 **22 根专属钩子**(`-unit-test` 后缀 = 有独立 `files:` 触发面、需要秒级归因的那个子集;2026-10-25 增补 adc-cal / prot-dim / vol-idle-sync / ui-data / meas / run-par 六根)——**这是口径不是缺口**:`test/host/` 实测 40 套带 `run_unit_test.py`,其余 **18 套**(含 `test/host/ui_sink`)没有专属钩子,但每次提交都被 `test-coverage` 总闸全量真跑并守基线回退,**失败照样拦**,只是归因落在总闸输出上;**没有专属钩子 ≠ 没被跑**,18 套台账与补钩子的判据 → `docs/门禁说明/host-unit-tests.md` §6 第 4 条。**Lead 裁定 2026-10-27:不补第 23 根**——读「这套跑没跑」去看总闸输出,别数钩子(原写「23 个 / 含 ui-sink 七个」是双重错:既把 22 说成 23,又宣称 ui-sink 有钩子——配置历史里 `ui-sink-unit-test` 从未存在)+ `test-coverage`(**覆盖率总闸**:跑全部 40 套并守基线回退;缺 mscoverage 组件时按用户裁定 **FAIL**、不 skip,2026-10-24)+ `test-suite-switch` + `registration-check`(双端注册反向校验 + UI 页面描述符表接线,登记簿条目「rs485_task 白名单缺口」)+ `generated-fresh`(**生成器幂等性**:把 `tools/menu_gen/gen_menu.py`、中文字库链、`tools/arch_diagram/gen_*.py` 拷进**系统临时目录**重跑,与工作区**逐字节**必须一致——钩子只读、不写仓库也不 stash 别人在飞的改动;实证 `0f7b5a87` 改了模板文字没重跑生成物,接线前实测另有 5 张 `docs/images/` 配图已漂 → 钉成只减不增基线,**业务生成物零豁免面** → `docs/门禁说明/generated-fresh.md`)+ `nested-comment`(**块注释嵌套**:注释体内再出现 /* 会被 ARMCC 报 9-D,且**按包含者数量刷屏**、只在重编译该 TU 时才暴露;本仓诱因就是「在注释里写作用域/通配路径」,改法是写全目录或用尖括号 ;接线当日实扫 403 个 .c/.h,新发 0、存量 2 处(`test/host/common/` 两份假件头)钉只减不增基线 → `docs/门禁说明/nested-comment.md`)+ `mem-budget`(RAM 92% 预算门禁,登记簿条目「缩堆迁 CCM 后半(暂缓)」)+ `font-charset`(UI 字符集差集检查,防缺字白框)+ `ui-golden`(UI 像素回归,菜单 8 状态 + 内容页 60 页黄金参考)+ `layer-deps`(**分层方向**:`Drivers/BSP/**` 不得 include `App/**` 的头;存量 3 条基线只减不增(2026-10-25 记录 reader 注入削掉 UI 记录 3 条边,6→3))+ `bsp-err`(**BSP 错误码与超时命名约定**:公开 API 不得拿 `HAL_StatusTypeDef`/`bool` 当错误通道、`*_TIMEOUT` 宏不得取负值、非 void 须写「返回值:」、**返回错误码的函数不得裸丢弃返回值**(须接住或显式 `(void)`;实测编译器与 cppcheck 都不报这类,只有这条会响);约定正文 `Drivers/BSP/bsp_err.h`,存量基线只减不增(2026-10-23 首清点 19 条 → 已还 18;`consume-result` 上线又暴露 37 条存量丢弃 → **现 38 条**)) - **范围 = 项目代码**:第三方(`Lib/`、`Middlewares/`、CMSIS、HAL、`lftpd`、`dhara`、`MDK-ARM`)排除;`cppcheck`/`coding-standard` 另排除 `test/`,规范检查再排除 CubeMX 生成的 `Src/`/`Inc/`。**`simulator/` 已纳入全部钩子**(2026-10-11)——生成物只靠 `.gitignore` 挡,**不在 `exclude` 里写目录名**(教训见 `docs/代码规范/pre-commit使用说明.md` §5.5) - ⚠ **pre-commit 4.x 已移除 `always: true`**(实测对 `local` 钩子只告警 `Unexpected key(s)` 并跳过)→ 想"总是跑"的钩子**必须让 `files:` 覆盖到所有会触发它的文件**,没有兜底开关 - **改写型钩子(`trailing-whitespace` + `end-of-file-fixer`)豁免 CubeMX/Keil 生成文件**(配置里 YAML 锚点 `&cubemx-generated`);⚠ **只读检查不受影响**:`cppcheck` / 乱码 / `cubemx-survival` / `task-table` / `mem-numbers` 仍覆盖 `Src/`、`Inc/` @@ -153,9 +153,9 @@ ## 文档与图形 -- **登记簿类文档「完成即销项」**:`docs/任务规划/README.md` 这类待办登记簿,事项修复/关闭后**直接从表中删除该行**(不保留"已消化"行)——结论与证据应已沉淀进对应模块文档/问题记录。销项时必须:① 先核对目标文档确已含完整记录 ② 同步清理其他文档对该编号的引用 ③ 改完跑 `check_doc_links.py --all` + pre-commit。**新条目标识(用户裁定 2026-10-14)**:`#` 列填**语义短语**(如 `沉降窗 800ms 上限只留痕`),**不再新增字母+数字编号**——"编号不回收"只写规则却不留痕迹就不可执行(销项删行后仓库里毫无痕迹,2026-10-14 实测就发生过「销项号被重新取走」的撞号事故),语义标识自带唯一性;**存量编号(登记簿 N-x / S-x / T-x 与专项 A-x)已于 2026-10-26 全部转成语义短语**,旧号进 `scripts/id_aliases.json` 标 `retired-to-phrase`、不得再指;**「数据可信」任务卡号(中文前缀「卡」+ 数字,14 个)已于 2026-10-27 随卡销项整族清退**,换算表 `docs/编号规范.md` §9.3——这一族**刻意不进 `id_aliases.json`**:中文前缀不进 check_ids 语料,登记了机器也看不见,**没有机器识别面**,停发只靠规范与评审;**已随销项消失的号永久作废**、不得复用 → `docs/任务规划/README.md` §0 +- **登记簿类文档「完成即销项」**:`docs/任务规划/README.md` 这类待办登记簿,事项修复/关闭后**直接从表中删除该行**(不保留"已消化"行)——结论与证据应已沉淀进对应模块文档/问题记录。销项时必须:① 先核对目标文档确已含完整记录 ② 同步清理其他文档对该编号的引用 ③ 改完跑 `check_doc_links.py --all` + pre-commit。**新条目标识(用户裁定 2026-10-14)**:`#` 列填**语义短语**(如 `沉降窗 800ms 上限只留痕`),**不再新增字母+数字编号**——"编号不回收"只写规则却不留痕迹就不可执行(销项删行后仓库里毫无痕迹,2026-10-14 实测就发生过「销项号被重新取走」的撞号事故),语义标识自带唯一性;**存量编号(登记簿 N-x / S-x / T-x 与专项 A-x)已于 2026-10-26 全部转成语义短语**,旧号进 `scripts/archive/id_gate/id_aliases.json` 标 `retired-to-phrase`、不得再指;**「数据可信」任务卡号(中文前缀「卡」+ 数字,14 个)已于 2026-10-27 随卡销项整族清退**,换算表 `docs/编号规范.md` §9.3——这一族**刻意不进 `id_aliases.json`**:中文前缀不进 check_ids 语料,登记了机器也看不见,**没有机器识别面**,停发只靠规范与评审;**已随销项消失的号永久作废**、不得复用 → `docs/任务规划/README.md` §0 - 图形走 **`draw-diagram` skill**:精确布局图用 `tools/arch_diagram/gen_*.py` 生成器(产物放 `docs/images/`,**脚本与产物同一笔提交**:改生成器没重跑,下一个碰巧重跑的人会看到一段「不是我改的」diff——已机械化 `generated-fresh`,重跑到临时目录逐字节比对 → `docs/文档规范.md` §4.4);拓扑图用 Mermaid;**勿手绘 ASCII 框图**。文件引用关系图走 `tools/refgraph`(`& 'tools\refgraph\gen_refgraph.bat'`) -- **改名 / 挪目录一律走 `scripts/rename_ref.py`(先 dry-run,确认后 `--apply`)**:`git mv` + 自动改写全库引用(反引号引用 / Markdown 链接 / 图片 `../` 层级换算 / `#include` / `uvprojx` `` / `CMakeLists.txt`),落盘后自动跑 `check_doc_links --all` 复核——手工扫引用既慢又漏(一次改名历史上波及 10~30 文件)。引用章节用「`路径.md` §N.M」**紧邻写法**(`doc-links` 校验编号是否还在:紧邻/裸名/前缀/别名/自引用**全部拦提交**(钩子带 `--sections-strict`);每次跑打印「可判定比例」,`--section-todo` 出待改清单,昵称歧义就登记 `scripts/section_aliases.json` 或写清楚)→ `docs/文档规范.md` §3.5 / §3.6。**编号改名走 `scripts/rename_ids.py`**(映射表驱动、**显式 scope**、干跑默认、自动写 `scripts/id_aliases.json` 的 scoped 旧号→新号条目;`[示例]`/`[计划]` 行与变更记录表不改写;**绝不全局查找替换**——同一裸形字面量可能同时属多个族,全局替换等于造新撞号,实测 `S3` 三义) +- **改名 / 挪目录一律走 `scripts/rename_ref.py`(先 dry-run,确认后 `--apply`)**:`git mv` + 自动改写全库引用(反引号引用 / Markdown 链接 / 图片 `../` 层级换算 / `#include` / `uvprojx` `` / `CMakeLists.txt`),落盘后自动跑 `check_doc_links --all` 复核——手工扫引用既慢又漏(一次改名历史上波及 10~30 文件)。引用章节用「`路径.md` §N.M」**紧邻写法**(`doc-links` 校验编号是否还在:紧邻/裸名/前缀/别名/自引用**全部拦提交**(钩子带 `--sections-strict`);每次跑打印「可判定比例」,`--section-todo` 出待改清单,昵称歧义就登记 `scripts/section_aliases.json` 或写清楚)→ `docs/文档规范.md` §3.5 / §3.6。**编号改名走 `scripts/rename_ids.py`**(映射表驱动、**显式 scope**、干跑默认、自动写 `scripts/archive/id_gate/id_aliases.json` 的 scoped 旧号→新号条目;`[示例]`/`[计划]` 行与变更记录表不改写;**绝不全局查找替换**——同一裸形字面量可能同时属多个族,全局替换等于造新撞号,实测 `S3` 三义) - 文档写作规范(编码/BOM/链接/表格/一致性钩子)→ `docs/文档规范.md`;全量索引与推荐阅读顺序 → `docs/README.md` ## 边界(Ask first / Never) @@ -175,8 +175,8 @@ | ADC 采样节拍 / 通道映射 / V0.1 硬件缺陷 | `docs/子系统设计/ADC采样节拍设计说明.md`、`docs/硬件平台/ADC通道映射说明.md` | | 存储栈(FatFs / dhara / lftpd / 两条 FatFs 陷阱) | `docs/架构设计/STM32F4-Base存储架构说明.md` | | RAM / 栈预算 / 容量台账 | `docs/内存管理/RAM使用分析与优化方案.md`、`内存内容分配策略.md` | -| **每个提交门禁一篇详解**(查什么 / 拦下过什么真事 / 限制与盲区 / 基线口径) | `docs/门禁说明/README.md`(52 个钩子 → 28 篇索引 + 1 指针) | -| **要不要给某个东西发编号**(默认:不发,写语义短语)/ 允许用号的 7 个族(`TC-*` 已停发——「停发」不等于「暂缓」,也不等于「可以清号」)/ `id-check` 八项校验 | `docs/编号规范.md`(§1 先问三句、§4.1 族总表〔穷举〕与『已停发』栏、§8 门禁与实测基线) | +| **每个提交门禁一篇详解**(查什么 / 拦下过什么真事 / 限制与盲区 / 基线口径) | `docs/门禁说明/README.md`(51 个钩子 → 28 篇索引,其中 1 篇是退役留档 + 1 指针) | +| **要不要给某个东西发编号**(默认:不发,写语义短语)/ 允许用号的 7 个族(`TC-*` 已停发——「停发」不等于「暂缓」,也不等于「可以清号」)/ 编号门禁现状(`id-check-new`:只查新增行;旧的八项校验已退役) | `docs/编号规范.md`(§1 先问三句、§4.1 族总表〔穷举〕与『已停发』栏、§8 门禁与实测基线) | | 提交门禁通用机制(阶段 / stash 陷阱 / 触发面 / 增量拦截三段式) | `docs/代码规范/pre-commit使用说明.md` §2 | | 代码规范 V1.0 / cppcheck 口径 | `docs/代码规范/嵌入式C语言代码规范_V1.0.md`、`cppcheck使用说明.md` | | 自动化测试 / 实机测试 / 板级套件 | `docs/测试说明/自动化测试流程.md`、`实机测试实施指南.md`、`board-test-suite` skill | diff --git a/docs/代码规范/pre-commit使用说明.md b/docs/代码规范/pre-commit使用说明.md index 25babc5b..d3155849 100644 --- a/docs/代码规范/pre-commit使用说明.md +++ b/docs/代码规范/pre-commit使用说明.md @@ -94,7 +94,7 @@ git commit | **stash 覆盖面:只覆盖已跟踪文件的未暂存改动**(2026-10-26 读源码定案,**对所有钩子通用**) | 机制在 pre-commit 的 `staged_files_only._unstaged_changes_cleared()`:`git diff-index ` 取补丁 → `git checkout -- .` → 跑完 `git apply` 还原。所以「钩子实跑 = 只看到 HEAD + 本笔 staged」这句**对已跟踪文件成立、对未跟踪文件不成立**:未跟踪文件压根不在 `diff-index` 里,**不会被藏**;`git add -N`(intent-to-add)也救不了——pre-commit 只 `git rm --cached` 把它撤下索引(`_intent_to_add_cleared()`),**文件本体仍在盘上**。后果:别人写了尚未入库的文件(新页面实例 / 新单测目录 / 新文档)躺在树里时,**任何一笔碰到该文件所属钩子 `files:` 的提交都会被这份半成品拖红**——红的内容没错,但账不该记在这笔提交上。实测:`ui_page_clock.c`、`ui_page_reset.c` 处于未跟踪且未绑 `#page` 期间,`generated-fresh` 对**所有人**的 UI 提交都会 FAIL(现场日志 `docs/门禁说明/generated-fresh.md` §6 第 8 条)。三条结论:① 提交排序——会让全树变红的半成品要么先落地(绑引用 + 重跑生成器)要么先挪出工作树;② 凡「判定基准取工作区」的钩子(重跑比对类、全库统计类)在多人同树下必须配**静默窗口**;③ 真要 `--no-verify` 抢跑,正文必须点名是哪几个**未跟踪**文件拖的红,别让它被读成「钩子不可信」 | | **`always: true` 已废** | pre-commit 4.x 对 `local` 钩子里这个键**只告警 `Unexpected key(s)` 然后忽略** → "想总是跑"只能把 `files:` 写全(教训 → §5.5) | | **改写型与只读型的豁免不对称** | YAML 锚点 `&cubemx-generated` 只豁免 `trailing-whitespace` 与 `end-of-file-fixer`;`cppcheck` / `no-mojibake` / `cubemx-survival` / `task-table` / `mem-numbers` **仍覆盖** `Src/`、`Inc/` | -| **增量拦截三段式** | 规则恒生效 + 存量钉在基线/台账 + `--prune` 点名"已还清、请删行";**脚本刻意没有 `--write`**(不提供"一条命令把现状洗成合法"的入口)。使用者(2026-10-26 实跑核对):`layer-deps`(**基线内 3** + ALLOW 永久豁免 3,共见 6 处)、`bsp-err`(38 条)、`id-check`(工作区台账已还清 = **0 条指纹 / 0 处**;HEAD 那版是 303 条指纹 / 651 处)。原写「layer-deps(6)」「id-check 台账 640 处」都是没跟着还账更新的旧数 | +| **增量拦截三段式** | 规则恒生效 + 存量钉在基线/台账 + `--prune` 点名"已还清、请删行";**脚本刻意没有 `--write`**(不提供"一条命令把现状洗成合法"的入口)。使用者(2026-10-26 实跑核对):`layer-deps`(**基线内 3** + ALLOW 永久豁免 3,共见 6 处)、`bsp-err`(38 条)、~~已退役的 `id-check`~(工作区台账已还清 = **0 条指纹 / 0 处**;HEAD 那版是 303 条指纹 / 651 处)。原写「layer-deps(6)」「id-check 台账 640 处」都是没跟着还账更新的旧数 | | **没有 `.map` 即跳过** | `mem-numbers` / `mem-budget` 在无 Keil 构建的机器(含远端 CI)上是**跳过**,不是"通过"——别把跳过读成有余量 | | **配置自己坏 = 全部静默不跑** | 改完 `.pre-commit-config.yaml` 的验收不是过 `check-yaml`,而是实跑 `-m pre_commit run --all-files`,确认目标钩子**出现在输出里**且状态不是 `Skipped` | | **范围策略** | 第三方与生成物只靠 `.gitignore` 与顶层 `exclude`(不在各钩子里重复写目录名);权威口径 → `AGENTS.md` 提交门禁一节 + §5.5 | @@ -134,7 +134,7 @@ git commit | **字节卫生 = 改写型钩子的只读等价** | 下面的一行式 + `git diff --check` | 一次查完**待提交清单(含未跟踪新文件)**的 CR / 缺尾换行 / U+FFFD / 行尾空格,全程不写盘 | | 受影响模块的主机单测 | `& '.venv\Scripts\python.exe' test/host/<模块>/run_unit_test.py` | 只跑你碰的那几套;**改过骨架** `test/host/common/unit_test_harness.py` 就要跑全套(等价 22 根钩子同时触发) | | 全量单测 + 覆盖率 | `& '.venv\Scripts\python.exe' scripts/check_test_coverage.py` | 0=全过且覆盖率未回退 / 1=有失败或回退 / 2=环境(缺 `cl.exe` / mscoverage) | -| 编号 | `& '.venv\Scripts\python.exe' scripts/check_ids.py --strict` | 增量拦截:台账之外新错即 1;顺带核「可判定比例」与「不可判定绝对数」两行(2026-10-26 余量只剩 12 处) | +| 编号 | `& '.venv\Scripts\python.exe' scripts/archive/id_gate/check_ids.py --strict` | 增量拦截:台账之外新错即 1;顺带核「可判定比例」与「不可判定绝对数」两行(2026-10-26 余量只剩 12 处) | | 文档链接与章节 | `& '.venv\Scripts\python.exe' scripts/check_doc_links.py --all` | 0 通过 / 1 有问题(钩子还多带 `--sections-strict`) | | 生成器幂等 | `& '.venv\Scripts\python.exe' scripts/check_generated_fresh.py` | 重跑到临时目录逐字节比对;**必须 `.venv` 解释器**,否则字库链假红 → `docs/门禁说明/generated-fresh.md` §4 | | 一把梭(上面多数静态项 + 主机单测) | `& '.venv\Scripts\python.exe' scripts/ci_local.py` | 非 0 就别抢跑(但它**不含** `stack_report` / `ram_baseline`,数字与安全边界要另跑) | diff --git a/docs/任务规划/分工说明-20261028-RS485解锁与门禁口径对账.md b/docs/任务规划/分工说明-20261028-RS485解锁与门禁口径对账.md index 36c0baba..10cce198 100644 --- a/docs/任务规划/分工说明-20261028-RS485解锁与门禁口径对账.md +++ b/docs/任务规划/分工说明-20261028-RS485解锁与门禁口径对账.md @@ -36,7 +36,7 @@ |---|---|---| | A | RS485 两条 ❌ 清零,`rs485_task` 的技术门禁解除(**是否接线仍由用户裁定**) | `test/host/rs485` 全绿 + `MDK-ARM/build_log.txt` **0 错误 0 警告** | | B | 声明 / 文档 / 实跑 **三数一致** | 解析计数输出 + `docs/门禁说明/README.md` 差集为空 | -| A+B | `registration-check`、`bsp-err`、`nested-comment`、`id-check` 基线 **只减不增** | `scripts/ci_local.py` 输出 + `scripts/id_known_backlog.json` 台账 | +| A+B | `registration-check`、`bsp-err`、`nested-comment`、`id-check` 基线 **只减不增** | `scripts/ci_local.py` 输出 + `scripts/archive/id_gate/id_known_backlog.json` 台账 | ## 交接 diff --git a/docs/测试说明/主机单测覆盖率口径.md b/docs/测试说明/主机单测覆盖率口径.md index 6bb91808..13dffb5e 100644 --- a/docs/测试说明/主机单测覆盖率口径.md +++ b/docs/测试说明/主机单测覆盖率口径.md @@ -696,7 +696,7 @@ uint16_t ch395f_link_change_count(void); - **顺手照出的隐患**:待发条目只存 `const char *`,复用栈缓冲投递时整批别名到最后一次写入(实测落盘「1~5 + 12 七份」)。已改为条目内嵌 `desc[SYSLOG_DESC_MAX + 1u]` 并在投递时截断拷贝,头文件参数契约同步改写;代价 `+352 B ZI / +60 B Code`。理由与实测细节 → `docs/子系统设计/运行与自检记录设计说明.md` §4.4。 - **两次测法自误(教训,别重复)**:① 先按 700 ms 快投递测,测到的 34 条丢失其实是投递侧队列满(设计如此),根本没走到被整改的支路——**测错了对象**;② 钩子投完后 `return` 使 testTask 退出,约 10 s 后被看门狗复位,把还压在 RAM 队列里的条目一起带走——**污染了自己的计数**。两者都不是固件问题,根因都是没有先验证测量手段本身有效。 - **假件护栏的一次正向记录**:条目由 8 B 变 32 B 后,`test/host/sys_log_mcu` 的假消息队列因 `MQ_MAXMSG`(原 24)拒收一切 `osMessageQueuePut`,从既有用例起整片失败——这种「尺寸变了就响」的断言比任何评审都可靠;该宏已抬到 40 并把现象写进注释。 -- 本轮改动面:`App/log/sys_log_mcu.c`(条目结构 + 投递拷贝)、`App/log/sys_log.h`(参数契约)、`test/host/sys_log_mcu/sys_log_mcu_test.c`(新增 2 条断言 + `MQ_MAXMSG`)、`scripts/id_registry.json`(游标 `TC-SYSLOG-108`)。 +- 本轮改动面:`App/log/sys_log_mcu.c`(条目结构 + 投递拷贝)、`App/log/sys_log.h`(参数契约)、`test/host/sys_log_mcu/sys_log_mcu_test.c`(新增 2 条断言 + `MQ_MAXMSG`)、`scripts/archive/id_gate/id_registry.json`(游标 `TC-SYSLOG-108`)。 - **台架与临时改动已全部还原**:钩子、负向对照、套件宏逐一反向删除(`git status` 归零),设备上 `BENCH.STS` / `BENCH2.STS` / `B5FILL.STS` 与含钩子记录的 `SELFTEST.LOG` 已删除,产品固件重建后重烧并回读校验通过。 ### P3|**明确不做**(把理由写死,免得下次又被列回待办:29 个 `.c` = 4,814 行) diff --git a/docs/编号规范.md b/docs/编号规范.md index 8d6b145a..0cc4e3e7 100644 --- a/docs/编号规范.md +++ b/docs/编号规范.md @@ -9,8 +9,8 @@ > 2026-10-26 起两批清理把编号字面量从 **10,956 压到 8,230 处**,2026-10-27 复测为 **7,828 处**(§8.1 有口径说明); > 而清掉的号里绝大多数从来没被任何脚本读过一次。沿革与教训留在 §8.3 与 git log,正文不复述。 > -> **机器面才是事实源**:族注册表 `scripts/id_registry.json`、旧号别名 `scripts/id_aliases.json`、 -> 门禁 `scripts/check_ids.py`(八项校验,详解 `docs/门禁说明/id-check.md`)。本文与机器面冲突时 +> **机器面才是事实源**:族注册表 `scripts/archive/id_gate/id_registry.json`、旧号别名 `scripts/archive/id_gate/id_aliases.json`、 +> 门禁 `scripts/archive/id_gate/check_ids.py`(八项校验,详解 `docs/门禁说明/id-check.md`)。本文与机器面冲突时 > **以机器面为准,并回来改本文**。 --- @@ -99,7 +99,7 @@ P-6 号必须能反查到定义(属主登记处得存在)· P-7 编号不语 > > - ❌「不做 = 维持原状 = 还能发」——**错**。新用例一律用**语义化测试函数名 + 文档用例表的行名**(§3.3), > 不再配 TC 号;指认**既有**用例仍可引用现存号(旧号只读,不是许可新配)。 -> - ❌「停发 = 这族要废了,顺手清掉、把号腾出来复用」——**也错**。现存号与它在 `scripts/id_registry.json` +> - ❌「停发 = 这族要废了,顺手清掉、把号腾出来复用」——**也错**。现存号与它在 `scripts/archive/id_gate/id_registry.json` > 里的登记,是 `check_test_traceability.py` 与 40 套 `run_unit_test.py` **按字面量读的追溯把手**, > 清它等于换机制(§9.1);号不回收、不复用是 §1 的硬规矩。 > - ❌「registry 里 TC 族还带着活游标,所以门禁允许我发」——**不成立:这条缺口已于 2026-10-27 同日关掉**。 @@ -142,13 +142,13 @@ P-6 号必须能反查到定义(属主登记处得存在)· P-7 编号不语 | 停发族 | 现在怎么写 | 旧号去哪查 | |---|---|---| -| 登记簿 `N-x` / `S-x` / `T-x`、专项 `A-x`、已删报告的 UI 簇 `U1~U5`(2026-10-26 方案 B) | 语义短语——**登记簿表首格本身就是短语**,如「双转换器无共同采样触发」「CI 远端闭环未验证」 | `scripts/id_aliases.json` 标 `retired-to-phrase` | -| 网络设计条目 `F-NET/F-DRV/F-MS-`(12 个,2026-10-27 批次一) | 「§7 + 条目名」短语,如 `(§7「全局读即清搁浅事件」)`;条目名的权威清单 = `docs/网络/网络自愈架构设计.md` §7「条目名」列;那个 DRV 段孤儿号按本节末句**删号留事实**、未补定义 | `scripts/id_aliases.json` 标 `retired-to-phrase`(13 条)+属主文档 §7 编号列仅作历史对照 | -| 「数据可信」任务卡号(中文前缀「卡」+ 数字,形态见 §9.3;2026-10-27 批次五) | §5 表的**标识列直接写任务名**(「端子/子板变比确认」「两点标定与精度验收」),代码注释与文档写语义短语(「标定折算落地」「未标定闭锁」「遥测快照发布」…);**逐号换算表见本文 §9.3** | ⚠ **机器面空白**:中文前缀不进 `scripts/check_ids.py` 语料(族 pattern 全是拉丁形态)→ 门禁咬不到,今天只有本表 + §9.3 + 评审三条兜;`id_aliases.json` 刻意不登记(登记了机器也看不见,只多一张没人核的表) | +| 登记簿 `N-x` / `S-x` / `T-x`、专项 `A-x`、已删报告的 UI 簇 `U1~U5`(2026-10-26 方案 B) | 语义短语——**登记簿表首格本身就是短语**,如「双转换器无共同采样触发」「CI 远端闭环未验证」 | `scripts/archive/id_gate/id_aliases.json` 标 `retired-to-phrase` | +| 网络设计条目 `F-NET/F-DRV/F-MS-`(12 个,2026-10-27 批次一) | 「§7 + 条目名」短语,如 `(§7「全局读即清搁浅事件」)`;条目名的权威清单 = `docs/网络/网络自愈架构设计.md` §7「条目名」列;那个 DRV 段孤儿号按本节末句**删号留事实**、未补定义 | `scripts/archive/id_gate/id_aliases.json` 标 `retired-to-phrase`(13 条)+属主文档 §7 编号列仅作历史对照 | +| 「数据可信」任务卡号(中文前缀「卡」+ 数字,形态见 §9.3;2026-10-27 批次五) | §5 表的**标识列直接写任务名**(「端子/子板变比确认」「两点标定与精度验收」),代码注释与文档写语义短语(「标定折算落地」「未标定闭锁」「遥测快照发布」…);**逐号换算表见本文 §9.3** | ⚠ **机器面空白**:中文前缀不进 `scripts/archive/id_gate/check_ids.py` 语料(族 pattern 全是拉丁形态)→ 门禁咬不到,今天只有本表 + §9.3 + 评审三条兜;`id_aliases.json` 刻意不登记(登记了机器也看不见,只多一张没人核的表) | | `E-xx` 审计发现、`P0-x`~`P3-x` 审计条目、报告六族 `D/R/F/N/U/S`、复审残号 `S1~S14`/`A-x`/`B1~B10`/`T-x`、模拟器差距 `H-x`/`L-x`、`TM-*` 阶段号、`DP-*`、`gen`/`round`/会话临时号 | 写条目本身("原子快照取数"、"队头阻塞"、"台架日志代次 288"、"第 3 轮台架") | 别名表标 `void`;**部分死号故意不进别名表**,好让门禁继续咬残留引用 | | 规范曾规划却从未启用的前缀族(`DEF`/`WI`/`DR`/`OQ`/`RSK`/`GAP`/`SC`/`GEN`/`MS`/`UL`/`LAT`/`CS` 等) | 同上,写事实 | 无定义,本就不该存在 | -> 想知道某个号还活着吗:跑 `scripts/check_ids.py --top 0`,或直接查 `id_aliases.json`——命中 `void` / +> 想知道某个号还活着吗:跑 `scripts/archive/id_gate/check_ids.py --top 0`,或直接查 `id_aliases.json`——命中 `void` / > `retired-to-phrase` 就是死号。**看到查不到的号,正确动作是删号留事实,不是补一个定义。** ### 4.2 目标前缀(作废) @@ -199,7 +199,7 @@ P-6 号必须能反查到定义(属主登记处得存在)· P-7 编号不语 --- ## 6. 模块码表 -`TC` 与 `TRAP` 共用模块码。唯一事实源是 `scripts/id_registry.json` 的族 pattern 与属主文档标题行; +`TC` 与 `TRAP` 共用模块码。唯一事实源是 `scripts/archive/id_gate/id_registry.json` 的族 pattern 与属主文档标题行; **本文故意不再抄一份**——抄一份就多一处会过期的地方(历史上这张表就长期与代码不同步)。 要加模块码:先改 registry,再在属主文档出现,最后才在别处引用。 @@ -223,11 +223,16 @@ P-6 号必须能反查到定义(属主登记处得存在)· P-7 编号不语 --- -## 8. 门禁:`id-check`(八项校验) +## 8. 门禁(2026-10-28 起:只有一道) -查什么、报错怎么读、盲区在哪——**全在 `docs/门禁说明/id-check.md`**,本文只留口径与基线。 -八项校验一句话版:① 未登记前缀 ② 形态不合规(裸形 / 空格 / 中文 / 补零)③ 悬空引用 ④ 重复定义 -⑤ 冻结族越游标 ⑥ 编号未紧邻文档名 ⑦ 孤儿条目(告警)⑧ 可判定比例 + 两根护栏(**自 2026-10-28 起只报告,不拦提交**,路线见 §8.5)。 +**现行门禁 = `id-check-new`**(钩子同名):只查 `git diff` 的**新增行**里有没有未登记形态的 +「字母+数字」标识;零语料、零维护。判据、白名单与盲区 → `docs/门禁说明/id-check-new.md`。 + +本节以下(§8.1~§8.4)是**已退役**的全库语料审计(`id-check`,八项校验)的留档: +脚本与两份语料已整体移入 `scripts/archive/id_gate/`,不再进提交门禁, +只在你手工复查「存量编号现状」时才跑。退役理由与判据替换见 §8.5; +八项校验一句话版(历史口径):① 未登记前缀 ② 形态不合规 ③ 悬空引用 ④ 重复定义 +⑤ 冻结族越游标 ⑥ 编号未紧邻文档名 ⑦ 孤儿条目(告警)⑧ 可判定比例 + 两根护栏。 ### 8.1 当前基线(2026-10-26 编号迁移批次后重打) @@ -253,7 +258,7 @@ P-6 号必须能反查到定义(属主登记处得存在)· P-7 编号不语 ——两处都在 2026-10-26 修掉了,别再往回改。 ### 8.4 台账与 `--strict` -错误级问题按「文件 + 校验项 + 字面量 + 次数」记指纹进 `scripts/id_known_backlog.json`,`--strict` 只拦 +错误级问题按「文件 + 校验项 + 字面量 + 次数」记指纹进 `scripts/archive/id_gate/id_known_backlog.json`,`--strict` 只拦 **台账之外**的新账,台账只减不增。本批台账已还清到 **0 条**——从现在起任何一条新错误级问题都会当场 拦提交,**别指望还有豁免面**可钻。 @@ -265,7 +270,7 @@ P-6 号必须能反查到定义(属主登记处得存在)· P-7 编号不语 |---|---|---| | ① | 两根护栏(比例基线 / 不可判定绝对数上限)**转报告制**:照打数字,不再影响退出码 | **已完成 2026-10-28** | | ② | 用 **diff 级新号拦截**替换语料审计:只看新增行里命中"字母+数字"形态、且不在白名单里的字面量,FAIL 并提示改成语义短语;白名单 = 前缀级两张表(活族 11 + 器件/协议/点号约 90),基本不增长 | **已完成 2026-10-28**(`scripts/check_ids_new.py` + 钩子 `id-check-new`,与 `id-check` **双跑观察期**;详解 `docs/门禁说明/id-check-new.md`) | -| ③ | 退役语料:99 族盘点成"活族清单",冻结族段与 `id_aliases.json` 移入归档;`check_ids.py` 降为手工报告工具,退出钩子 | 待做(② 落地观察一周再动) | +| ③ | 退役语料:99 族语料+脚本整体移入 `scripts/archive/id_gate/`(保留可复现性,不再进提交门禁);`check_ids.py` 降为手工报告工具,钩子摘除(口径 52 → 51) | **已完成 2026-10-28**(用户裁定跳过观察期直接做;`docs/门禁说明/id-check-new.md` 是唯一现役编号门禁) | **在 ② 落地之前,校验 1~6 仍是唯一的机械牙**:别因为"两根线不拦了"就顺手写号—— 新增的未登记前缀照样当场 FAIL(实测:在一个新文件里写一个自造前缀 + 数字,校验 1 与增量拦截双拦)。 @@ -328,7 +333,7 @@ P-6 号必须能反查到定义(属主登记处得存在)· P-7 编号不语 1. **关掉已清退族的发号口**:`L-` 与 `F--` 从 §4.1『允许继续发号』**整行移出**(7 行 → 5 行),在『已停发、存量待清』各补一行硬口径——留着那两行,扫表的人照样照着发号(同 `TC-*` 那次的教训)。**机器面已探针复核**:`_check_dangling` 对「L 段号形态的新号」与「F 条目号形态的新号」各写一个,全部命中 §8 校验 3 **错误级**(台账 0 指纹 → 等于拦提交),所以不需要再冻结数值游标(各段最高号不同,单一数字游标反而放行低号)。 2. **本文自述形态化**:把本文里 4 处「字母 T 紧跟数字」与 2 处 DRV 段孤儿号的**字面量写法**改成形态描述(lesson 不丢),使这四个族的门禁命中数真正归零,而不是停在「只有规范自己在引用」。 -3. **登记机器面还空着的那一面**:`scripts/id_registry.json` 给 `L-PROT`/`FEAT` 补 `retired` 字段;给 `T-TEST` 补 `cursor_note` 写明——它的 pattern 最高只到数字 3,**即使 `frozen: true` 校验 5 也碰不到任何新写法**(探针实测写 4 不响),所以该族停发今天只有 §3.3 禁令 + 评审两道兜底,**别把「存量已清零」读成「机器已关闭」**。 +3. **登记机器面还空着的那一面**:`scripts/archive/id_gate/id_registry.json` 给 `L-PROT`/`FEAT` 补 `retired` 字段;给 `T-TEST` 补 `cursor_note` 写明——它的 pattern 最高只到数字 3,**即使 `frozen: true` 校验 5 也碰不到任何新写法**(探针实测写 4 不响),所以该族停发今天只有 §3.3 禁令 + 评审两道兜底,**别把「存量已清零」读成「机器已关闭」**。 > ⚠ 本轮执行期间另有一道并行改动落地:`docs/测试说明/boot_log_data/README.md`(登记簿旧号「启动日志固化流程」)与 `docs/测试说明/m2_data/README.md`(审计发现 E 族一处死号)已由该道改为语义短语——**本笔不重复改这两处、也不替它收口**;复测两处死号引用均为 0。 @@ -337,7 +342,7 @@ P-6 号必须能反查到定义(属主登记处得存在)· P-7 编号不语 **批次一 · 现在就能清(约 62 个站点 / 20 个字面量,不碰任何门禁)**:`N-*`、`TM-*`、`T-TEST`、`F-*`。 -> `F-*` 已于 2026-10-27 收口:映射 `scripts/rename_maps/batch7-f-net-semantic.json`(10 条**带上下文**的定点改写),`docs/网络/网络自愈架构设计.md` §7 加「条目名」列作权威对照,13 个旧号进 `scripts/id_aliases.json` 标 `retired-to-phrase`。 +> `F-*` 已于 2026-10-27 收口:映射 `scripts/rename_maps/batch7-f-net-semantic.json`(10 条**带上下文**的定点改写),`docs/网络/网络自愈架构设计.md` §7 加「条目名」列作权威对照,13 个旧号进 `scripts/archive/id_gate/id_aliases.json` 标 `retired-to-phrase`。 > 作用域刻意只列 2 个文件、且 `old` 全部带上下文——同树里 `docs/硬件平台/` 的 **变压器位号(字母 T 紧跟数字)**(网表 ~4200 处 R/C/D/J/X/U/T 位号,本就不在门禁语料内)、`docs/芯片手册/` 的时序记号,以及各文档 Mermaid 图的**单字母节点名**(`F -->`、`EV`、`LN`…)都会被宽松正则顺伤;变更记录行(`BSD_Socket_API_使用指南.md` 的 `| 2026-10-13 |`)按 §8.1 豁免不改写。 这四族**没有任何脚本按字面量匹配**,纯人读,正是「语义标识最好」的适用面;台架阶段族还是裸形(字母 T 紧跟一位数字), 最容易与别的字母撞义。改法:号 → 短语(「台架阶段一」「网络自愈:监听生命周期」),残留引用同步清, @@ -370,7 +375,7 @@ P-6 号必须能反查到定义(属主登记处得存在)· P-7 编号不语 (新旧并行核对通过,再谈切换),**不许先改文档再改代码**(会凭空造出悬空号,§8 校验 3 会当场拦)。 **这条裁定的机器口径已落地(2026-10-27 同日补;上一版这里写「停发今天只有规范效力」,那是当日的实测记录,不是笔误,留作历史)**: -`scripts/id_registry.json` 的 **37 个 TC 类族已全部 `frozen: true`**,其中 **34 个 `TC-HOST-*` 子族带游标**,冻结在 +`scripts/archive/id_gate/id_registry.json` 的 **37 个 TC 类族已全部 `frozen: true`**,其中 **34 个 `TC-HOST-*` 子族带游标**,冻结在 裁定日该套件存量最高号;5 个游标低于存量的已抬到水位(`TC-PROTELEM-013→015`、`TC-SYSLOG-108→137`、 `TC-ADCHEALTH-011→023`、`TC-ADCCAL-017→023`、`TC-I104SRV-041→053`),裁定理由记在 registry 顶层 `tc_freeze_2026_10_27`。落地的直接诱因是本族在裁定当天还在长大:另一道在飞的 `time_sync` 改动新增了 @@ -453,14 +458,15 @@ P-6 号必须能反查到定义(属主登记处得存在)· P-7 编号不语 | 日期 | 变更 | 说明 | |---|---|---| +| 2026-10-28 | **编号门禁第三步收口:全库语料审计退役(钩子 52 → 51)** | 用户裁定跳过观察期直接做。`check_ids.py` 与两份语料(`id_registry.json` 87.6 KB / `id_aliases.json` 187 KB)+ 债务台账整体移入 `scripts/archive/id_gate/`(附归档 README,含"为什么退役 / 现在用什么 / 怎么手工跑");`id-check` 钩子摘除,现役编号门禁只剩 `id-check-new`(只查新增行)。连带改:`rename_ids.py` 的别名表路径指向归档、新门禁排除面加 `scripts/archive/`、`doc-links` 跳过 `.mnemon/` 与 `ci-artifacts/`(本地状态与草稿,非项目文档)、`id-check.md` 加退役横幅、`门禁说明/README` 与 `AGENTS` 的钩子数三数对齐(声明 51 / commit 阶段 50 + gitlint 1)。归档脚本从新路径实跑:811 文件 / 8,051 字面量、`--strict` rc=0。 | | 2026-10-28 | **编号门禁第二步落地:新增行拦截(零语料)** | `scripts/check_ids_new.py` + 钩子 `id-check-new`:只看新增行,破折形态未知前缀 FAIL、已停发族只 WARN、单字母+数字放行(元件位号同形,见该门禁 §6 盲区)。白名单是**前缀级**两张表(活族 11 条 / 器件与协议约 90 条),不是字面量账本——后者会退化成 `id_aliases.json` 的老路。调参依据:最近 80 笔真实提交回放,未知形态 15 种(12 种是设备与协议名、3 种是停发族),调好后误报 0;自检 5 正例 + 29 反例。与 `id-check` **双跑**一个观察期后再按 §8.5 ③ 退役旧语料。 | | 2026-10-28 | **编号门禁减负第一步:两根护栏转报告制** | 用户裁定「编号门禁每次浪费很多时间」→ 先摘掉语料审计的强制面。护栏 1(可判定比例基线)与护栏 2(不可判定绝对数上限)自此**只打印、不拦提交**;实测把基线调到 99.9%、上限调到 1 处,退出码仍为 0。硬拦只剩校验 1~6 的台账外新账(同一实测:新文件里写一个自造前缀 + 数字,校验 1 与增量拦截照旧 FAIL)。退役路线 ①②③ 写进 §8.5;减负依据 = 近 80 笔提交有 61 笔被编号体系牵连、语料共 99 族(78 族已冻结)。 | | 2026-10-28 | **变更记录行里已停发/作废族的示例编号改形态描述;并用门禁自身计数器把「这一笔能不能压下不可判定绝对数」钉死为零** | 用户指令:把变更记录行里已停发族的那几枚示例编号改成语义形态描述,并确认它让不可判定引用绝对数净减、不是只算自己这一笔。**实测裁定:净减 = 0**。门禁把「表格首格是日期」的行整行豁免于编号判定(registry 侧的变更记录豁免,本笔前全库已豁免 198 处站点),本表的示例编号从来不进引用总数分母,改它必然不动绝对数——改前改后同一个计数器均为 **1003**(上限 1166;可判定 87.43%,三项都是 2026-10-28 本回合实测)。唯一移动的是那行豁免计数本身(本文件少 1 处站点),把它当清退成果就是把自记账成全局减量,正是本笔要排除的错法。本文对该计数器的全部贡献 **6** 处,逐文件集合差实测:全是「非编号」判定栏里既定的噪声名与裸形盲区(哈希算法名、总线名、严重度档位、硬件位号),不是编号,不清。本笔动的 3 处只是写法:作废的网络条目孤儿号(F 前缀 + 模块码段 + 数字序号三段)与已删报告的 UI 簇(字母 U 紧跟一位数字,区间两端即该簇首尾两枚);事实本体仍在别名表、registry 游标备注与 git 历史,一处没丢。刻意不动:硬件位号形态的举例(判非编号)、保留现存号族的冻结游标数字(冻结水位的证据本体)、其它文档与注册表里的同名字段(各自写域)。§5.5 同步写死该例外的硬口径。零代码、零编号增删、两根护栏基线均未调整。 | | 2026-10-27 | **批次五:「数据可信」任务卡号整族清退 + 注入验证卡销项删行** | 用户指令「数据可信.md 已经完成的内容请进行销项删除,去除相关编号」。实测 **288 站点 / 56 文件**(代码与测试 191 / 文档 56 / 门禁配置与本文 41)全改语义短语;§5 表首列由「序」改「标识(任务名)」、14 个旧号进 §9.3 换算表;顺带按属主文档判语义清掉同形态的悬空引用 4 处(「UI 补齐」波次的 `[comm]` 段前置项)。门禁面:编号字面量与不可判定绝对数**零变化**(中文前缀不在语料),收口复跑 `check_ids.py --strict` 与 `check_doc_links.py --all --sections-strict` | | 2026-10-27 | **批次四:`L-PROT` / `FEAT` 发号口关闭(§4.1 七行→五行)+ 本文自述形态化 + 登记 `T-TEST` 机器面空白** | 用户指令「语义标识已定为默认形态,看看还有哪些编号族仍被引用、各自还剩多少,把能清的族清掉一批」。按门禁 `Checker` 实测三口径重打 §9 存量表:**真编号活引用只剩 `TC-*`(保留、水位 497/81 未涨)、`TRAP-*`、`CODE-RULE-*`、`MENU-STATE-*` 四族**,批次一/二涉及的 `N-*`/`TM-*`/`T-TEST`/`L-PROT`/`FEAT` 活引用均已归零。本笔:① §4.1 把 `L-`、`F--` 从『允许继续发号』整行移出并在『已停发』栏各写一行(含探针证据:新形态号 → 校验 3 错误级);② 本文 6 处形态自述改「字母+数字」描述,使四个族门禁命中归零、lesson 不丢;③ registry 给 `L-PROT`/`FEAT` 补 `retired`、给 `T-TEST` 补 cursor_note(pattern 上限即 3 → 冻结游标是空操作,停发今天只有规范效力);④ 分类登记 §4.4 误判面(版本记号 / 活表代号 / 状态组合 / 位号)与 §4.3 冻结波次号两类**不清**的理由。未改门禁判定逻辑、未动冻结历史与原始串口日志、未新增任何号。 | -| 2026-10-27 | **批次一 `F-*` 收口:网络设计 12 个条目号转「条目名」语义短语,§7 表加「条目名」列为权威对照** | 用户指令「把网络设计里的 `F-*` 条目号换成语义短语,别改坏硬件资料的 T1/T2/T3 位号和 Mermaid 节点名」。走 `scripts/rename_ids.py`(映射 `scripts/rename_maps/batch7-f-net-semantic.json`,`--no-alias` 后手工写别名),10 处定点改写=属主文档正文 9 处(含 1 处孤儿号删号留事实)+ `test/host/net_socket/net_socket_test.c` 注释 1 处;孤儿号(F 前缀 + 模块码段 + 数字序号的三段形态;§7 从无定义行)删号留事实、不补定义;13 个旧号标 `retired-to-phrase`。刻意不动:§7 编号列(历史对照)、`BSD_Socket_API_使用指南.md` 变更记录行、`docs/硬件平台/` 位号、Mermaid 节点名。`scripts/id_registry.json` FEAT `cursor_note` 改记停发口径(三模块各有最高号 → 不冻结游标的理由写在里面)。零代码语义变更。 | -| 2026-10-27 | **停发机械化落地:34 个 `TC-HOST-*` 子族游标冻结,§8 校验 5 开始咬新配的 TC 号** | 上一笔把缺口登记为「停发今天只有规范效力」并写明机械化怎么做;本笔照它落地、把话兑现:`scripts/id_registry.json` 37 个 TC 类族全部 `frozen: true`,34 个子族的 `cursor` 冻结在裁定日存量最高号(字符串形态——整型比较静默不生效;5 个低于存量的已抬:`TC-PROTELEM-013→015`、`TC-SYSLOG-108→137`、`TC-ADCHEALTH-011→023`、`TC-ADCCAL-017→023`、`TC-I104SRV-041→053`),理由记在顶层 `tc_freeze_2026_10_27`。探针(Checker `_check_frozen`):在 `TC-PROTSET-` 段存量最高号之上再加一号 → 命中 1 条校验 5,写存量最高号本身 → 零误伤;`check_ids.py --only 5` = 0 处;plain 与 `--strict` 的错误级 findings 与本笔前逐条相同(**12 条 `TC-TIMESYNC-0xx` 悬空引用属另一道在飞的 time_sync 改动,不在本笔写域,也没替它改**);台账 0 条、可判定 87.67%、不可判定 979 / 上限 1,166,不动 §8.1。**没有把主族 `TC` 说成已冻结**:它 `cursor` 仍为 `null`,§4.1 框内第三条与 §9.1 末段把这块空白及其兜底(校验 3 + 冻结水位 564/474/79 只减不增 + 评审)写明,并规定「给这些模块补号即使在文档里补了定义行也算违令」。§9.1 末段由「效力边界」改写为「机器口径已落地」,当日实测留作历史不抹。零代码、零编号增删。 | +| 2026-10-27 | **批次一 `F-*` 收口:网络设计 12 个条目号转「条目名」语义短语,§7 表加「条目名」列为权威对照** | 用户指令「把网络设计里的 `F-*` 条目号换成语义短语,别改坏硬件资料的 T1/T2/T3 位号和 Mermaid 节点名」。走 `scripts/rename_ids.py`(映射 `scripts/rename_maps/batch7-f-net-semantic.json`,`--no-alias` 后手工写别名),10 处定点改写=属主文档正文 9 处(含 1 处孤儿号删号留事实)+ `test/host/net_socket/net_socket_test.c` 注释 1 处;孤儿号(F 前缀 + 模块码段 + 数字序号的三段形态;§7 从无定义行)删号留事实、不补定义;13 个旧号标 `retired-to-phrase`。刻意不动:§7 编号列(历史对照)、`BSD_Socket_API_使用指南.md` 变更记录行、`docs/硬件平台/` 位号、Mermaid 节点名。`scripts/archive/id_gate/id_registry.json` FEAT `cursor_note` 改记停发口径(三模块各有最高号 → 不冻结游标的理由写在里面)。零代码语义变更。 | +| 2026-10-27 | **停发机械化落地:34 个 `TC-HOST-*` 子族游标冻结,§8 校验 5 开始咬新配的 TC 号** | 上一笔把缺口登记为「停发今天只有规范效力」并写明机械化怎么做;本笔照它落地、把话兑现:`scripts/archive/id_gate/id_registry.json` 37 个 TC 类族全部 `frozen: true`,34 个子族的 `cursor` 冻结在裁定日存量最高号(字符串形态——整型比较静默不生效;5 个低于存量的已抬:`TC-PROTELEM-013→015`、`TC-SYSLOG-108→137`、`TC-ADCHEALTH-011→023`、`TC-ADCCAL-017→023`、`TC-I104SRV-041→053`),理由记在顶层 `tc_freeze_2026_10_27`。探针(Checker `_check_frozen`):在 `TC-PROTSET-` 段存量最高号之上再加一号 → 命中 1 条校验 5,写存量最高号本身 → 零误伤;`check_ids.py --only 5` = 0 处;plain 与 `--strict` 的错误级 findings 与本笔前逐条相同(**12 条 `TC-TIMESYNC-0xx` 悬空引用属另一道在飞的 time_sync 改动,不在本笔写域,也没替它改**);台账 0 条、可判定 87.67%、不可判定 979 / 上限 1,166,不动 §8.1。**没有把主族 `TC` 说成已冻结**:它 `cursor` 仍为 `null`,§4.1 框内第三条与 §9.1 末段把这块空白及其兜底(校验 3 + 冻结水位 564/474/79 只减不增 + 评审)写明,并规定「给这些模块补号即使在文档里补了定义行也算违令」。§9.1 末段由「效力边界」改写为「机器口径已落地」,当日实测留作历史不抹。零代码、零编号增删。 | | 2026-10-27 | **停发口径收口:`TC-*` 从『允许继续发号』表整行移出,并登记「机器面还没冻结」这个缺口** | 裁定上一笔已入档,但效力写在了会被扫表读过的地方:`TC-*` 仍占着「允许继续发号」表第一行、用途列还写着「要进 C 断言标签」,那句"注意它已停发"只是表前的脚注;而那张表连表头行都在早先瘦身时丢了(GFM 里表格不能紧跟段落,整张塌成正文)。本笔:① 移出该行、补回表头与空行,『允许继续发号』写成**恰好 7 行**;② 表下加防误读框,把「不做了」的两条误读各钉一次——「维持原状所以还能发」与「停发所以顺手清掉/复用号」,并写明唯一重启入口 = 先裁定再回本节改表;③ 实测登记效力边界:registry 37 个 TC 类族仍有 35 个 `frozen: false` 带活游标,§8 第 5 项碰不到它们(且 `cursor` 为空时该校验直接跳过),所以停发今天只有规范效力,机械化单独开卡走 §7.3;④ §5.1 补「不在 7 行内第 ① 步就走不通」、§9.1 两条硬口径扩成三条(新增「停发 ≠ 待清」)并补效力边界段、§9.2 计数 8 → 7。同步:`AGENTS.md` 索引行、`docs/测试说明/测试文档模板规范.md` §6.3、`docs/门禁说明/host-unit-tests.md` §7 号段行(那里原文写着「新增用例要带号」,是最直接的误读源头)。零代码、零编号增删。 | | 2026-10-27 | **批次三裁定「不做」:`TC-*` 保留现状但即日停发** | 用户原话「批次三,不坐」(即不做)。裁定写进 §9.1 批次三(含理由与两条硬口径)、§4.1『已停发』栏加一行、§9 结果表同步。停发的硬口径:游标冻结、现存号只减不增、**新用例一律用语义化测试函数名 + 文档表格行名,不再配 `TC-` 号**;真要清则先让追溯器同时认新旧两种形态、核对通过后单独开卡,不许先改文档再改代码(会造悬空号)。留着的判据依据:`TC-*` 是 §4.1 那条判据(有脚本按字面量匹配)唯一真满足的族,字母号的痛在「人读」侧,解法是不再造给人读的号,而不是拆掉机器面的把手。 | | 2026-10-27 | **语义标识定为唯一默认形态;编号收窄为「机器按字面量匹配」的例外,并首次给出现量清点与三批计划** | 用户原话:「不要用字母加数字的编号,简直太难以理解了,语义标识是最好的」。本笔:① 标题下的一句话从「允许用号的族只有 8 个」改成「语义标识是唯一默认、编号是例外」,并把 §4.1 拆成『允许继续发号』8 族与『已停发、存量待清』4 族(`N-*` / `TM-*` / 台架阶段裸形 / `F-*`)——原表自称穷举,实际漏登记了这三类在用族,属真缺陷。② 新增 §9 存量清点(用门禁自身接口实测:26 族仍有引用、565 个字面量、1,108 个引用站点)与三批计划:批次一 62 站点不碰门禁即可清、批次二保护功能号 184 站点转功能名、批次三 `TC-*` 561 站点需先换追溯机制(等用户裁定)。③ §8.1 基线按 2026-10-27 复测重打:784 文件 / 7,828 字面量、护栏 2 实跑 1,161 / 上限 1,166。 | -| 2026-10-26 | **编号治理收口:清死号 → 停发活号 → 本文重写为短版(用户三次裁定)** | 全仓字母+数字编号 10,956 → 8,230 处。① **清死号**:属主登记处已删或从未启用的号一律就地删号留事实、禁补号(文本实删约 1,557 处)。② **停发活号**:登记簿 `N-x`/`S-x`/`T-x`、专项(A 前缀 + 数字)、已删报告的 UI 簇(字母 U 紧跟一位数字,区间两端即该簇首尾两枚)共 20 个号转成语义短语(约 418 处)——登记簿表首格就是短语,旧号进 `scripts/id_aliases.json` 标 `retired-to-phrase`;已销项的死号**故意不进别名表**,让门禁继续咬残留引用。③ **本文瘦身**:619 行 → 229 行,删掉八原则长表、迁移映射表、模块码表与门禁细节(那些各有事实源:registry / 别名表 / `docs/门禁说明/id-check.md`),改成「先问三句再决定要不要发号」+ §4.1 允许用号的族**穷举 = 8 个**。④ **门禁配套**:`check_ids.py` 加变更记录行豁免与第二根护栏 `undecidable_total_ceiling`(比值会被清号动作稀释,绝对数不会),债务台账还清到 0 条 → `--strict` 实为全量拦截,比例基线重打为 86.0%。**本表按用户 2026-10-26 的明确指示只保留最近一条**,更早沿革看 `git log` 与 `docs/门禁说明/id-check.md` §7.5(含其后的方案 B 一节);这是**本文档的例外**,不改变 §5.5对其他文档「冻结历史不回改」的约束。 | +| 2026-10-26 | **编号治理收口:清死号 → 停发活号 → 本文重写为短版(用户三次裁定)** | 全仓字母+数字编号 10,956 → 8,230 处。① **清死号**:属主登记处已删或从未启用的号一律就地删号留事实、禁补号(文本实删约 1,557 处)。② **停发活号**:登记簿 `N-x`/`S-x`/`T-x`、专项(A 前缀 + 数字)、已删报告的 UI 簇(字母 U 紧跟一位数字,区间两端即该簇首尾两枚)共 20 个号转成语义短语(约 418 处)——登记簿表首格就是短语,旧号进 `scripts/archive/id_gate/id_aliases.json` 标 `retired-to-phrase`;已销项的死号**故意不进别名表**,让门禁继续咬残留引用。③ **本文瘦身**:619 行 → 229 行,删掉八原则长表、迁移映射表、模块码表与门禁细节(那些各有事实源:registry / 别名表 / `docs/门禁说明/id-check.md`),改成「先问三句再决定要不要发号」+ §4.1 允许用号的族**穷举 = 8 个**。④ **门禁配套**:`check_ids.py` 加变更记录行豁免与第二根护栏 `undecidable_total_ceiling`(比值会被清号动作稀释,绝对数不会),债务台账还清到 0 条 → `--strict` 实为全量拦截,比例基线重打为 86.0%。**本表按用户 2026-10-26 的明确指示只保留最近一条**,更早沿革看 `git log` 与 `docs/门禁说明/id-check.md` §7.5(含其后的方案 B 一节);这是**本文档的例外**,不改变 §5.5对其他文档「冻结历史不回改」的约束。 | diff --git a/docs/门禁说明/README.md b/docs/门禁说明/README.md index 20d929ad..81d9787e 100644 --- a/docs/门禁说明/README.md +++ b/docs/门禁说明/README.md @@ -1,6 +1,6 @@ # 门禁逐项说明(每种门禁一篇) -> 这一目录回答一个问题:**提交时那 52 个钩子到底在干什么、拦谁、放谁、什么时候会骗人。** +> 这一目录回答一个问题:**提交时那 51 个钩子到底在干什么、拦谁、放谁、什么时候会骗人。** > 每个门禁一篇,八段固定结构:查什么 / 为什么要它 / 触发面 / 报错怎么读 / 好处 / > **限制与盲区** / 豁免与基线 / 改门禁本身要注意什么。**最后一节是这套文档存在的理由**—— > 一份只看"拦了什么"的门禁文档,会让人以为绿就是对的。 @@ -8,16 +8,16 @@ - 配置事实源:`.pre-commit-config.yaml`。**钩子数的唯一口径 = YAML 解析后的 hook 条目数**,不是文件里的文本行数。 自查(打印声明数;加/删一条钩子后,这个数要与 **AGENTS.md 的「共 N 个钩子」**、**本目录 §2 标题**同时对齐): `& '.venv\Scripts\python.exe' -c "import yaml; d=yaml.safe_load(open('.pre-commit-config.yaml', encoding='utf-8')); print(sum(len(r['hooks']) for r in d['repos']))"` - → **52**(2026-10-26:49 → 50 加 `generated-fresh`;2026-10-27:50 → 51 加 `nested-comment`; - 2026-10-28:51 → 52 加 `id-check-new`——编号门禁第二步,与 `id-check` 双跑观察)。 + → **51**(2026-10-26:49 → 50 加 `generated-fresh`;2026-10-27:50 → 51 加 `nested-comment`; + 2026-10-28:51 → 52 加 `id-check-new`、随即 52 → 51 摘掉 `id-check`(退役全库语料审计))。 ⚠ **别用 `grep -c` 去数配置里的声明行**:该文件里有一条**注释掉的**候选钩子(clang-format,第 65 行), - 文本 grep 会多算 1 = 53——「声明 53 / 文档 52 / 实跑 52」这种三个数不同源的争执就是这么来的。真要 grep, + 文本 grep 会多算 1 = 52——「声明 52 / 文档 51 / 实跑 51」这种三个数不同源的争执就是这么来的。真要 grep, 用只认行首缩进的模式直接数是 52(含那一条注释掉的候选,故与 YAML 口径差 1)。 ⚠ 反过来的坑也真踩过(2026-10-27):在配置**注释里复述那个 grep 字面量**,会让文本 grep 再虚高 1—— 数数只认 YAML 解析,注释与文档里都别写出那个字面量(`docs/门禁说明/nested-comment.md` §8 记了现场)。 实跑侧口径:`scripts/ci_local.py` 的 `[SUMMARY] L0: pre-commit hooks -- passed=A failed=B skipped=C`, - `A+B+C` = **commit 阶段**的钩子数(51),再加 `gitlint` 1 条(它的 commit-msg 阶段声明写在**上游**仓库自带的 - 钩子清单里,本配置文件里查不到,见 `scripts/ci_local.py` 文件头)→ 51 + 1 = 52 = 声明数,三数同源。 + `A+B+C` = **commit 阶段**的钩子数(50),再加 `gitlint` 1 条(它的 commit-msg 阶段声明写在**上游**仓库自带的 + 钩子清单里,本配置文件里查不到,见 `scripts/ci_local.py` 文件头)→ 50 + 1 = 51 = 声明数,三数同源。 - 通用机制(两阶段、stash 陷阱、`always` 已废、增量拦截三段式、旧 §2.x 查号表): `docs/代码规范/pre-commit使用说明.md` §2。 - 快速自查(不等提交):`& '.venv\Scripts\python.exe' scripts/ci_local.py`(L0 + L0b + L0.5)。 @@ -28,19 +28,19 @@ |---|---|---|---| | **改写型** | 不报错,直接改你的文件 | `trailing-whitespace`、`end-of-file-fixer` | 重新 `git add` 被改的文件再提交(它改的是工作区,不是索引) | | **硬拦截** | 违反即失败,没有存量豁免 | `cppcheck`、`coding-standard`、`doc-links`、`no-mojibake`、`mem-budget`、`ui-golden`、`font-charset`、`lv-conf-sync`、`task-table`、`mem-numbers`、`registration-check`、`cubemx-survival`、`test-suite-switch`、16 个主机单测、官方 5 个、`gitlint` | 只能改代码或改文档;**不要**找豁免开关 | -| **增量拦截** | 规则恒生效,但存量钉在基线/台账里,只许减不许增 | `layer-deps`(3 条,2026-10-25 还清 UI 记录 3 条)、`bsp-err`(38 条)、`id-check`(`scripts/id_known_backlog.json` 台账)、`generated-fresh`(5 处 `docs/images/` 配图存量,脚本内 `BASELINE`) | -| **只查新增** | 只看本次改动的增量,没有存量基线,也没有台账 | `id-check-new` | 改成语义短语,或把设备名/协议名登记进脚本白名单(行内 `[编号豁免]` 是最后手段) |、`nested-comment`(2 处主机侧假件头,`test/host/common/`,脚本内 `BASELINE`) | 报错先分清是**新增**还是**存量搬家**:`--verbose` 看归类,`--prune` 看已还清 | +| **增量拦截** | 规则恒生效,但存量钉在基线/台账里,只许减不许增 | `layer-deps`(3 条,2026-10-25 还清 UI 记录 3 条)、`bsp-err`(38 条)、`generated-fresh`(5 处 `docs/images/` 配图存量,脚本内 `BASELINE`)、`nested-comment`(2 处主机侧假件头,`test/host/common/`,脚本内 `BASELINE`) | 报错先分清是**新增**还是**存量搬家**:`--verbose` 看归类,`--prune` 看已还清 | +| **只查新增** | 只看本次改动的增量,没有存量基线,也没有台账 | `id-check-new` | 改成语义短语,或把设备名/协议名登记进脚本白名单(行内 `[编号豁免]` 是最后手段) | ⚠ 增量拦截最容易误会的一点:**绿灯不等于没问题**,只等于"没有比上次更差"。 每个增量拦截门禁的基线数字都写进它自己的文档,读那篇时第一眼看的就是"现在在册多少条"。 -## 2. 索引(52 个 hook → 28 篇 + 1 根只有本表指针(专篇待补)+ 1 根详解在 docs/测试说明/) +## 2. 索引(51 个 hook → 28 篇,其中 1 篇是已退役门禁的留档 + 1 根只有本表指针(专篇待补)+ 1 根详解在 docs/测试说明/) | 门禁文档 | 覆盖的 hook id | 一句话它在查什么 | 改了哪类文件才会跑 | 文档 | |---|---|---|---|---| | [`bsp-err.md`](bsp-err.md) | `bsp-err` | BSP 的对外 API 面:错误通道类型、超时宏命名、必须写返回值、返回值不得裸丢弃 | `Drivers/BSP/**` 或门禁自身 | 已写 | | [`layer-deps.md`](layer-deps.md) | `layer-deps` | 分层方向:`Drivers/BSP/**` 不得 include `App/**` | `Drivers/BSP/**` | 已写 | -| [`id-check.md`](id-check.md) | `id-check` | 实体编号的八项校验(未登记前缀、裸形、重复定义、孤儿、悬空引用…) | 几乎所有文本文件 | 已写 | +| [`id-check.md`](id-check.md) | ~~`id-check`~ | **已退役(2026-10-28)**:全库语料的八项校验,留档备查;现行编号门禁见下一行 | 在时有:几乎所有文本文件 | 已写(退役留档) | | [`id-check-new.md`](id-check-new.md) | `id-check-new` | **只查新增行**有没有新造编号(零语料前缀白名单,已停发族只告警) | 任意 md/c/h/py/yaml/txt | 已写 | | [`doc-links.md`](doc-links.md) | `doc-links` | 文档里的路径引用是否存在;`--sections-strict` 另查章节号是否还存在 | 任意 `.md` | 已写 | | [`cppcheck.md`](cppcheck.md) | `cppcheck`、`test-cppcheck` | 静态分析(真机侧与 `test/` 侧两套范围与抑制项) | C/H 源文件 | 已写 | diff --git a/docs/门禁说明/host-unit-tests.md b/docs/门禁说明/host-unit-tests.md index a8467792..17a321f1 100644 --- a/docs/门禁说明/host-unit-tests.md +++ b/docs/门禁说明/host-unit-tests.md @@ -127,7 +127,7 @@ - 用例号段:`TC-HOST-<模块码>` 以 `test/host/<目录>/*` 为属主登记处(`docs/编号规范.md` §4.1); **该号段 2026-10-27 起停发新号**(用户裁定「批次三,不坐」):新增用例**不配号**,写语义化测试函数名, 现存号只读、不清、不复用。追溯器只双向比对已有集合,**不会**因为新用例没号而报错——别把它当"要带号"。 - **机器口径同日已落地**:`scripts/id_registry.json` 37 个 TC 类族全部 `frozen: true`,34 个子族游标冻结在 2026-10-27 存量最高号, + **机器口径同日已落地**:`scripts/archive/id_gate/id_registry.json` 37 个 TC 类族全部 `frozen: true`,34 个子族游标冻结在 2026-10-27 存量最高号, 在号段上再加新号 = `id-check` 校验 5 错误级;无专属子族的模块码落在主族 `TC`(游标仍为空),那一面由校验 3 + 冻结水位 + 评审兜住 → `docs/编号规范.md` §4.1 末框与 §9.1 末段。 diff --git a/docs/门禁说明/id-check.md b/docs/门禁说明/id-check.md index f2044d5d..1b7c86c0 100644 --- a/docs/门禁说明/id-check.md +++ b/docs/门禁说明/id-check.md @@ -1,13 +1,20 @@ -# `id-check` — 编号门禁(实体编号的八项校验) +# `id-check` — 编号门禁(实体编号的八项校验)——**已退役(2026-10-28)** + +> ⚠ **本文是退役留档,不要照着它去改门禁。** +> 2026-10-28 用户裁定:编号体系本身不再产生价值,全库语料审计的维护成本高过收益 +> → 钩子摘除(52 → 51),脚本与两份语料整体移入 `scripts/archive/id_gate/`; +> **现行编号门禁 = `id-check-new`**(只查新增行、零语料)→ `docs/门禁说明/id-check-new.md`。 +> 退役路线与判据替换 → `docs/编号规范.md` §8.5。下面保留退役前的原样描述与实测基线, +> 只在手工复查「存量编号现状」时还用得上。 > 一句话:它管**"号"这个东西不许野生**——每个编号必须属于一个已登记的族、形态合法、 > 有定义处、有人引用、引用它的时候说清是哪篇文档的号。 > 规范正文 = `docs/编号规范.md`(§1 先问三句、§4.1 允许用号的族〔穷举〕、§8 门禁与实测基线),本门禁是那八项的机械执行。 -- 配置:`entry: python scripts/check_ids.py --strict`,`pass_filenames: false`, +- 配置:`entry: python scripts/archive/id_gate/check_ids.py --strict`,`pass_filenames: false`, `files:` 覆盖 `.md/.c/.h/.py/.yaml/.json/.txt` 与配置文件本身。 -- 两份数据源(不是脚本里写死的):`scripts/id_registry.json`(族 → 形态正则 / 属主登记处 / - 是否冻结 / 游标 / 作用域 / 级别)、`scripts/id_aliases.json`(旧字面量 → 现行字面量)。 +- 两份数据源(不是脚本里写死的):`scripts/archive/id_gate/id_registry.json`(族 → 形态正则 / 属主登记处 / + 是否冻结 / 游标 / 作用域 / 级别)、`scripts/archive/id_gate/id_aliases.json`(旧字面量 → 现行字面量)。 ## 1. 它在查什么 @@ -58,10 +65,10 @@ → 改引用/补登记处;确属该欠的债要在台账写 reason(默认禁止顺手加) ``` -- 单独跑:`& '.venv\Scripts\python.exe' scripts/check_ids.py --strict --verbose`(`--verbose` 带修法,`--top 30` 多打,`--only 1,3,5` 只跑指定校验)。 +- 单独跑:`& '.venv\Scripts\python.exe' scripts/archive/id_gate/check_ids.py --strict --verbose`(`--verbose` 带修法,`--top 30` 多打,`--only 1,3,5` 只跑指定校验)。 - 常用旗标:`--strict`(钩子用的档位)、`--verbose`、`--write-backlog` / `--prune-backlog` (重建 / 收紧台账)、`--update-baseline`(把当前可判定比例写回 `id_registry.json`,只许涨)、`--no-trace`。 -- 存量在 `scripts/id_known_backlog.json`(按指纹豁免,实跑 **0 处 / 0 类指纹**在册;HEAD 台账 303 条指纹 / 651 处)。 +- 存量在 `scripts/archive/id_gate/id_known_backlog.json`(按指纹豁免,实跑 **0 处 / 0 类指纹**在册;HEAD 台账 303 条指纹 / 651 处)。 ## 5. 好处 @@ -112,8 +119,8 @@ ## 7. 豁免与台账口径 -- 存量:`scripts/id_known_backlog.json`(指纹级);**只减不增**,收紧用 `--prune-backlog`。 -- 别名:`scripts/id_aliases.json`(旧字面量 → 现行字面量)——号改名走 `scripts/rename_ids.py`, +- 存量:`scripts/archive/id_gate/id_known_backlog.json`(指纹级);**只减不增**,收紧用 `--prune-backlog`。 +- 别名:`scripts/archive/id_gate/id_aliases.json`(旧字面量 → 现行字面量)——号改名走 `scripts/rename_ids.py`, 它会显式写别名条目,**绝不全局查找替换**。 - 比例基线:`id_registry.json` 的 `decidable_ratio_baseline`(实跑当前 86.01%,基线 86.0%、容差 0.1pp)。 @@ -202,7 +209,7 @@ **每批自证没吃余量(可复制的做法,五项式)**: -1. 改之前先跑一次 `./.venv/Scripts/python.exe scripts/check_ids.py`,记下三个数:字面量总数、可判定、 +1. 改之前先跑一次 `./.venv/Scripts/python.exe scripts/archive/id_gate/check_ids.py`,记下三个数:字面量总数、可判定、 不可判定绝对数。⚠ `--strict` 只回答「有没有新错误级」,**不回答可判定占比动了没有**——别拿它当替身。 2. 改完再跑一次,逐数比对。 3. 若绝对数涨了,先确认是不是本批吃的账。**不要用 `git stash` / `git checkout` 去回退**(那会把别人在飞的 @@ -214,7 +221,7 @@ **手工把上限调高等于自废这道闸,任何时候都不许做。** ## 8. 改这个门禁本身 -- 改族定义 = 改 `scripts/id_registry.json`,改完必须看**编号字面量总数有没有变小**: +- 改族定义 = 改 `scripts/archive/id_gate/id_registry.json`,改完必须看**编号字面量总数有没有变小**: 历史上两次批量改名后,识别正则的上界没跟着放宽,**整批号不再被匹配**(等于静默放行)。 - 不要为了绿而往台账加 reason;确实该欠的债要写清楚原因(默认禁止顺手加)。 - 台账文件自身不是语料(见 §6 第 6 条),改动它之后要单跑一次确认没有自循环新账。 diff --git a/scripts/README.md b/scripts/README.md index c51cd4a0..5870b23d 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -13,10 +13,10 @@ | `check_mojibake.py` | `Forbid U+FFFD mojibake` | 扫描 `U+FFFD` 乱码(`EF BF BD` 字节) | | `check_doc_links.py` | `doc-links` | **文档链接存在性** + 命名规范 + **`§N.M` 章节引用**(口径见 `docs/文档规范.md` §3.5)。钩子已带 `--sections-strict`(自引用失效也拦);`--section-todo` 列出机器判不了目标的 `§`(带改写建议)。每次跑打印「可判定比例」行,防覆盖率回落 | | `section_aliases.json` | (被 `check_doc_links.py` 读) | 文档**昵称别名表**:「内存方案」→ `docs/内存管理/RAM使用分析与优化方案.md`。只登记无歧义昵称;登记一次即把该昵称的引用纳入硬门禁 | -| `check_ids.py` | `id-check` | **编号门禁**:`docs/编号规范.md` §8 的八项校验(未登记前缀 / 形态 / 悬空 / 重复定义 / 越游标 / 未紧邻文档名 / 孤儿 / 可判定比例)。**已关闸为增量拦截**:钩子带 `--strict`,只拦 `scripts/id_known_backlog.json` 台账之外的新错误级问题(存量按指纹豁免、台账只减不增);可判定比例跌破基线任何模式都失败。详表(含限制与盲区)→ `docs/门禁说明/id-check.md` | +| `check_ids.py` | ~~`id-check`~(已退役) | **编号门禁(已退役,2026-10-28)**:`docs/编号规范.md` §8 的八项校验(未登记前缀 / 形态 / 悬空 / 重复定义 / 越游标 / 未紧邻文档名 / 孤儿 / 可判定比例)。**已关闸为增量拦截**:钩子带 `--strict`,只拦 `scripts/archive/id_gate/id_known_backlog.json` 台账之外的新错误级问题(存量按指纹豁免、台账只减不增);可判定比例跌破基线任何模式都失败。详表(含限制与盲区)→ `docs/门禁说明/id-check.md` | | `id_registry.json` | (被 `check_ids.py` 读) | 前缀族**注册表**:属主登记处 / 形态正则 / 冻结 / 游标,逐项来自 `docs/编号规范.md` §4;`decidable_ratio_baseline` = 校验 8 的基线(只许涨)。与 `section_aliases.json` 同一套"别名表 + 可判定比例"范式 | | `id_aliases.json` | (被 `check_ids.py` 读) | 编号**别名/作废表**:旧字面量 → 现行字面量或 `status: void`(如已销项的旧号仍被引用 → `status: void`、模块码 `PHY→NET`) | -| `check_test_traceability.py` | (被 `id-check` 顺带调用) | **TC 用例双向追溯**:文档 ↔ 代码两侧的 TC 编号集合比对;2026-10-20 起范围扩到 `test/host/` 与 7 篇「单元测试说明.md」(`--board-only` 回退旧板级口径)。此前该脚本**未挂任何钩子** | +| `check_test_traceability.py` | (原被 `id-check` 顺带调用;后者已退役) | **TC 用例双向追溯**:文档 ↔ 代码两侧的 TC 编号集合比对;2026-10-20 起范围扩到 `test/host/` 与 7 篇「单元测试说明.md」(`--board-only` 回退旧板级口径)。此前该脚本**未挂任何钩子** | | `gen_task_table.py` | `task-table` | FreeRTOS 任务表以 `Src/freertos.c` 为**唯一事实源**生成/校验 | | `check_mem_numbers.py` | `mem-numbers` | 内存/Flash 数字以 `.map` 为唯一事实源校验(体积档) | | `check_test_suite.py` | `test-suite-switch` | 测试套件开关=产品构建(防测试固件静默提交) | diff --git a/scripts/archive/id_gate/README.md b/scripts/archive/id_gate/README.md new file mode 100644 index 00000000..9e1f3d62 --- /dev/null +++ b/scripts/archive/id_gate/README.md @@ -0,0 +1,41 @@ +# 编号门禁·全库语料审计(已退役,2026-10-28 归档) + +本目录是 2026-10-20 ~ 2026-10-28 期间在 `pre-commit` 里跑的那套**全库编号审计**, +连同它的两份语料一起搬进来,**不再进提交门禁**。 + +| 文件 | 是什么 | +|---|---| +| `check_ids.py` | 八项校验脚本(规范 §8)。手工复查存量编号现状时才跑 | +| `id_registry.json` | 99 族的注册表:形态正则 / 属主登记处 / 冻结 / 游标 / 两条护栏的数值 | +| `id_aliases.json` | 旧号 → 新号 / 作废(`retired-to-phrase`、`void`)的别名表,187 KB | +| `id_known_backlog.json` | 债务台账(收口时已还清到 0 条) | + +## 为什么退役 + +实测拆账:单次运行只有 **1.8 s**,但**近 80 笔提交里 61 笔**改了语料 / 门禁 / 规范; +99 族里 78 族已冻结。真正值得机械守的只剩一件事——**别新写一个自造编号**, +而那件事不需要语料(判据只要「这个前缀我没见过」)。 + +## 现在用什么 + +- **现行门禁**:`scripts/check_ids_new.py` + 钩子 `id-check-new` —— 只查 `git diff` 新增行, + 零语料。详解 `docs/门禁说明/id-check-new.md`。 +- **路线与验收条件**:`docs/编号规范.md` §8.5(①②③ 三步的来龙去脉)。 +- **规范正文**(仍然有效,只是不再全库机械校验):`docs/编号规范.md` §1 先问三句、§4.1 族总表。 + +## 怎么手工跑一次 + +```text +& '.venv\Scripts\python.exe' scripts/archive/id_gate/check_ids.py # 全库报告 +& '.venv\Scripts\python.exe' scripts/archive/id_gate/check_ids.py --top 30 # 多看几条 +``` + +退出码:0 = 无错误级 / 仅告警;1 = 有错误级(`--strict` 语义);2 = 环境错误。 +注意:它扫的是 `git ls-files`,所以**未跟踪文件不在扫描面**(退役前的实测盲区)。 + +## 归档纪律 + +- 这两份语料**不再维护**:不要为了让报告变绿去改 `id_registry.json` / `id_aliases.json`。 +- `scripts/rename_ids.py` 仍会往归档的 `id_aliases.json` 写条目(改名工具没退役)—— + 那是它自己的账,与本目录的"冻结快照"性质不同,改名前先想清楚是否还要记这笔。 +- 真要恢复全库校验,先读 `docs/编号规范.md` §8.5 再决定,别直接把它塞回钩子。 diff --git a/scripts/check_ids.py b/scripts/archive/id_gate/check_ids.py similarity index 97% rename from scripts/check_ids.py rename to scripts/archive/id_gate/check_ids.py index 0e937ca8..24510204 100644 --- a/scripts/check_ids.py +++ b/scripts/archive/id_gate/check_ids.py @@ -1,7 +1,15 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ -check_ids.py — 编号门禁(docs/编号规范.md §8 的 8 项校验)。 +check_ids.py — 编号门禁(docs/编号规范.md §8 的 8 项校验)——**已退役(2026-10-28)**。 + +⚠ 退役说明(先读这段,别把它当活门禁用): + 本脚本与两份语料(id_registry.json / id_aliases.json)已整体移入 scripts/archive/id_gate/, + **不再进 pre-commit**,也不再有人被要求维护语料。现行编号门禁是 scripts/check_ids_new.py + (钩子 id-check-new:只查新增行、零语料)。本脚本保留下来只做一件事: + 想复查「存量编号现状」时手工跑一遍出报告。 + 路线与判据替换的来龙去脉 → docs/编号规范.md §8.5;新门禁详解 → docs/门禁说明/id-check-new.md。 + 下面这份 docstring 是退役前的原样,未改,作为历史口径保留。 两份配置(数据源 = 规范 §4 编号空间总表,逐项对应,不凭印象): scripts/id_registry.json 前缀族 → {形态正则, 属主登记处, 是否冻结, 游标, 作用域, 级别} @@ -55,9 +63,12 @@ for _stream in (sys.stdout, sys.stderr): if hasattr(_stream, "reconfigure"): _stream.reconfigure(encoding="utf-8", errors="replace") -REPO_ROOT = pathlib.Path(__file__).resolve().parent.parent -REGISTRY_FILE = REPO_ROOT / "scripts" / "id_registry.json" -ALIASES_FILE = REPO_ROOT / "scripts" / "id_aliases.json" +# 退役后本脚本住在 scripts/archive/id_gate/:仓库根是往上第 4 层, +# 两份语料与本脚本同目录(一起搬进来的,不跟着仓库结构再挪)。 +HERE = pathlib.Path(__file__).resolve().parent +REPO_ROOT = HERE.parents[2] +REGISTRY_FILE = HERE / "id_registry.json" +ALIASES_FILE = HERE / "id_aliases.json" TRACE_SCRIPT = REPO_ROOT / "scripts" / "check_test_traceability.py" # 候选池:任何「1~4 位大写字母 + 连字符 + 数字」先进来,再判是否登记过。 @@ -681,7 +692,7 @@ def parse_only(s): return {int(x) for x in re.split(r"[,\s]+", s) if x.strip().isdigit()} -BACKLOG_FILE = REPO_ROOT / "scripts" / "id_known_backlog.json" +BACKLOG_FILE = HERE / "id_known_backlog.json" def err_groups(ck): diff --git a/scripts/id_aliases.json b/scripts/archive/id_gate/id_aliases.json similarity index 100% rename from scripts/id_aliases.json rename to scripts/archive/id_gate/id_aliases.json diff --git a/scripts/id_known_backlog.json b/scripts/archive/id_gate/id_known_backlog.json similarity index 100% rename from scripts/id_known_backlog.json rename to scripts/archive/id_gate/id_known_backlog.json diff --git a/scripts/id_registry.json b/scripts/archive/id_gate/id_registry.json similarity index 99% rename from scripts/id_registry.json rename to scripts/archive/id_gate/id_registry.json index 11e44fc7..ad9b91c7 100644 --- a/scripts/id_registry.json +++ b/scripts/archive/id_gate/id_registry.json @@ -29,6 +29,7 @@ "N": "登记簿 N-x(§4.1 在册保留):连字符形才是规范形态" }, "excluded_paths": [ + "scripts/archive/", "Lib/", "Middlewares/", "Drivers/CMSIS/", diff --git a/scripts/check_doc_links.py b/scripts/check_doc_links.py index 1abc1e7a..923593bb 100644 --- a/scripts/check_doc_links.py +++ b/scripts/check_doc_links.py @@ -49,6 +49,8 @@ REPO_ROOT = pathlib.Path(__file__).resolve().parent.parent SKIP_PARTS = ("node_modules", ".venv", ".git", "build", "obj", "__pycache__", "Lib/lvgl", "simulator/SDL2", ".opencode/node_modules", ".workbuddy-ai", # 本地记忆/会话数据,非项目文档 + ".mnemon", # 同上:记忆工具的版本快照目录,已 .gitignore + "ci-artifacts", # 本地临时/草稿目录,已 .gitignore,不是项目文档 "docs/芯片手册") # 外部数据手册转录,非项目自有文档,链接形态不受控 # Markdown 链接:[text](target)。目标须以「非空白、非右括号」构成, diff --git a/scripts/check_ids_new.py b/scripts/check_ids_new.py index 27f82b09..ec765f4e 100644 --- a/scripts/check_ids_new.py +++ b/scripts/check_ids_new.py @@ -91,10 +91,11 @@ EXCLUDED_DIRS = ( "MDK-ARM/RTE/", "simulator/SDL2/", "simulator/build/", "simulator/tests/ref/", ".venv/", "ci-artifacts/", "test/board/third_party/", "scripts/rename_maps/", "tools/netlist_semantics/", ".dsh/skills/", "__pycache__/", + "scripts/archive/", # 2026-10-28 退役的全库编号语料:里面全是编号字面量,天经地义 + ) EXCLUDED_FILES = frozenset({ - "scripts/id_registry.json", "scripts/id_aliases.json", "scripts/id_known_backlog.json", - "scripts/check_ids.py", "scripts/check_ids_new.py", + "scripts/check_ids_new.py", # 本脚本自带正反例白名单,不能自我拦截 }) EXCLUDED_SUFFIX = (".svg", ".png", ".jpg", ".jpeg", ".gif", ".bin", ".map", ".htm", ".html", ".tsv", ".log", ".o", ".axf", ".hex", ".ico", ".ttf", ".woff", ".pyc", diff --git a/scripts/rename_ids.py b/scripts/rename_ids.py index 1dba21e7..a9b45862 100644 --- a/scripts/rename_ids.py +++ b/scripts/rename_ids.py @@ -40,7 +40,8 @@ import re import sys REPO_ROOT = pathlib.Path(__file__).resolve().parent.parent -ALIASES_FILE = REPO_ROOT / "scripts" / "id_aliases.json" +# 2026-10-28 编号门禁退役:别名表随语料一起搬进 scripts/archive/id_gate/ +ALIASES_FILE = REPO_ROOT / "scripts" / "archive" / "id_gate" / "id_aliases.json" # 与 scripts/id_registry.json 的 excluded_paths 同口径(改名同样不该碰这些语料) EXCLUDED = [