fix(门禁): 批 5 追溯器口径补齐——变更记录行不参与双向比对(未改任何号)

结论先行:我上一轮说「批 2 模块码单词化漏扫了 4 篇属主文档」——**被证据推翻**

- 依据是 check_test_traceability.py 报的 DOC-ONLY 38 处里有 8 处旧模块码
  (TC-AI-070/080/090、TC-PH-001/030、TC-TS-001、TC-VL-001),我据此写好了
  逐号点名的改名映射表准备落盘
- 改名工具干跑 **0 处命中**:查下去这 8 处**全部在变更记录行**(| 2026-10-10 | … |)里,
  写的是**当年**的用例名;按编号规范 §8.1 冻结历史不回改,旧号靠别名解析——
  而 TC-AI-070 → TC-ADCIN-070 这批**早在批 2 就已登记在 id_aliases.json**
- 所以照原计划改等于**销毁历史记录、收益为零**。真缺口是判据:追溯器是唯一
  没有「变更记录 / [示例] / [计划] 行豁免」的一支(check_ids / rename_ids /
  doc-links 都有),它把冻结历史当活引用 → 系统性假阳性

改了什么(判据,不改数据)
- check_test_traceability.py 加 SKIP_LINE(与另三支脚本同源的豁免正则),两侧采集
  都改为逐行判定,被豁免的号收进 frozen_ids 留痕,--verbose 全量列出——
  **豁免不等于已对应**,别拿它当收敛
- 顺带把 has_intent() 的判定范围从整文件收窄到**同号所在行**(意图必须写在号旁边,
  原先整文件里任何位置有人话就算过关,太松)

实测(关键是"没吞掉真对应")
- DOC-ONLY 38 → **29**(−9 全是冻结行假阳性,**不是真变好**);总差异 45 → 36
- **交集 260 → 260 不变**:豁免只吐冻结行,没有让任何一条真实对应消失
- 代码侧 578 个号不变(识别面没缩,这是改名/改判据最容易踩的坑)
- 错误级 632 不变(追溯不参与错误级计数);可判定比例 83.02%;--strict 通过

剩 29 处是真问题,但**不是编号问题**(要人裁决,不由门禁决定)
- 4 处无模块码形态(TC-1003 / TC-206 / TC-501 / TC-704):② 大批的文档侧镜像
- TC-NET-607 一条是历史指称(原文「原 TC-NET-607/608/609,现 701/702/703」),
  一对多写不进一对一的别名表
- TC-NET-302/401/402/501 标题明写「(硬件层)」= 人工台架步骤,代码无载体是预期
- 其余 20 处(TC-NET-101/102/1101/601/606/701~704/801/802/901/902/1006/1501~1503、
  TC-GD5F-503)**全库无任何载体**:文档声明了用例而代码/台架/模拟器都没有实现

另一个我自己的错误,记进 §8.3 而不只是提交信息
- 补别名时把 8 个键写到了 JSON **顶层**(真容器是 aliases,515 条)→ 条目完全无效;
  是 assert k not in d['aliases'] 拦下的,删掉无效键后 id_aliases.json 字节与 HEAD 一致
- 教训:DOC-ONLY 这类两侧字面比对差异,先判它是不是冻结行/别名可解析,再谈改数据;
  改名工具 0 命中与 assert 失败都是**信号**,不是小故障

文档:docs/编号规范.md §8.1 口径修正记录 + §8.3 批 5 行与经过段(含被推翻的判断)+ 变更记录;
docs/代码规范/pre-commit使用说明.md §2.25 顺带收编行同步;脚本 docstring 同步

验证:check_doc_links.py --all 143 篇 0 失效;id-check --strict 通过;三个改动文件
BOM=否、CR=0;未改 C/H,不需 @build;台账无需收账(本轮 0 处销账)
This commit is contained in:
2026-10-21 13:25:06 +08:00
parent 52976bdec3
commit 43fbfa140b
3 changed files with 55 additions and 7 deletions
+1 -1
View File
@@ -455,7 +455,7 @@ cppcheck 是开源 C/C++ 静态分析工具,**不运行代码**,通过语法
| **八项校验**([示例] 本行引用的是各种非法形态示例,不是真实编号) | ①未登记前缀 ②形态不合规(裸形 `S3` / 空格形 `Trap 07` / 中文形 `陷阱 1` / 补零错 / 档位词带后缀 / 大写后缀 / 缺模块码)③悬空引用 ④重复定义 ⑤冻结前缀越游标 ⑥文档内编号未紧邻文档名 ⑦孤儿条目(告警)⑧可判定比例(只许涨不许跌) |
| **配置两份** | `scripts/id_registry.json`:前缀族 → 属主登记处 / 形态正则 / 是否冻结 / 游标,**逐项来自 `docs/编号规范.md` §4 总表**,游标取「规范记载值」与「全库实测最大号」的较大者,偏差写进 `cursor_note`(实测偏差见规范 §8.2);`scripts/id_aliases.json`:旧号 → 新号 / 作废标记(照搬 `section_aliases.json` 的成功范式) |
| **判定口径** | 「定义」= 字面量出现在该族**属主登记处文档**里(不依赖表格行首等易漂移形态)→ §5.5「销项 = 删行 + 清全库引用」只做一半,校验 ③ 立刻报(`N-31`/`N-32` 正是这条)。「重复定义」= 字面量出现在**定义位**(表格首格 / 标题行 / 列表项行首),正文提到不算,否则任何交叉引用都会误判成事故。多族同形时的定族顺序:所在文档即属主 > 紧邻属主线索 > **定义位优先**(`docs/编号规范.md` §4.3 冻结快照族 `N-RPT`/`D-RPT`/`S-RPT`/`R-RPT`/`F-RPT`/`P-AUDIT`/`A-AUDIT`/`B-AUDIT` **不参与**——否则已销项的登记簿 `N-21` 会被审计报告同号接管,门禁反过来教人补错文档名,实测把校验 6 从 266 撑到 1437、可判定比例假崩到 68.7%)> 判悬空的族 > 全局族;小写子项后缀(`-b`/`-c`)在母号在册时视为已定义(`subitem_ok`),差异仍由双向追溯如实报 |
| **顺带收编**([示例] 本行引用了非法形态示例号)| `scripts/check_test_traceability.py`(TC 用例双向追溯)由本钩子一并调用:正则补齐 `TC-[A-Z]{1,4}-\d{3,4}[a-z]?` 与大写后缀 / 无模块码形态(旧 `TC-[A-Za-z0-9]+-\d+` **整条漏扫** `TC-ADCIN-01A`),比对范围从「`test/board/*.c` ↔ `*_Test_Guide.md`」扩到 `test/host/` 一侧 + 7 篇「单元测试说明.md」(差异从 33 处涨到 326 处——**原口径漏的正是主机侧单测这一半**),另加 `--board-only` 回退旧口径。**2026-10-21 同口径改写**:差异分三档 `DOC-ONLY`(文档声明而代码没有,真断链 38)/ `CODE-ONLY`(代码有、母号不在登记处且号旁无意图,真未登记 7)/ `IN-CODE`(靠号旁写着意图放过 238,**弱于文档的保证,单列示数不算过关**);另修 `TC_RE` 模块码上界 `{0,4}`→`{0,8}`(批 2 单词化后代码侧一度从 556 缩到 217) |
| **顺带收编**([示例] 本行引用了非法形态示例号)| `scripts/check_test_traceability.py`(TC 用例双向追溯)由本钩子一并调用:正则补齐 `TC-[A-Z]{1,4}-\d{3,4}[a-z]?` 与大写后缀 / 无模块码形态(旧 `TC-[A-Za-z0-9]+-\d+` **整条漏扫** `TC-ADCIN-01A`),比对范围从「`test/board/*.c` ↔ `*_Test_Guide.md`」扩到 `test/host/` 一侧 + 7 篇「单元测试说明.md」(差异从 33 处涨到 326 处——**原口径漏的正是主机侧单测这一半**),另加 `--board-only` 回退旧口径。**2026-10-21 同口径改写**:差异分三档 `DOC-ONLY`(文档声明而代码没有,真断链 38)/ `CODE-ONLY`(代码有、母号不在登记处且号旁无意图,真未登记 7)/ `IN-CODE`(靠号旁写着意图放过 238,**弱于文档的保证,单列示数不算过关**);另修 `TC_RE` 模块码上界 `{0,4}`→`{0,8}`(批 2 单词化后代码侧一度从 556 缩到 217) |。**批 5(2026-10-21)再补口径**:变更记录行与 `[示例]`/`[计划]` 行不参与双向比对(冻结历史按 §8.1 不回改、旧号靠别名解析),`DOC-ONLY` 38 → 29 且交集 260 不变;被豁免的号进 `frozen_ids`,`--verbose` 列出——**豁免不等于已对应** |
| **最新实测(2026-10-21,B 层口径后)** | 8322 处编号字面量 / 可判定 **82.71%**(6883/8322);错误级 711 = ②398 + ③44 + ⑥269,告警级 ③223 + ⑦100。⚠ **与 2026-10-20 的 1312 不可直接比**:其中 504 处属**口径修正**(主机侧单测 118 号实测在代码目录外零消费者,改认 `test/host/<目录>/*` 为属主登记处;子项后缀母号在册即算已定义),74 处属我修的**注册表漏配属主**(活登记处在 `docs/任务规划/README.md`,`N-21` 在其中出现 2 次而我只登记了 `登记簿.md`),**真正变好 0 处**——完整对照见 `docs/编号规范.md` §8.1 口径修正记录 |
| **有牙实测(牙齿)**([示例] 下列字面量是注入用的假编号) | 注入打在临时档(`git add -N` 进索引,跑完 `git rm --cached` + 删除,`git status` 干净):`Z-99`→①、裸形 `S3`→②、`TC-NET-9999`→③、第二篇属主文档重复定义 `DP-01`→④、`E-70`→⑤(`E-xx` 冻结于 `E-63`)、裸引 `D-7`→⑥;六项分别被对应校验点名,`--strict` 退出码 1 |
| **显式盲区(不是"检查通过")** | ① 裸形同字母多义(§1.2:`P1` 五义 / `L1` 四义 / `U1` 四义 / `D7` 三义)与元器件位号同形(§4.4)→ 裸形族**只在属主登记处文档内**判越游标,文档外降告警;② 圈号编号(①②③…)与正常列举无法机械区分,不入判定;③ `docs/芯片手册/`、`docs/硬件平台/` 整体排除(位号 `B1`/`C1`/`L1` 与编号同形,是撞形根源)。前两块收口属 §9 阶段 1-②/1-③ 迁移批次,落地后再扩判定范围——盲区登记在 `id_registry.json` 的 `blind_spots` / `unmanaged_bare` |
+25
View File
@@ -424,6 +424,7 @@ git grep -n '<旧字面量>' # 零残留
| `excluded_paths` 加 `scripts/id_aliases.json`、`scripts/id_registry.json` | 别名表/注册表**自身不得制造引用面**——上批别名条目一度成为这些号的唯一"外部引用" | 极小 |
| **追溯脚本同口径对齐**(`check_test_traceability.py`):文档声明了代码没有 = DOC-ONLY 真断链(38);代码有、母号不在登记处**且号旁没写人话意图** = CODE-ONLY 真未登记(7);代码有但旁边写着意图 → 单列 `IN-CODE`(238),**弱于文档的保证,禁止当成已登记** | B 层认代码为属主后,老口径「每个号都必须出现在文档」与门禁自相矛盾——照它升 `--strict` 会拦死 173+ 处本不该写文档的号,逼出 `--no-verify`,门禁公信力就是这么没的 | 差异从 284 降到 45(38+7),另 238 处转入「看得见但不过关」的 `IN-CODE` 账 |
| ⚠ 同批改名要复核**所有**识别面:`TC_RE` 也停在 `{0,4}`,模块码单词化后代码侧集合从 556 悄悄缩到 217(339 个号隐形),已放宽到 `{0,8}` | 这是「改名必须连带复核判据面」教训的**第二次发生**,发生在另一支脚本上 | 修回后代码侧 578 |
| **追溯器补上「变更记录 / `[示例]` / `[计划]` 行」豁免**(`check_test_traceability.py`,与 `check_ids.py` / `rename_ids.py` / `doc-links` 同一条口径) | 追溯器是**唯一没这条豁免**的一支:它把冻结历史当活引用,凡变更记录里写过的旧用例号一律要求代码里也存在同号 (例:`\| 2026-10-10 \| 新增 TC-AI-070..078 \|` 写的是**当年**的名字,号在批 2 已改成 `TC-ADCIN-*`,按 §8.1 历史行不回改 → 拿它去代码里找同号必然落空) | `DOC-ONLY` 38 → **29**(−9 全是假阳性,**不是真变好**)。关键佐证:**交集 260 → 260 不变**——豁免没有吞掉任何一条真对应,只吐出了冻结行 |
| 已销项历史任务号 `T-2`/`T-3`/`T-4`/`T-6` 入别名表(`status: void`) | §5.5「销项 = 删行 + 清引用」只做了一半的欠账;本条只让门禁停止把它当自造号,并如实指路 | 悬空错误 −35 |
**修正后实测(2026-10-21)**:错误级 **711**(B 层前 1318)= ②398 + ③44 + ⑥269;告警级 ③223 + ⑦100;可判定比例 **82.71%**(6883/8322),基线仍 82.6%。
@@ -448,6 +449,7 @@ git grep -n '<旧字面量>' # 零残留
| 批 | 日期 | 族 | 旧 → 新 | 处数 / 文件 | 别名 |
|---|---|---|---|---|---|
| **批 5(口径)** | 2026-10-21 | 追溯器豁免 | **未改任何编号**:给 `check_test_traceability.py` 补与其它三支工具同源的「变更记录 / `[示例]` / `[计划]` 行不比对」口径 + `--verbose` 打印被豁免的 9 个号 | 判据改动;`DOC-ONLY` 38 → 29、交集 260 不变 | 无新增(`TC-AI-070` 等 8 个旧号**早在批 2 就已在别名表**,本批一度以为缺、写错层级后被 assert 拦下) |
| **批 4(Trap)** | 2026-10-21 | 陷阱号形态 | `Trap 01~07` → `TRAP-GD5F-01~07`、`陷阱 1` → `TRAP-RTC-01`、`Trap 21`/`Trap 19` → `TRAP-NET-21`/`TRAP-NET-19`、`见陷阱 01` → `TRAP-GD5F-01` | 23 处 / 11 文件(含 `Drivers/BSP/GD5F2GQ5UE/*` 注释 4 处、`test/board/*` 2 处) | 11 条全部带 scope;映射表即审计轨迹 `scripts/rename_maps/batch3-trap.json` |
| **批 1** | 2026-10-20 | 代码规范条款 | `S1`~`S19` → `CODE-RULE-01`~`19` | 78 处 / 2 文件 | 18 条(scoped:`scripts/check_coding_standard.py`、`docs/代码规范/pre-commit使用说明.md`) |
| **批 3(口径)** | 2026-10-21 | 主机侧单测归属 | 建 9 族 `TC-HOST-*`(代码即属主)+ `subitem_ok` + `snapshot_only` + 补 README 属主 + `T-x` 入别名 | 判据与注册表改动,未改任何存量号 | 见 §8.1 口径修正记录 |
@@ -458,6 +460,28 @@ git grep -n '<旧字面量>' # 零残留
---
**批 5 的经过值得记一笔:我的判断被自己的证据推翻了两次**
1. 我据 `DOC-ONLY` 38 处判定「批 2 模块码单词化漏扫了 4 篇属主文档」(`TC-AI-070/080/090`、
`TC-PH-001/030`、`TC-TS-001`、`TC-VL-001`),并写好了逐号点名的映射表准备改名。
2. 改名工具干跑 **0 处命中** → 查下去发现这 8 处**全部位于变更记录行**(`| 2026-10-10 | … |`),
按 §8.1 属冻结历史、**本就不该回改**;再查别名表,`TC-AI-070 → TC-ADCIN-070` 这批
**早在批 2 就已登记**。也就是说:真要按原计划改,是在销毁历史记录,而收益是零。
3. 我顺手补别名时把键写到了 JSON **顶层**(真容器是 `aliases`,515 条),条目完全无效——
是 `assert k not in d['aliases']` 把它拦下来的;删掉无效键后该文件字节与 HEAD 完全一致。
**教训写在这里而不只是提交信息里**:`DOC-ONLY` 这类"两侧字面比对"的差异,**先判它是不是冻结行/
别名可解析**,再谈改数据;改名工具的 0 命中和 assert 失败都是**信号**,不是小故障。
**剩 29 处 `DOC-ONLY` 是真问题,但不是编号问题**(`--verbose` 可复现全清单):
- 4 处无模块码形态(`TC-1003`、`TC-206`、`TC-501`、`TC-704`)——属 ② 大批的文档侧镜像;
- `TC-NET-607` 一条是**历史指称**:原文写「原 TC-NET-607/608/609,现 701/702/703」,
一条对三条,别名表是一对一模型,写不进别名;
- `TC-NET-302/401/402/501` 标题明写「(硬件层)」= 人工台架步骤,代码里没有实现载体**是预期**;
- 其余 20 处(`TC-NET-101/102/1101/601/606/701~704/801/802/901/902/1006/1501~1503` 与
`TC-GD5F-503`)**全库无任何载体**(代码、台架脚本、模拟器都没有)——文档声明了用例而没有实现,
这三类要不要各立口径(人工台架豁免 / 历史指称 void 别名 / 真未实现登记待办),**属产品裁决,不由门禁决定**。
**批 4 刻意不改的三处(写清楚,别被当成漏网)**
- `docs/环境与部署/并行任务工作树方案.md` 里的 `wip/trap22-fix` 是 **git 分支名**,不是编号——
@@ -534,6 +558,7 @@ git grep -n '<旧字面量>' # 零残留
|---|---|---|
| 2026-10-14 | 新增 P-7 与引用可读性规则 | §2 加 **P-7「编号不语义,引用必语义」**(编号本体保持无语义并冻结,但正文引用必须带语义括注、禁裸 ID 独担信息)→ 六条原则变**七条**;§5.1 加前置步"先问能不能不加号";新增 **§5.6「编号密集文档的对照节(强制)」**(≥3 个编号族必须加「导读:编号与术语」);§4.1 补登记 **`E\d+`**(N34 自愈实验编号族,已封闭)并把 `N-\d{2}` 的在册范围订正为「曾用最大 `N-33`,现存至 `N-29`」;§1.2 悬空引用示例补 `N-32`;§7.1 同步订正。起因:`docs/网络/网络自愈架构设计.md` 合并与导读节实践暴露"裸编号引用不可读",用户裁定以后尽量用语义标识 |
| (规划稿) | 建立本文档 | 全库扫描 1,385 个不同编号 / 19,306 处出现后定稿的两层编号体系(全局编号 + 文档内编号)、六条原则、目标前缀总表、三批迁移映射与 `check_ids.py` 门禁设计;用户决策:`E-xx` 冻结保留、严重度档位词 `P0~P3` 不变、文档落 `docs/编号规范.md`、阶段 1 三批全做 |
| 2026-10-21 | **批 5:追溯器口径补齐(未改任何号)** | `check_test_traceability.py` 加入与 `check_ids.py`/`rename_ids.py`/`doc-links` 同源的「变更记录 / `[示例]` / `[计划]` 行不参与比对」豁免,并新增 `frozen_ids` 留痕(`--verbose` 可列);`DOC-ONLY` 38 → 29、总差异 45 → 36,**交集 260 → 260 不变**(证明没吞掉真对应)。批 5 原计划的 8 处文档侧改名**被证据否掉**(全在变更记录行、别名批 2 已登记),未落盘;经过与教训、以及剩 29 处的三类真问题都写进 §8.3 批 5 段 |
| 2026-10-21 | **批 4:陷阱号统一(② 清的第一族)** | 23 处 / 11 文件:`Trap 01~07` → `TRAP-GD5F-01~07`(属主文档 7 个标题行从此成为定义位)、`陷阱 1` → `TRAP-RTC-01`、`Trap 21`/`Trap 19` → `TRAP-NET-21`/`TRAP-NET-19`;UI 文档自指改写成平实语言。别名 11 条全部带 scope。改名后 `TRAP-GD5F-01/05/06` 三处历史悬空引用自动落地为已定义;三处刻意不改与 `docs/硬件平台/` 盲区写进 §8.3 批 4 |
| 2026-10-21 | **关闸:`id-check` 转增量拦截** | `check_ids.py` 新增 `--write-backlog` / `--prune-backlog` 与按台账比对的 `--strict`(指纹 = 文件 + 校验号 + 字面量 + 计数,**不含行号**);生成 `scripts/id_known_backlog.json`(340 条覆盖 710 处存量);钩子 `entry` 加 `--strict`。验收三例:新字面量拦、同号计数增长拦、干净态放行,全通过。新增 §8.4 说明机制与「为什么不照清零再升 strict 的原节奏」 |
| 2026-10-21 | **追溯脚本同口径对齐** | `check_test_traceability.py` 差异定义改为 DOC-ONLY / CODE-ONLY / IN-CODE 三档(真差异 45 = 38 + 7;弱保证 238 单列示数);顺带修 `TC_RE` 模块码上界 `{0,4}`→`{0,8}`——**同一个坑第二次踩**(代码侧一度从 556 缩到 217),已写进 §8.1 |
+29 -6
View File
@@ -27,6 +27,8 @@
② 代码有、母号不在文档、**且号旁边没写人话意图** → CODE-ONLY(真未登记);
③ 代码有、靠"旁边有意图"放过 → 单独打印为 IN-CODE,**弱于文档**,不算已登记。
小写子项后缀(`TC-XXX-003b`)按母号算(`subitem_ok`),与编号门禁同口径。
**2026-10-21 第二次口径修正(批 5)**:变更记录行与 `[示例]`/`[计划]` 行**不参与比对**
(冻结历史按编号规范 §8.1 不回改,旧号靠 `id_aliases.json` 解析;这条豁免另三支脚本早有,本脚本是最后缺它的一个,`DOC-ONLY` 因此 38 → 29、交集不变);被豁免的号存进 `frozen_ids`,`--verbose` 全量列出——**豁免不等于已对应**,别拿它当收敛。
退出码:
0 = 无差异;或有差异但**默认仅告警**(与 doc-links 演进路径一致)
@@ -64,6 +66,14 @@ TC_RE = re.compile(r"TC-(?:[A-Z][A-Z0-9]{0,8}-\d{1,4}[A-Za-z]?|\d{2,4}[a-z]?)")
TC_CANON_RE = re.compile(r"^TC-[A-Z][A-Z0-9]{0,8}-\d{3,4}[a-z]?$") # 与 §4.1 实测形态同步
# 占位符前缀(文档模板里的 `TC-XXX-…`)不参与比对
PLACEHOLDER_PREFIXES = {"XXX"}
# 与 check_ids.py / rename_ids.py / check_doc_links.py **同一套**豁免口径:
# 变更记录行与 [示例] / [计划] 行是**冻结历史或写法示例**,不是活引用(§8.1 纪律:
# 历史行里的旧号不回改,靠别名表解析)。追溯器原先缺这一条,产生系统性假阳性——
# 2026-10-21 实测:DOC-ONLY 38 处里 12 处来自变更记录行,例如
# `| 2026-10-10 | 新增 TC-AI-070..078(70 → 79 用例)|` 写的是**当年**的用例名,
# 该号在批 2 已随代码改名成 TC-ADCIN-*,历史行不该回改,拿它去代码里找同号必然落空。
SKIP_LINE = re.compile(r"\[示例\]|\[计划\]|^\s*\|\s*20\d\d-\d\d-\d\d\s*\|")
frozen_ids: set = set() # 只在 --verbose 里列:被豁免的号(历史/示例),不是"已对应"
def _prefix(tc: str) -> str:
@@ -100,18 +110,24 @@ def collect(paths, label, want_intent=False):
"""返回 (ids_set, per_prefix_counts[, intent_set])。逐文件扫描,缺文件不致命。"""
ids = set()
intents = set()
global frozen_ids
for p in paths:
try:
text = p.read_text(encoding="utf-8", errors="replace")
except OSError as e: # pragma: no cover - 环境错误
print(f"[ERR] 无法读取 {p}: {e}", file=sys.stderr)
return (None, None, None) if want_intent else (None, None)
for m in TC_RE.findall(text):
if _prefix(m) in PLACEHOLDER_PREFIXES:
continue
ids.add(m)
if want_intent and has_intent(text, m):
intents.add(m)
for line in text.splitlines():
skip = bool(SKIP_LINE.search(line))
for m in TC_RE.findall(line):
if _prefix(m) in PLACEHOLDER_PREFIXES:
continue
if skip: # 冻结历史 / 示例行:不参与双向比对,只留痕
frozen_ids.add(m)
continue
ids.add(m)
if want_intent and has_intent(line, m):
intents.add(m)
counts = {}
for i in sorted(ids):
counts[_prefix(i)] = counts.get(_prefix(i), 0) + 1
@@ -173,6 +189,7 @@ def main():
print(f"代码侧:{len(code_files)} 个文件,{len(code_ids)} 个 TC")
print(f"文档侧:{len(doc_files)} 个文件,{len(doc_ids)} 个 TC")
print(f"交集:{len(code_ids & doc_ids)}")
print(f"豁免:变更记录/[示例]/[计划] 行的号 {len(frozen_ids)} 个(口径同 check_ids.py,见 §8.1)")
if args.verbose:
print("--- 各前缀 TC 计数(代码 / 文档)---")
@@ -194,6 +211,12 @@ def main():
for i in code_only_in_code:
print(f" {i}")
if args.verbose and frozen_ids:
print("--- 被豁免的号(变更记录 / [示例] / [计划] 行,共 %d 个)**不是已对应**,"
"历史旧号靠 id_aliases.json 解析 ---" % len(frozen_ids))
for i in sorted(frozen_ids):
print(" ", i)
if not doc_only and not code_only:
print("\n[OK] 双向一一对应,无差异")
return 0