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 反例仍全过。
This commit is contained in:
2026-10-28 12:38:38 +08:00
parent a5832788e9
commit 1668842d61
20 changed files with 152 additions and 107 deletions
+2 -2
View File
@@ -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` | 测试套件开关=产品构建(防测试固件静默提交) |
+41
View File
@@ -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 再决定,别直接把它塞回钩子。
@@ -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):
@@ -29,6 +29,7 @@
"N": "登记簿 N-x(§4.1 在册保留):连字符形才是规范形态"
},
"excluded_paths": [
"scripts/archive/",
"Lib/",
"Middlewares/",
"Drivers/CMSIS/",
+2
View File
@@ -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)。目标须以「非空白、非右括号」构成,
+3 -2
View File
@@ -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",
+2 -1
View File
@@ -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 = [