09_项目治理 · 验收判据与质量门禁
目的:把「v2.0 文档标准」从口号变成可机器判定的判据,让长任务的推进有唯一事实来源。 建立:2026-09-21 | 脚本:
09_项目治理/gates/check_kb.py、gates/selftest_gate.py
一、一条判据必须凑齐三要素
判据写”XX 通过”而”通过”没定义,就等于没有判据 —— 只能靠印象,而且文档里的复选框永远不会被勾上。
| 要素 | 本项目怎么落 |
|---|---|
| 判定方式 | 写成 check_kb.py 里的一条 check():测哪些对象(从目录结构读,不手抄)、什么算过、失败时打印具体文件名 |
| 责任人 | 机器(门禁脚本)/ 人(本文件第二节的「人工项」,逐项列明由谁走查) |
| 证据落点 | 门禁输出 + 03_长任务执行日志.md 的当次记录(含分数前后对比) |
二、门禁清单(全部可自动化,当前 8 条)
| ID | 判据 | 判定对象 | 通过条件 | 基线 2026-09-21 |
|---|---|---|---|---|
| G1 | 静态文档含「引用源与扩展阅读」章节 | 00/01/02/03/04/05/07/08 下全部 md(排除 README 与「导读」) | 100% | 40/43 ❌ |
| G2 | 静态文档抬头前 20 行标注「数据核实日期」 | 同上 | 100% | 10/43 ❌ |
| G3a | 资讯 frontmatter 六个必填字段 | 06_行业资讯/<子目录>/*.md | title/date/type/period/summary/tags 非空 | ✅ |
| G3b | 资讯 type 与所在子目录一致 | 同上(目录→type 映射) | 100% 一致 | ✅ |
| G3c | 资讯 date 为 YYYY-MM-DD | 同上 | 100% | ✅ |
| G4 | 品牌档案 tags 含「国际品牌」或「国产品牌」 | 06_行业资讯/品牌档案/* | 100% | 17/17 ✅ |
| G5 | 中文名资讯文件带 ASCII slug | 资讯侧文件名非 ASCII 的 | 100% | 17/17 ✅ |
| G6 | 站点输出 slug 唯一(无覆盖) | 全库 md,按 import-docs.mjs 规则模拟计算 | 无重复 | ✅ |
为什么 G4/G5/G6 值得单独设:它们对应已经真实发生过的三类事故 —— 品牌分类误判(G4,2026-09-20 修)、中文名文件同名覆盖(G5)、以及同模块同序号文档 slug 互相覆盖(G6)。这三类缺陷的共同点是不报错:站点照常构建成功,只是内容悄悄错了。
三、断言强度自查(防「装饰品门禁」)
弱断言是本项目最容易自欺的一步。已做的防范:
| 反面写法 | 本门禁的做法 |
|---|---|
| 只报一个布尔值,红了自己去找 | 每条 FAIL 打印具体文件名(G2 一次列出全部 33 份缺口) |
| 断言”章节存在”而不查内容 | G1 查具体章节标题字符串;G3 逐字段判非空 |
| 判据清单手抄(加模块就静默失准) | STATIC_MODULES 从本文件同步维护;资讯目录→type 映射集中在一处 |
| 只对新文件生效 | G6 模拟 import-docs 规则扫描全库,能抓到存量冲突 |
| 新增判据只验证”能变绿” | 必须先跑 selftest_gate.py(见下) |
自检夹具:先证明它会红
gates/selftest_gate.py 构造一棵带已知缺陷的临时知识库(8 类缺陷各一),断言:
- 8 条判据全部变红(少红 = 漏检,说明该断言无效);
- FAIL 条数恰好等于 8(多红 = 误报);
- 合规样例未被误报。
export PATH="/usr/bin:/bin:/usr/local/bin:$PATH"; export PYTHONIOENCODING=utf-8
PY="C:/Users/Gary/.workbuddy/binaries/python/versions/3.13.12/python.exe"
"$PY" "C:/Users/Gary/WorkBuddy/2026-09-09-22-57-42/outputs/液压行业知识库/09_项目治理/gates/selftest_gate.py"
2026-09-21 自检结果:8/8 判据按预期变红,合规样例无误报 → 门禁可信。
纪律:任何新增/修改判据后,必须重跑自检。只会变绿的断言是装饰品 —— 它给了你”已经查过”的错觉。
四、明确不做自动化的部分(人工项)
以下项不做自动化,也不伪装成”门禁通过”。缺记录时在日志里记 SKIP,不得记 PASS。
| 人工项 | 为什么不能自动化 | 走查人 | 记录落点 |
|---|---|---|---|
| 内容事实正确性(数字/结论是否与一手来源一致) | 需要回一手来源逐条核对,涉及判断 | 知识库维护人 | 执行日志 |
| 销售可用性(话术是否真能用、参数是否够选型) | 需要真实销售场景反馈 | 销售负责人 | 执行日志 |
| 站点可读性(排版/移动端/检索体验) | 需要真人浏览 | 维护人 | 执行日志 |
| 案例真实性(客户是否同意公开、数字是否脱敏) | 涉及商务与法务判断 | 业务负责人 | 执行日志 |
为什么”不自动化”比”假装自动化”重要:伪造的绿灯比没有门禁更危险 —— 它把”没测”伪装成”测过且合格”,问题会在一次外部审计里集体暴露。
五、新增一条判据的标准动作
- 确认它能被程序判定(判不了的进第四节人工项);
- 在
check_kb.py加check(),必须打印失配对象名; - 在
selftest_gate.py的FIXTURES加一份对应缺陷样本,注册进EXPECT_FAIL; - 跑自检 → 必须 8→9 全红;
- 在本文件第二节登记(ID / 判定对象 / 通过条件 / 基线);
- 跑真实库,把新基线写进看板第八节进度快照。
禁止:为了让门禁变绿而放宽断言(“期望值调松”= 把门禁推向”永远为真”);正确做法是把”正确被排除/正确缺失”本身变成新断言。
六、门禁与站点构建的关系
| 环节 | 命令 | 失败含义 |
|---|---|---|
| 门禁 | check_kb.py | 文档标准未达标 —— 不阻塞构建,但必须在日志里记录分数 |
| 导入 | node scripts/import-docs.mjs | frontmatter/slug 规则问题 |
| 构建 | npm run build | Astro/schema 问题(历史上 techs is not defined、schema enum 未扩展都出在这里) |
| 部署 | npx --yes wrangler@4 pages deploy | 凭证/网络问题(历史上 OAuth 过期、~/.npm/_npx 缓存损坏) |
四步失败定位顺序固定:OAuth 续期 → import-docs → build → deploy。任一步失败保留已生成文件,在日志写明失败环节与报错。
构建失败兜底:rm -rf ~/hydrolearning/dist && cp -a <stage>/. ~/hydrolearning/ 后重跑(曾踩坑:dist 缓存导致旧错误复现)。
七、反面对照清单(这些做法都被证明有害)
- ❌ 门禁写在文档里不落脚本 → 等于没有门禁
- ❌ 断言只查”非空/存在/不报错” → 最坏的取值也能过
- ❌ 用”总数”做断言 → 共享状态下必然假失败
- ❌ 发现红了就把期望值调松 → 把门禁改成”永远为真”
- ❌ 新增判据不跑自检 → 装饰品
- ❌ 一次改几十份文档却一次都不跑门禁 → 无法定位是哪份改坏的
- ❌ 把不可判定的项标成”门禁通过” → 把”没测”伪装成”测过”