# -*- coding: utf-8 -*- """DoD 验收清单文档(docs/DoD验收清单.md)完整性与指标一致性检查。 检查项: 1. 必备章节齐全(目的用法 / 内核验收 / 首模板验收 / NFR 核对 / 验收流程节点 / 风险登记 / 一致性说明); 2. PRD §10 验收标准中的关键量化指标全部出现(P99≤1.8s / 丢失率≤0.02% / 可用性≥99.8% / 路由准确率≥96.5% / 首屏≤2s / 质量预测准确率≥90% / 预警提前≥30分钟 / 误报率 / 本地首token≤1.5s / 交接班报告≤2分钟); 3. 状态口径四态(未开始 / 待验证 / 通过 / 阻塞)齐全; 4. 验收流程六节点(自测 / 内部评审 / 客户UAT / 上线 / 质保观察 / 闭环)齐全; 5. 引用的核心验收证据文件路径在仓库内真实存在。 用法:python _check_dod.py """ import os import re import sys HERE = os.path.dirname(os.path.abspath(__file__)) REPO_ROOT = os.path.dirname(HERE) DOC_PATH = os.path.join(HERE, "DoD验收清单.md") REQUIRED_SECTIONS = [ "## 1. 目的与用法", "## 2. iAOP-Core 内核验收", "## 3. iAOP-Template-Ti 一期首模板验收", "## 4. NFR 量化底线核对表", "## 5. 验收流程与节点", "## 6. 阻塞与风险登记", "## 7. 一致性说明", ] # PRD §9/§10 关键量化指标(去空格后匹配,兼容全角/半角差异) KEY_METRICS = [ "1.8s", # 采集 P99 "0.02%", # 丢失率 "99.8%", # 可用性 "96.5%", # 路由准确率 / DLP(路由口径) "2s", # 首屏 "90%", # 质量预测准确率 "30 分钟", # 预警提前量 "1.5s", # 本地首 token "2 分钟", # 交接班报告生成 "100%", # DLP 拦截率 ] STATUS_TOKENS = ["未开始", "待验证", "通过", "阻塞"] # 状态表格中的符号(核对口径可勾选) STATUS_SYMBOLS = ["☐", "◐", "✅", "⛔"] FLOW_NODES = ["自测", "内部评审", "客户 UAT", "生产上线", "质保观察", "闭环"] # 关键证据文件须真实存在(仓库内) EVIDENCE_PATHS = [ os.path.join(REPO_ROOT, "core", "data-bus", "scripts", "bench_write.py"), os.path.join(REPO_ROOT, "core", "edge-gateway", "scripts", "verify_resilience.py"), os.path.join(REPO_ROOT, "docs", "采集网只读隔离与网闸配置.md"), os.path.join(REPO_ROOT, "core", "edge-gateway", "config", "point_dict.example.csv"), os.path.join(REPO_ROOT, "core", "llm-gateway", "router.py"), os.path.join(REPO_ROOT, "core", "llm-gateway", "dlp.py"), os.path.join(REPO_ROOT, "deploy", "k8s", "helm", "iaop"), os.path.join(REPO_ROOT, "templates", "resin", "version.yaml"), os.path.join(REPO_ROOT, "templates", "ti-cl4", "point-dict", "point_dict.default.csv"), os.path.join(REPO_ROOT, "docs", "LIMS质检接口字段清单.md"), os.path.join(REPO_ROOT, "docs", "产品设计文档_iAOP.md"), ] def _norm(s: str) -> str: """归一化用于指标比对:移除所有空白。""" return re.sub(r"\s+", "", s) def main() -> int: failures = [] if not os.path.isfile(DOC_PATH): print("FAIL") print(" -", "DoD 验收清单文档缺失:DoD验收清单.md") return 1 text = open(DOC_PATH, "r", encoding="utf-8").read() # 1) 必备章节 for sec in REQUIRED_SECTIONS: if sec not in text: failures.append(f"缺少必备章节:{sec}") # 2) 关键量化指标(归一化后比对) norm_text = _norm(text) for metric in KEY_METRICS: if _norm(metric) not in norm_text: failures.append(f"缺少关键量化指标:{metric}") # 3) 状态口径四态齐全 for token in STATUS_TOKENS: if token not in text: failures.append(f"缺少状态口径说明:{token}") symbol_present = [sym for sym in STATUS_SYMBOLS if sym in text] if len(symbol_present) < 3: failures.append(f"状态符号至少覆盖 3 种,实际出现:{symbol_present}") # 4) 验收流程六节点 for node in FLOW_NODES: if node not in text: failures.append(f"缺少验收流程节点:{node}") # 5) 引用证据文件真实存在 for p in EVIDENCE_PATHS: if not os.path.exists(p): failures.append(f"引用证据路径不存在:{os.path.relpath(p, REPO_ROOT)}") if failures: print("FAIL") for f in failures: print(" -", f) return 1 print("OK: DoD 清单章节/量化指标/状态口径/流程节点/证据路径校验通过") return 0 if __name__ == "__main__": sys.exit(main())