refactor(编号): B 层口径落地——主机侧单测认代码为属主登记处

为什么不是"补 7 篇文档"
- 实测这些号在代码目录外**零消费者**(NANDPORT 47 / PROTELEM 13 / PROTSET 11 /
  FREQ 11 / FTPAUTH 10 / SHA256 8 / SOE 7 / ADCHEALTH 11 / IEC104 23,共 141 号),
  唯一"外部引用"是 scripts/id_aliases.json 自己 → 逐号写文档等于造一份没人读、
  还要跟着代码同步改的复述层(违反"同一事实只在一处详述")

判据与注册表改动
- 新增 9 族 TC-HOST-<模块码>:class 仍为 TC(跨模块同号照旧由校验 4 抓)、
  owner_docs_glob = test/host/<目录>/*、每模块游标做号段不越界(含 IEC104 补漏:
  它上批改名前是纯数字 TC-104-*,没进当时的悬空普查所以漏建族)
- 新旗标 allow_orphans(不补该旗标会让 141 号全变孤儿告警)、
  subitem_ok(小写子项后缀母号在册即算已定义,差异仍由双向追溯如实报)
- snapshot_only:§4.3 冻结快照族不参与"定义位优先"——先试无差别生效时,已销项的
  登记簿 N-21 被审计报告同号接管,校验 6 从 266 暴涨到 1437、可判定比例假崩 68.7%,
  且提示会教人补错文档名(正是 §1.2 的 N-31 撞号制造方式),故回退并改为快照族豁免
- excluded_paths 加 scripts/id_aliases.json 与 scripts/id_registry.json:
  别名表/注册表自身不得制造引用面
- T-2 / T-3 / T-4 / T-6 入别名表标 void(2026-10-02 复审专项条目,销项只删行没清引用)

修自己的漏配(这条是 bug 修复,不是口径)
- N / S-LDG / T-LDG 族漏登记 docs/任务规划/README.md(活登记处,N-21 在其中出现 2 次),
  只登记了 docs/任务规划/登记簿.md(N-21 为 0)→ 74 处真条目被误判

数字与诚实交代
- 错误级 1318 → 711(②398 + ③44 + ⑥269);可判定比例 82.74%(基线 82.6%)
- ⚠ 其中 504 处属**口径修正**、74 处属**修 bug**,**真正变好 0 处**;已在
  docs/编号规范.md §8.1 写口径修正记录表,禁止拿 711 与 1318 直接比
- 文档:§4.1 补 TC-HOST 说明、§8.1 口径修正记录、§8.3 批 3 行、变更记录;
  pre-commit使用说明 §2.25 判定口径与最新实测同步
- 未改任何 C/H,不需 @build;提交钩子即 L0 + L0.5 全量验证
This commit is contained in:
2026-10-21 10:51:25 +08:00
parent bda7ab2b50
commit 4b9a4f4e24
5 changed files with 297 additions and 16 deletions
+25
View File
@@ -304,6 +304,19 @@ class Checker(object):
for f in fams:
if f.get("adjacent_required") and self._has_adjacent_cue(f, line, start):
return f
# **定义位优先**:号在哪个族的属主登记处真定义了,就按那个族判。
# 没有这一条,`TC-NANDPORT-007`(定义在 test/host/nand_port 的 TC-HOST 族)在别处
# 被引用时会落回通用 TC 族(属主 = docs/测试说明/),假报一片悬空。
for f in fams:
# §4.3 **冻结历史快照族不参与定族**:它的号只是当年报告的存档,不是活的属主。
# 否则 `N-21`(登记簿条目已销项)会被报告里同号的另一码事"接管",报出
# "请写《项目审查与优化建议报告》的文档名"——照做就把登记簿条目和审计报告
# 搅成一条,正是 §1.2 的 N-31/N-32 撞号制造方式(实测这么改,属主不明暴涨 392 条、
# 可判定比例假崩到 69.9%)。快照族只在**有紧邻文档名**时才被上面的线索步选中。
if f.get("snapshot_only"):
continue
if literal in self.owner_tokens[f["name"]]:
return f
for f in fams:
if f.get("check_dangling") and f["_owners"]:
return f
@@ -421,6 +434,14 @@ class Checker(object):
if alias_hit(self, literal, rel) or literal in set(fam.get("allow_missing_defs", [])):
self.stats["alias_hits"] += 1
return
if fam.get("subitem_ok"):
# 小写子项后缀(`TC-TIMESYNC-003b`):§4.1 明写「后缀只允许 -<小写字母>」,
# 是**合法形态**,母号在册就算语义可判定;逐条登记子项只会把文档写成代码复述。
# 可见性不丢——check_test_traceability.py 仍按完整字面量报 码有文档无。
base = re.sub(r"[a-z]$", "", literal)
if base != literal and base in self.defined_all:
self.stats["subitem_hits"] += 1
return
sev = fam.get("dangling_outside_owner", "error") if rel not in fam["_owners"] else "error"
self.add(3, sev, rel, lineno, literal,
"悬空引用:%s 在属主登记处(%s)查无定义,也不在别名表里(§8 校验 3)"
@@ -504,6 +525,10 @@ class Checker(object):
for fam in self.families:
if not fam.get("check_dangling") or not fam["_owners"]:
continue
if fam.get("allow_orphans"):
# 属主登记处 = 代码的族(TC-HOST-*):号定义在测试函数上、本来就只在
# 自己文件里出现,按"无人引用"报孤儿是纯噪音(118 条),显式声明不判
continue
for lit in sorted(self.owner_tokens[fam["name"]]):
outside = {r for r in self.refs.get(lit, set()) if r not in fam["_owners"]}
if not outside: