Files
group_fqcd_jr/客服agent/_build/_consistency.py
T
张胜宇 bc61d5c579 docs: 入库权威文档目录(客服agent/ 24 份 + 开发文档/ 50 份,替换旧命名的过期副本)
## 为什么做这一步

权威文档 74 份此前**只在本机**,评审者 clone 分支后看不到任何设计文档;而仓库里那两份同名目录
是 **2026-09-16 之前的过期副本,连文件名都是旧的**(无体系编号)。本次按「**权威覆盖过期**」入库。

## 入库内容

| 目录 | 文件数 | 体积 | 说明 |
|---|---|---|---|
| `客服agent/` | 24 | 0.77 MB | `D2.1`~`D2.6` 对外交付四件套 + 演示脚本/答辩报告 + `_build` 构建工具 |
| `开发文档/` | 50 | 2.16 MB | `D1.x` 索引与决策、`D3.x` 方案、`D4.x` 清除与重构留痕、`D5.x` 业务流程、`D6.x` 业务事实基座、`D7.x` 交付物、`D8.x` 规范 |

**旧的过期副本整体移除**(`客服Agent执行Todolist.md` → `D2.1-客服Agent执行Todolist.md` 之类
的改名 + 新增 `D2.5`/`D2.6`),入库后目录内容与权威副本**逐文件一致(零差异,已复核)**。

## 入库前的安全扫描(必须留痕)

- 扫描规则:`sk-` 类密钥 / `Bearer` 长串 / `password=`、`api_key=` 赋值 / 会话中出现过的两把明文 key 片段。
- 结论:**真实密钥只出现在 `.env`**(已被 `.gitignore` 命中,未入库);`.env.example` 与
  `config/risk.env.example` 只有**空占位**。
- 文档内唯一命中是 `D3.1` 里一处**截断的示例 JWT**(`Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...`),
  末尾带省略号,是接口文档的示意值,**不是可用凭据**。
2026-09-20 15:03:15 +08:00

100 lines
3.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""四份交付文档 · 跨文档一致性自检。仅读取,不改文件。"""
import re
from pathlib import Path
D = Path(r"D:\桌面\金融\客服agent")
OUT = Path(r"D:\桌面\金融\_consistency.txt")
FILES = {
"需求": D / "D2.2-客服Agent需求文档.html",
"计划": D / "D2.3-客服Agent开发计划.html",
"Todo": D / "D2.1-客服Agent执行Todolist.md",
"知识库": D / "D2.4-客服Agent知识库设计方案.html",
}
texts = {}
lines = []
lines.append("== 一、文件基本情况 ==")
for name, p in FILES.items():
if p.exists():
t = p.read_text(encoding="utf-8")
texts[name] = t
lines.append(f" {name:4s} {p.name} {t.count(chr(10)) + 1} 行 / {len(t)} 字符")
else:
lines.append(f" [MISSING] {p}")
lines.append("")
lines.append("== 二、关键事实在各文档中的出现次数(0 = 遗漏)==")
FACTS = [
("功能需求 48 条", r"48 条"),
("FR-CS-048", r"FR-CS-048"),
("非功能需求 21 条", r"21 条"),
("NFR-CS-021", r"NFR-CS-021"),
("51 项", r"51 项"),
("7 批次 / 7 个批次", r"7 个?批次"),
("12 步", r"12 步"),
("6 文件 / 六文件", r"(六文件|6 个?文件)"),
("组 2 四文件", r"组 2|组2"),
("三集合", r"三集合"),
("阈值 0.75", r"0\.75"),
("阈值 0.70", r"0\.70"),
("阈值 0.65", r"0\.65"),
("over-fetch", r"over-fetch"),
("不变量", r"不变量"),
("actor.py", r"actor\.py"),
("knowledge_tier.py", r"knowledge_tier\.py"),
("三条红线", r"三条红线"),
("subject_type", r"subject_type"),
("零 DDL", r"零 ?DDL"),
]
hdr = " " + "事实".ljust(26) + "".join(n.center(8) for n in FILES)
lines.append(hdr)
for label, pat in FACTS:
row = " " + label.ljust(26)
for name in FILES:
t = texts.get(name, "")
row += str(len(re.findall(pat, t))).center(8)
lines.append(row)
lines.append("")
lines.append("== 三、投顾残留检查(应全部出现在「已清除/作废」语境)==")
for name, t in texts.items():
if name == "知识库":
continue
hits = [m.start() for m in re.finditer("投顾", t)]
bad = []
for h in hits:
ctx = t[max(0, h - 60): h + 60].replace("\n", " ")
if not re.search(r"已(整体)?清除|作废|不再|已删除|清除后|已移除|已下架|原|投顾模块已", ctx):
bad.append(ctx)
lines.append(f" {name}: 命中 {len(hits)} 处,其中疑似「仍在依赖」{len(bad)} 处")
for b in bad[:5]:
lines.append(f" ⚠ …{b}…")
lines.append("")
lines.append("== 四、HTML 锚点自检(TOC href vs 正文 id)==")
for name in ("需求", "计划", "知识库"):
t = texts.get(name, "")
hrefs = set(re.findall(r'class="toc-item" href="#([^"]+)"', t))
ids = set(re.findall(r'<h[1-4] id="([^"]+)"', t))
missing = sorted(hrefs - ids)
lines.append(f" {name}: TOC {len(hrefs)} 条 / 正文 id {len(ids)} 个 / 失效 {len(missing)}")
for m in missing:
lines.append(f" ⚠ 失效锚点: {m}")
lines.append("")
lines.append("== 五、四文档交叉引用检查 ==")
EXPECT = {
"需求": ["客服Agent开发计划", "客服Agent执行Todolist", "客服Agent知识库设计方案"],
"计划": ["客服Agent需求文档", "客服Agent执行Todolist", "客服Agent知识库设计方案"],
"知识库": ["客服Agent需求文档"],
}
for name, refs in EXPECT.items():
t = texts.get(name, "")
for r in refs:
lines.append(f" {name} → {r}: {'✅' if r in t else '❌ 缺'}")
OUT.write_text("\n".join(lines), encoding="utf-8")