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。
This commit is contained in:
2026-10-29 20:22:47 +08:00
parent 5c64cf0859
commit 51d89cf9d3
13 changed files with 134 additions and 145 deletions
+8 -6
View File
@@ -1,11 +1,12 @@
# 编号门禁·全库语料审计(已退役,2026-10-28 归档)
# 编号门禁归档(两道都已退役:全库语料审计 2026-10-28、新增行检查 2026-10-29)
本目录是 2026-10-20 ~ 2026-10-28 期间在 `pre-commit` 里跑的那套**全库编号审计**,
连同它的两份语料一起搬进来,**不再进提交门禁**。
本目录是 2026-10-20 ~ 2026-10-29 期间在 `pre-commit` 里跑过的**两套编号门禁**,连同它们的
语料与白名单一起搬进来,**都不再进提交门禁**。2026-10-29 的裁定见每篇文末与其留档文档。
| 文件 | 是什么 |
|---|---|
| `check_ids.py` | 八项校验脚本(规范 §8)。手工复查存量编号现状时才跑 |
| `check_ids_new.py` | 只查新增行的那道(2026-10-28 ~ 2026-10-29 在钩子里跑),2026-10-29 用户裁定退役后降为**手工形态普查**;`--self-test` 保留,`REPO_ROOT` 因归档位置深两级改取 `parents[3]` |
| `id_registry.json` | 99 族的注册表:形态正则 / 属主登记处 / 冻结 / 游标 / 两条护栏的数值 |
| `id_aliases.json` | 旧号 → 新号 / 作废(`retired-to-phrase`、`void`)的别名表,187 KB |
| `id_known_backlog.json` | 债务台账(收口时已还清到 0 条) |
@@ -18,9 +19,10 @@
## 现在用什么
- **现行门禁**:`scripts/check_ids_new.py` + 钩子 `id-check-new` —— 只查 `git diff` 新增行,
零语料。详解 `docs/门禁说明/id-check-new.md`。
- **路线与验收条件**:`docs/编号规范.md` §8.5(①②③ 三步的来龙去脉)。
- **没有现行门禁**:接班的 `id-check-new`(只查新增行、零语料)也在 2026-10-29 被用户裁定退役,
脚本进本目录。编号形态此后无机器面,判据 = `docs/编号规范.md` §1 三句自问 + §4.1 族总表 + 评审;
留档 `docs/门禁说明/id-check-new.md`(拦下过什么、为什么退、手工怎么再跑)。
- **路线与验收条件**:`docs/编号规范.md` §8.5(①②③④ 四步的来龙去脉)。
- **规范正文**(仍然有效,只是不再全库机械校验):`docs/编号规范.md` §1 先问三句、§4.1 族总表。
## 怎么手工跑一次
+5 -3
View File
@@ -5,10 +5,12 @@ check_ids.py — 编号门禁(docs/编号规范.md §8 的 8 项校验)—
⚠ 退役说明(先读这段,别把它当活门禁用):
本脚本与两份语料(id_registry.json / id_aliases.json)已整体移入 scripts/archive/id_gate/,
**不再进 pre-commit**,也不再有人被要求维护语料。现行编号门禁是 scripts/check_ids_new.py
(钩子 id-check-new:只查新增行、零语料)。本脚本保留下来只做一件事:
**不再进 pre-commit**,也不再有人被要求维护语料。接班的 scripts/check_ids_new.py
(钩子 id-check-new:只查新增行、零语料)已于 2026-10-29 一并退役,也进了本目录——
**编号形态此后没有机器面**。本脚本保留下来只做一件事:
想复查「存量编号现状」时手工跑一遍出报告。
路线与判据替换的来龙去脉 → docs/编号规范.md §8.5;新门禁详解 → docs/门禁说明/id-check-new.md。
路线(①②③④ 四步)→ docs/编号规范.md §8.5;两道门禁的留档 → docs/门禁说明/id-check.md
与 docs/门禁说明/id-check-new.md。
下面这份 docstring 是退役前的原样,未改,作为历史口径保留。
两份配置(数据源 = 规范 §4 编号空间总表,逐项对应,不凭印象):
+264
View File
@@ -0,0 +1,264 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""check_ids_new.py — 编号门禁·新增行(**已退役 2026-10-29,用户裁定**;本脚本降为手工报告工具)
退役口径:钩子已从 .pre-commit-config.yaml 摘除(YAML 解析条目 52 → 51),编号形态此后
**没有机器面**——靠 docs/编号规范.md §1 的三句自问 + 评审。留档说明 → docs/门禁说明/id-check-new.md。
本脚本与 check_ids.py(2026-10-28 退役的全库八项校验)同处一档:手工复查「这批改动 / 这段历史
里有没有野生编号」时才跑,跑不跑都不影响提交。
判据(三条,都不依赖任何族清单 / 游标 / 属主登记处):
1. 破折形态(形如 前缀-数字,或 前缀-段-数字):首段不在 KNOWN_DASH → FAIL;
在 RETIRED_DASH(已停发族)→ 只 WARN(不拦,提示改语义短语)。
2. 裸形态(大写字母紧跟数字,如 TIM3 / YX15 / TPAFE5160):前缀不在 KNOWN_BARE → FAIL。
3. 单字母+数字(C12 / U15 / L3 / R3)→ **放行**:元件位号与层次号同形,这是本脚本的已知盲区
(与旧门禁的"裸形盲区"同源,见 docs/门禁说明/id-check-new.md §5)。
用法(仓库根;钩子摘除后没有自动调用者,四条都是手工):
python scripts/archive/id_gate/check_ids_new.py # 查暂存区
python scripts/archive/id_gate/check_ids_new.py --worktree # 查工作区未暂存的改动
python scripts/archive/id_gate/check_ids_new.py --range A..B # 查一段提交的新增行
python scripts/archive/id_gate/check_ids_new.py --self-test # 内建正反例自检(改脚本后必跑)
退出码:0 = 通过 / 仅告警;1 = 新增了未知编号;2 = 环境错误。
豁免:行内含 [示例] / [计划] 的行按冻结口径跳过;确需保留的写法在同一行写 [编号豁免]。
"""
import argparse
import re
import subprocess
import sys
from pathlib import Path
# Windows 控制台默认 GBK,文档行里可能带 emoji(❌/✅)→ 打出来会 UnicodeEncodeError。
for _stream in (sys.stdout, sys.stderr):
try:
_stream.reconfigure(encoding="utf-8", errors="replace")
except (AttributeError, ValueError):
pass
# 归档位置比原位置深两级(scripts/archive/id_gate/)→ 上溯到仓库根要 parents[3]
REPO_ROOT = Path(__file__).resolve().parents[3]
# --- 破折形态:首段白名单(活族 + 标准编号;新增族要先登记到这里,这就是"允许用号的唯一口子")
KNOWN_DASH = frozenset({
"FR", # 功能需求号(docs/产品需求/产品需求设计文档.md §4.1 在册保留)
"NFR", # 非功能需求号
"TC", # 主机侧用例号(已停发,但存量引用最多)
"TRAP", # 陷阱台账(TRAP-NET-xx / TRAP-ADC-xx)
"CODE", # 代码规范条目(CODE-RULE-xx)
"MENU", # 菜单状态(MENU-STATE-xx,像素回归引用)
"UTF", # 编码名(UTF-8)
"RS", # 串行标准名(RS-232 / RS-485)
"SHA", # 摘要算法名(SHA-256)
"CRC", # 校验算法名(CRC-16)
"DMA", # DMA 控制器编号(DMA-2,少量文档写法)
})
# --- 已停发的族:新写号只 WARN(存量引用仍大量存在,硬拦会把正常编辑也挡了)
RETIRED_DASH = frozenset({
"N", "S", "T", "A", "E", "D", "L", "P", "F", "H", "Z", "O", # 登记簿 / 专项 / 层次 / 原则等旧族
"GAP", "DR", "MS", "WI", # 其余已转语义短语的族
})
# --- 裸形态:前缀白名单(外设 / 器件 / 协议 / 保护元件 / 点号;按实测普查枚举,几乎不增长)
KNOWN_BARE = frozenset({
# 外设与内核
"TIM", "ADC", "SPI", "DMA", "USART", "UART", "I2C", "CAN", "GPIO", "NVIC", "APB", "AHB", "EXTI",
"IRAM", "IWDG", "WWDG", "FPU", "SRAM", "CCM", "ROM", "RAM", "FLASH", "POR", "BOR", "PIN",
# 引脚名(PA10 / PB10 / PC4 / PD12 / PE3 / PG9 / PH1 ...)
"PA", "PB", "PC", "PD", "PE", "PF", "PG", "PH",
# 器件 / 模块 / 工具链
"STM", "TPAFE", "CH", "SD", "GD", "W25", "SD2506", "LVGL", "RTOS", "OS", "UV", "VS", "SDL", "PROF",
# 协议 / 标准 / 编码
"IEC", "MODBUS", "TCP", "UDP", "FTP", "SNTP", "SOE", "COS", "CRC", "SHA", "IEEE", "ISO", "UTF", "ARGB", "RGB",
# 串行标准(RS232 / RS485 常写成不带连字符的形式)
"RS", "CAN",
# 遥信 / 遥控点号与保护元件代号(协议数据,不是标识符)
"YX", "YK", "YT", "YH", "OC", "UV", "OV", "CP", "VS", "PF", "SV", "AC", "DC", "IA", "IB", "IC", "UN", "UA", "UB", "UC",
# 统计 / 队列 / 结构计数
"AIN", "CTR", "SQRT", "SQR", "LQFP", "DIV", "SCALE", "INTS", "HEX", "TLV", "LNK", "PHASE", "BALA", "ECCS",
"CN", "LED", "DB", "FAT", "AX", "SUB", "CLS", "IN", "BLE", "PH", "SYS", "TE", "LPN", "FF", "HW", "ZL", "RX",
"WSL", "WIN", "GPXTI", "COT", "WRTC", "RM", "CR", "SM", "IP", "COM", "SOCK", "LBA", "BOOT", "EXTKO", "INT",
# RCC_CSR 复位标志位号(BOR25 / PIN26 / POR27 / SFT28 / IWDG29 / WWDG30)
"SFT",
# UART 采样模式位名(OVER8)
"OVER",
# 录波段文件名:固件生成的 100 个号轮转(WAVE00 到 WAVE99 的 .BIN,App/algo/wave_store.c 拼名
# FTP 根下 /wave/ 目录;文档与日志里都要写这个字面量,2026-10-29 登记)
"WAVE",
})
# --- 前缀后面接 -数字 其实是算术(SIZE-2 / LEN-1),不是编号
ARITH = frozenset({"SIZE", "MAX", "MIN", "LEN", "CNT", "NUM", "IDX", "POS", "PTR", "TOP", "END",
"LOW", "HIGH", "ROW", "COL", "BASE", "MASK", "HALF", "NUM", "VAL", "BIT", "BYTE"})
EXCLUDED_DIRS = (
"Lib/", "Middlewares/", "Drivers/CMSIS/", "Drivers/STM32F4xx_HAL_Driver/",
"docs/芯片手册/", "docs/硬件平台/", "docs/images/", "docs/内存管理/data/",
"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/check_ids_new.py", # 本脚本自带正反例白名单,不能自我拦截(归档后整目录已在
# EXCLUDED_DIRS 的 scripts/archive/ 里,这行只是历史留笔)
})
EXCLUDED_SUFFIX = (".svg", ".png", ".jpg", ".jpeg", ".gif", ".bin", ".map", ".htm", ".html",
".tsv", ".log", ".o", ".axf", ".hex", ".ico", ".ttf", ".woff", ".pyc",
".sct", ".lin", ".s", ".bat", ".ps1", ".json")
DASH_RE = re.compile(r"(?<![\w/.-])([A-Z]{1,6})((?:-[A-Z0-9]{1,8})*)-(\d{1,3})(?![\w/-])")
BARE_RE = re.compile(r"(?<![\w/.-])([A-Z]{2,6})(\d{1,4})(?![\w/-])")
SKIP_MARKERS = ("[示例]", "[计划]", "[编号豁免]")
def iter_added_lines(spec):
"""产出 (path, lineno, text):只吐新增行(不含 +++ 头)。spec 见 parse_args。"""
if spec["mode"] == "cached":
cmd = ["git", "-c", "core.quotepath=false", "diff", "--cached", "-U0",
"--diff-filter=ACMR", "--no-color"]
elif spec["mode"] == "worktree":
cmd = ["git", "-c", "core.quotepath=false", "diff", "-U0", "--diff-filter=ACMR", "--no-color"]
else:
cmd = ["git", "-c", "core.quotepath=false", "diff", "-U0", "--diff-filter=ACMR",
"--no-color", spec["range"]]
try:
out = subprocess.run(cmd, cwd=str(REPO_ROOT), capture_output=True, text=True,
encoding="utf-8", errors="replace")
except OSError as exc:
print("[ERR] 无法运行 git:%s" % exc, file=sys.stderr)
raise SystemExit(2)
if out.returncode != 0:
print("[ERR] git 返回 %d:%s" % (out.returncode, (out.stderr or "").strip()[:300]),
file=sys.stderr)
raise SystemExit(2)
path = None
for raw in (out.stdout or "").splitlines():
if raw.startswith("+++ "):
path = raw[4:].strip()
if path.startswith("b/"):
path = path[2:]
continue
if raw.startswith("--- ") or raw.startswith("@@"):
m = re.search(r"\+(\d+)", raw) if raw.startswith("@@") else None
lineno = int(m.group(1)) if m else 0
continue
if raw.startswith("+") and path:
yield path, lineno, raw[1:]
lineno += 1
def path_in_scope(rel):
if rel in EXCLUDED_FILES or rel.startswith(EXCLUDED_DIRS):
return False
return not rel.endswith(EXCLUDED_SUFFIX)
def classify_dash(token):
m = DASH_RE.fullmatch(token)
if not m:
return None
prefix = m.group(1)
if prefix in ARITH or m.group(1) + m.group(2) in ARITH:
return None
if prefix in KNOWN_DASH:
return None
if prefix in RETIRED_DASH:
return "warn"
return "fail"
def classify_bare(token):
m = BARE_RE.fullmatch(token)
if not m:
return None
prefix = m.group(1)
if len(prefix) < 2:
return None
if prefix in KNOWN_BARE:
return None
return "fail"
def scan_lines(lines, show_ok=False):
fails, warns = [], []
for rel, lineno, text in lines:
if not path_in_scope(rel):
continue
if any(mark in text for mark in SKIP_MARKERS):
continue
stripped = re.sub(r"0x[0-9A-Fa-f]+", " ", text)
for m in re.finditer(r"(?<![\w/.-])([A-Z][A-Z0-9]*(?:-[A-Z0-9]+)*-[0-9]{1,3})(?![\w/-])", stripped):
verdict = classify_dash(m.group(1))
if verdict == "fail":
fails.append((rel, lineno, m.group(1), text.strip()[:110]))
elif verdict == "warn":
warns.append((rel, lineno, m.group(1)))
for m in re.finditer(r"(?<![\w/.-])([A-Z]{2,6}[0-9]{1,4})(?![\w/-])", stripped):
if classify_bare(m.group(1)) == "fail":
fails.append((rel, lineno, m.group(1), text.strip()[:110]))
return fails, warns
SELF_TEST_POSITIVE = ["ZZ-9", "NEWFAM-1", "QZ12", "XYZ-3-1", "AB12"]
SELF_TEST_NEGATIVE = ["TC-NET-204", "TRAP-NET-18", "TRAP-ADC-01", "CODE-RULE-20", "MENU-STATE-01",
"FR-UI-2", "UTF-8", "RS-485", "SHA-256", "CRC-16", "TIM3", "YX15", "YK11",
"TPAFE5160", "GD5F2GQ5UE", "CH395F", "SD2506", "STM32F407", "USART1", "PA10",
"C12", "U15", "L3", "R3", "D7", "SIZE-2", "LEN-1", "GPIO_PIN_5", "ADC_CHANNEL_14"]
def self_test():
ok = True
lines = [("t.md", 1, "新增 %s 编号" % t) for t in SELF_TEST_POSITIVE]
lines += [("t.md", 100 + i, "引用 %s 与 %s" % (t, t)) for i, t in enumerate(SELF_TEST_NEGATIVE)]
fails, warns = scan_lines(lines)
hit = {f[2] for f in fails}
for t in SELF_TEST_POSITIVE:
if t not in hit:
print("[FAIL] 自检:正例未被拦下:%s" % t)
ok = False
for t in SELF_TEST_NEGATIVE:
if t in hit:
print("[FAIL] 自检:该放行的被拦了:%s" % t)
ok = False
print("[%s] 自检:%d 个正例全部拦下、%d 个反例全部放行"
% ("OK" if ok else "FAIL", len(SELF_TEST_POSITIVE), len(SELF_TEST_NEGATIVE)))
return 0 if ok else 1
def main(argv=None):
ap = argparse.ArgumentParser(description="只查新增行的新编号(无全库语料)")
ap.add_argument("--worktree", action="store_true", help="查工作区未暂存的改动")
ap.add_argument("--range", metavar="A..B", help="查一段提交(默认查暂存区)")
ap.add_argument("--self-test", action="store_true", help="跑内建正反例自检")
ap.add_argument("--verbose", action="store_true", help="把命中行的原文也打出来")
args = ap.parse_args(argv)
if args.self_test:
return self_test()
spec = {"mode": "range" if args.range else ("worktree" if args.worktree else "cached"),
"range": args.range}
fails, warns = scan_lines(iter_added_lines(spec))
if warns:
print("[WARN] 新增行里出现已停发族的编号 %d 处(不拦提交,但请改成语义短语):" % len(warns))
for rel, lineno, tok in warns[:10]:
print(" %s:%d %s" % (rel, lineno, tok))
if len(warns) > 10:
print(" … 其余 %d 处略" % (len(warns) - 10))
if fails:
print("[FAIL] 新增行里有 %d 处**未登记形态**的字母+数字标识:" % len(fails))
for rel, lineno, tok, text in fails[:20]:
print(" %s:%d %s" % (rel, lineno, tok))
if args.verbose:
print(" %s" % text)
print(" → 语义标识是默认形态:改写成短语(docs/编号规范.md §1);")
print(" 确属设备名/协议名/位号,就改形态(写语义短语)——本门禁已于 2026-10-29 退役,")
print(" 不再是提交钩子;要再拿它当尺子就手工跑 scripts/archive/id_gate/check_ids_new.py。")
return 1
print("[OK] 新增行无未登记编号%s"
% ("(%d 处停发族提示)" % len(warns) if warns else ""))
return 0
if __name__ == "__main__":
sys.exit(main())
@@ -355,7 +355,7 @@ 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` **双跑**一个观察期后再按 `docs/编号规范.md` §8.5 ③ 退役旧语料。 |
| 2026-10-28 | **编号门禁第二步落地:新增行拦截(零语料)** | 脚本(今在 `scripts/archive/id_gate/check_ids_new.py`)+ 钩子 `id-check-new`:只看新增行,破折形态未知前缀 FAIL、已停发族只 WARN、单字母+数字放行(元件位号同形,见该门禁 §6 盲区)。白名单是**前缀级**两张表(活族 11 条 / 器件与协议约 90 条),不是字面量账本——后者会退化成 `id_aliases.json` 的老路。调参依据:最近 80 笔真实提交回放,未知形态 15 种(12 种是设备与协议名、3 种是停发族),调好后误报 0;自检 5 正例 + 29 反例。与 `id-check` **双跑**一个观察期后再按 `docs/编号规范.md` §8.5 ③ 退役旧语料。 |
| 2026-10-28 | **编号门禁减负第一步:两根护栏转报告制** | 用户裁定「编号门禁每次浪费很多时间」→ 先摘掉语料审计的强制面。护栏 1(可判定比例基线)与护栏 2(不可判定绝对数上限)自此**只打印、不拦提交**;实测把基线调到 99.9%、上限调到 1 处,退出码仍为 0。硬拦只剩校验 1~6 的台账外新账(同一实测:新文件里写一个自造前缀 + 数字,校验 1 与增量拦截照旧 FAIL)。退役路线 ①②③ 写进 `docs/编号规范.md` §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 历史,一处没丢。刻意不动:硬件位号形态的举例(判非编号)、保留现存号族的冻结游标数字(冻结水位的证据本体)、其它文档与注册表里的同名字段(各自写域)。`docs/编号规范.md` §5.5 同步写死该例外的硬口径。零代码、零编号增删、两根护栏基线均未调整。 |
| 2026-10-27 | **批次五:「数据可信」任务卡号整族清退 + 注入验证卡销项删行** | 用户指令「数据可信.md 已经完成的内容请进行销项删除,去除相关编号」。实测 **288 站点 / 56 文件**(代码与测试 191 / 文档 56 / 门禁配置与本文 41)全改语义短语;`docs/编号规范.md` §5 表首列由「序」改「标识(任务名)」、14 个旧号进 §9.3 换算表;顺带按属主文档判语义清掉同形态的悬空引用 4 处(「UI 补齐」波次的 `[comm]` 段前置项)。门禁面:编号字面量与不可判定绝对数**零变化**(中文前缀不在语料),收口复跑 `check_ids.py --strict` 与 `check_doc_links.py --all --sections-strict` |