feat(门禁): id-check 关闸——按债务台账增量拦截,warn-only 时代结束
机制(--strict 不再「有错就失败」,而是只拦台账外的新账) - scripts/id_known_backlog.json:340 条指纹覆盖 710 处存量(②167 类 / ⑥135 / ③38) - 指纹 = (文件, 校验号, 字面量) → 计数,故意不含行号:行号每改必漂, 用它当指纹会让台账天天假新增,三天后没人敢看 strict,台账失效比没台账更糟 - 带计数而非集合:同一文件里同一个号多出现一次也算新账(复制粘贴式扩散 正是编号烂掉的主路径,只按「出现过没有」判会放过它) - 新增 --write-backlog 与 --prune-backlog(只减不增;台账内条目变多当场点名); --strict 缺台账返回 2,绝不退化成一次性拦死存量;--only 与 --strict 互斥 - 钩子 entry 加 --strict;--only 与 --strict 互斥 - 顺带修 _scan_malformed 的反向 bug:原条件 (skip and name != "空格形 Trap") 语义正好写反,带 [示例] 的行反而专被 Trap 规则咬;改为示例行全部不判 - 第一次提交就被自己的台账咬住(id_known_backlog.json 里当然写着 P1-3 等号, 被当成新引用)→ 台账加入 excluded_paths:登记号的表不是引用号的文档, 与 id_aliases.json / id_registry.json 同一条道理 为什么不照「清零再升 strict」的原节奏(§8.4 详述) - 存量 710 处清完要数周,这期间新债一条都不拦,而新增才是烂掉主因 - 「等清零」让人习惯「报红但照样提交」,真关闸那天没人再信门禁; 本仓已有 mem-budget / mem-numbers 走 --no-verify 的先例,不再开第二个口子 关闸验收三例(临时件当场还原、git diff 干净) - A 全新前缀 Z-99 → exit 1 点名 ✅ 咬 - B 同号计数 1→2 → exit 1 点名 ✅ 咬 - C 干净态 710 处 → exit 0 放行 ✅ 放(放不住存量就会逼出 --no-verify) 验证:--strict 干净态 exit 0;可判定比例 82.74%(基线 82.6%); doc-links 失效/待确认 0;未改 C/H 不需 @build。 文档:编号规范 §8 上线节奏改写 + 新增 §8.4 机制表;pre-commit使用说明 §2.25; AGENTS.md 门禁行由 warn-only 改为已关闸增量拦截。
This commit is contained in:
+98
-6
@@ -612,11 +612,56 @@ 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"
|
||||
|
||||
|
||||
def err_groups(ck):
|
||||
"""当前错误级问题按 `(文件, 校验号, 字面量)` 归并计数——**债务台账的指纹**。
|
||||
|
||||
指纹故意**不含行号**:行号每编辑一次就漂移,拿它当指纹会让台账天天"新增",
|
||||
三天后 strict 输出全是假警报,没人敢再看——台账失效比没有台账更糟。
|
||||
用**计数**而不是集合:同一文件里同一个号第 N+1 次出现必须能抓出来,
|
||||
复制粘贴式扩散正是编号烂掉的常见路径(§1.2 的跨文档同号不同义就这么来的)。
|
||||
"""
|
||||
g = defaultdict(int)
|
||||
for f in ck.findings:
|
||||
if f.severity == "error":
|
||||
g[(f.rel, f.code, f.literal)] += 1
|
||||
return g
|
||||
|
||||
|
||||
def load_backlog():
|
||||
"""台账 → {(file, code, literal): count};文件不存在返回 None。"""
|
||||
if not BACKLOG_FILE.is_file():
|
||||
return None
|
||||
doc = json.loads(BACKLOG_FILE.read_text(encoding="utf-8"))
|
||||
return {(e["file"], int(e["code"]), e["literal"]): int(e["count"])
|
||||
for e in doc.get("entries", [])}
|
||||
|
||||
|
||||
def backlog_doc(entries, errs, ratio):
|
||||
return {
|
||||
"schema": 1,
|
||||
"note": ("编号债务台账(docs/编号规范.md §8.4):--strict 只对**台账之外**的新错误级问题拦提交。"
|
||||
"台账只许减不许增——还清的用 --prune-backlog 收掉;确需新增一条必须写 reason 字段"
|
||||
"说明这笔债为什么该存在,默认禁止顺手加行(否则一周后台账就变成第二个 backlog)。"
|
||||
"指纹 = 文件 + 校验号 + 字面量,不含行号(行号会漂,用它台账天天假新增)。"),
|
||||
"generated_by": "scripts/check_ids.py --write-backlog",
|
||||
"total_error_findings": errs,
|
||||
"decidable_ratio_at_generation": round(ratio, 2),
|
||||
"entries": entries,
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser(
|
||||
description="编号门禁:docs/编号规范.md §8 的 8 项校验(默认 warn-only)")
|
||||
ap.add_argument("--strict", action="store_true",
|
||||
help="校验 1~6 的错误改为拦提交(默认 warn-only,不拦)")
|
||||
help="增量拦截:台账(scripts/id_known_backlog.json)之外的新错误级问题 → 拦提交")
|
||||
ap.add_argument("--write-backlog", action="store_true",
|
||||
help="把当前全部错误级问题写成债务台账(关闸前的初始化动作)")
|
||||
ap.add_argument("--prune-backlog", action="store_true",
|
||||
help="从台账里收掉已还清的条目(只减不增),并回写")
|
||||
ap.add_argument("--verbose", action="store_true", help="每条附带修法")
|
||||
ap.add_argument("--top", type=int, default=12, help="每类校验打印的条数(默认 12)")
|
||||
ap.add_argument("--only", default="", help="只跑指定校验,如 --only 1,3,5")
|
||||
@@ -635,6 +680,39 @@ def main():
|
||||
return rc
|
||||
ratio, errs = ck.report(args.top, parse_only(args.only))
|
||||
|
||||
groups = err_groups(ck)
|
||||
err_total = sum(groups.values())
|
||||
if args.only and (args.strict or args.write_backlog or args.prune_backlog):
|
||||
print("[ERR] --only 是局部排查,不能与 --strict / 台账写入同用(门禁结论必须全量)",
|
||||
file=sys.stderr)
|
||||
return 2
|
||||
if args.write_backlog:
|
||||
entries = [{"file": k[0], "code": k[1], "literal": k[2], "count": v}
|
||||
for k, v in sorted(groups.items())]
|
||||
BACKLOG_FILE.write_text(
|
||||
json.dumps(backlog_doc(entries, err_total, ratio), ensure_ascii=False, indent=2) + "\n",
|
||||
encoding="utf-8", newline="\n")
|
||||
print("[OK] 债务台账已写 %s:%d 条指纹,覆盖 %d 处错误级问题"
|
||||
% (BACKLOG_FILE.name, len(entries), err_total))
|
||||
return 0
|
||||
if args.prune_backlog:
|
||||
led = load_backlog()
|
||||
if led is None:
|
||||
print("[ERR] 还没有台账,无从清理", file=sys.stderr)
|
||||
return 2
|
||||
paid = [k for k in led if groups.get(k, 0) == 0]
|
||||
grew = [(k, led[k], groups.get(k, 0)) for k in led if groups.get(k, 0) > led[k]]
|
||||
kept = [{"file": k[0], "code": k[1], "literal": k[2], "count": groups[k]}
|
||||
for k in sorted(led) if groups.get(k, 0) > 0]
|
||||
BACKLOG_FILE.write_text(
|
||||
json.dumps(backlog_doc(kept, err_total, ratio), ensure_ascii=False, indent=2) + "\n",
|
||||
encoding="utf-8", newline="\n")
|
||||
print("[OK] 台账已还清 %d 条,剩 %d 条(只减不增)" % (len(paid), len(kept)))
|
||||
for k, was, now in grew[:10]:
|
||||
print("[WARN] 台账内条目**变多了**(这属于新增债务,strict 会拦):%s 校验%d %s %d→%d"
|
||||
% (k[0], k[1], k[2], was, now))
|
||||
return 0
|
||||
|
||||
if args.update_baseline:
|
||||
base = reg.get("decidable_ratio_baseline")
|
||||
if base is not None and ratio + RATIO_TOL < base:
|
||||
@@ -672,12 +750,26 @@ def main():
|
||||
print("\n[FAIL] 校验 8:可判定比例跌破基线 %.2f%% < %.2f%%(只许涨不许跌,容差 %.1fpp)"
|
||||
% (ratio, base, RATIO_TOL))
|
||||
return 1
|
||||
if errs:
|
||||
if err_total:
|
||||
if args.strict:
|
||||
print("\n[FAIL] 编号门禁:%d 处错误级问题(--strict 拦提交)" % errs)
|
||||
return 1
|
||||
print("\n[WARN] 编号 backlog:%d 处错误级问题,warn-only 不拦提交"
|
||||
"(§8 上线节奏:清账后加 --strict)" % errs)
|
||||
led = load_backlog()
|
||||
if led is None:
|
||||
print("\n[FAIL] --strict 但缺 scripts/id_known_backlog.json —— 拒绝退化成"
|
||||
"「一次性拦死全部存量」(那样只会逼人 --no-verify)。"
|
||||
"先跑 --write-backlog 生成台账(§8.4)", file=sys.stderr)
|
||||
return 2
|
||||
new = {k: c - led.get(k, 0) for k, c in groups.items() if c > led.get(k, 0)}
|
||||
if new:
|
||||
print("\n[FAIL] 编号门禁·增量拦截:%d 类**台账之外**的错误级问题(新引入的债,§8.4)"
|
||||
% len(new))
|
||||
for (rel, code, lit), n in sorted(new.items(), key=lambda kv: -kv[1])[:args.top]:
|
||||
print(" +%d [校验%d] %s %s" % (n, code, rel, lit))
|
||||
print(" → 改引用/补登记处;确属该欠的债要在台账写 reason(默认禁止顺手加)")
|
||||
return 1
|
||||
print("\n[OK] 增量拦截通过:无台账外新账(存量 %d 处按台账豁免,§8.4)" % err_total)
|
||||
else:
|
||||
print("\n[WARN] 编号 backlog:%d 处错误级问题,warn-only 不拦提交"
|
||||
"(关闸方式见 §8.4:--strict + 债务台账)" % err_total)
|
||||
else:
|
||||
print("\n[OK] 校验 1~6 无错误")
|
||||
return 0
|
||||
|
||||
Reference in New Issue
Block a user