Files
iAOP/docs/_check_dod.py
bot_dev1 76f921f994 feat(#90): DoD 验收清单逐条核对(内核/首模板/NFR/流程节点+程序化核对脚本)
- docs/DoD验收清单.md:把 PRD §9 NFR + §10 DoD + §7.7 交付物清单拆成勾选式清单
  · iAOP-Core 6 模块 28 项(C-01~C-28)+ 首模板 8 项(T-01~T-08)
  · NFR 量化底线核对表(P99≤1.8s/丢失率≤0.02%/可用性≥99.8%/路由≥96.5%/首屏≤2s 等)
  · 验收流程六节点(自测→内部评审→客户UAT→上线→质保观察→闭环)
  · 风险登记(标注数据不足/UAT 配合度/机房环境)与四态状态口径
- docs/_check_dod.py:程序化核对必备章节/量化指标/状态口径/流程节点/证据路径
- 验证:6 个 docs 校验脚本全部通过(含新增 _check_dod.py),无回归
2026-08-05 02:34:00 +08:00

124 lines
4.6 KiB
Python

# -*- 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())