Skip to content

ADR-013 · 评审提交文档的受控 KB ingestion · 只进知识层, 不碰判断产出

字段
状态accepted · 项目主理 2026-07-07 认可 + 零影响严格评审通过 (CTO 会签待补)
日期2026-07-07
决策者CTO + 项目主理
承接ADR-006 (脱敏分层) · ADR-011 (敏感分级) · ADR-012 (多场景评审)
相关config.yaml (sources / ignore) · scripts/reviewed_docs_filter.py (骨架) · 现有材料过滤层范式 (§6.5) · scripts/redact_check.py (脱敏闸) · CLAUDE.md §2.1 / §3.3 / §6 / §9

1. Context

1.1 · 起源

飞书评审机器人已进入日常运营, 每天都有业务文档被提交评审。这些文档承载真实企业知识 (业务规划 / 组织 / 经营数据), 项目主理希望把它们沉淀进企业知识库 (_wiki/), 丰富 entities / people / concepts

诉求本身合理: 每天流过的知识不应蒸发。但直接实现会撞上项目最核心的架构边界, 且必须满足第 0 红线: 对现有多场景评审 + 飞书机器人运营绝对零影响

1.2 · 现状: 两类产物都在 sage-wiki 的 ignore 里

产物落盘sage-wiki 态度原因
评审提交文档 (原始 PDF/docx)cases/.review-inbox/ (无清理 cron, 已持久)ignore + gitignore队列邻接, 未去重 / 未分级 / 未脱敏
评审报告 (评委产出)reports/ignore版本不可变 / 评委独立 / 归因轨迹

CLAUDE.md §2.1 明确: 这条 ignore 列表是 D7 边界判断的核心实现, 是设计原则不是性能优化

1.3 · 为什么不能"图方便"直接 ingest

  • 报告 (reports/): ingest 会破坏三样东西 —— ①versions/v{n}.md 快照不可变性 (归因锚点), ②reviews/<judge>.md 评委独立性 (评委间 delta 是数据), ③同一对象多次判断的差异轨迹。§3.3 已把"ingest report"列为明确禁止项。
  • 提交文档: 是第三方业务文档, 含真实机构名 + 经营数字 (§9 confidential/tian_only)。Wiki 知识层要求"先脱敏再进"(§6.1)。原始件直接进 = 未脱敏机密铺进知识库, 既污染又违纪; 且评审队列是临时、去重前、与 reports/ 邻接的目录, 不能作为 watch 源。

2. Decision

分两半, 边界清晰:

2.1 · 报告: 永不 ingest, 维持既有单向集成

reports/ 保持 ignore。报告与 Wiki 的连接已存在且正确 (§3.1 / §3.2): 报告"Background from Wiki"段单向链接到 entities; Wiki entities 自动挂"Related Judgements"回链 (只读 metadata)。不新增任何反向 ingest。 这条是不变承诺。

2.2 · 提交文档: 走一条受控 ingestion 管线 (纯只读取源, 零钩子)

新增一条受控管线, 范式照搬已验证的材料过滤层 (§6.5: 三通道分级 + 阈值 + 敏感度分级, 见 §2.4):

关键 (2026-07-07 修订, 见 §2.4): 内部 KB 保留原文; 敏感度分级在 VM 上做, 跨机的是原文 markdown (走私有分支跟踪, 非公开); 原始 PDF/docx 二进制不跨机。

┌─ VM (生产机) ──────────────────────────────────────────────────────┐
│ 飞书 bot → cases/.review-inbox/  (原始机密 PDF, 仅 VM 本地, gitignored)│
│    │  (SR-1 只读, SR-5 只取对应 job 已 done/ 的)                      │
│    ▼  scripts/reviewed_docs_filter.py                               │
│    │  (VM 上独立 cron/unit · SR-3 资源限额+开关 · SR-4 夜间错峰       │
│    │   · 不进消息事件循环 · 不改任何在跑代码)                          │
│    │   ├─ 去重 (content-hash)                                       │
│    │   ├─ 价值分级 (三通道打分, 是否值得沉淀)                          │
│    │   ├─ 敏感度分级 ★ redact 当探测器 (机构/财务 → 升 tian_only, 原样) │
│    │   └─ 阈值 ≥0.7 auto / 0.3–0.7 人工 / <0.3 不进 (纯 score)        │
│    ▼  raw/reviewed-docs/*.md  (原文 markdown + 分级 frontmatter)     │
└────┼───────────────────────────────────────────────────────────────┘
     │  传输 (§2.3, 已定 2026-07-07): 脱敏 .md 走 vm-data-backup 分支 (复用现有备份链)

┌─ 开发机 (sage-wiki 所在) ──────────────────────────────────────────┐
│ raw/reviewed-docs/  ← pull / rsync                                  │
│    ▼  sage-wiki compile (watch:false 错峰)                          │
│    ▼  _wiki/entities / people / concepts   ← 只进知识层              │
└────────────────────────────────────────────────────────────────────┘

要点:

  1. 只进知识层 (entities / people / concepts), 不进 reports/、不进 summaries/ 的判断部分。
  2. 纯只读取源, 零钩子: 过滤器从 cases/.review-inbox/ 只读取源, 且只取对应 job 已在队列 done/ 状态的文档; 不改 review_worker / feishu_events 一行 (见 §7 SR-2)。
  3. 进的是原文 (2026-07-07 修订, 见 §2.4): 内部 KB 保留原文, 靠私有存储 + 敏感度分级保护, 不删内容; redact 命中 → 升 tian_only, 不拦。
  4. 每个进 raw/reviewed-docs/ 的文件带 provenance: 只读链接回原评审 case (cases/<id>), 供审计追溯 —— 单向, 不反向 ingest report。
  5. 保留策略 (项目主理 2026-07-07 拍板): 原文副本永久保留, data owner = 项目主理
  6. 知识分类 (M2, category): 每份带 category frontmatter (business 企业业务知识 / tooling 关于 boss 系统自身 / 可扩展)。都入库, 不因类别丢弃 —— 元文档单独归一类, KB 内分类查询, 与业务知识分开。

2.3 · 数据流与跨机传输 (2026-07-07 严格评审补) ★

严格评审暴露一个必须显式解决的缺口: 提交文档只落在 VM (.review-inbox, gitignored + 备份 cron 排除 PDF), 而 sage-wiki 在开发机 —— 现状数据流不通。

定案的物理拓扑:

  • 过滤器 (分级) 跑在 VM —— 文档在哪处理就在哪, 原始 PDF/docx 二进制 永不离开 VM。因此 SR-3/SR-4 (独立进程 + 资源限额 + 夜间错峰) 是真约束 (下修正 §7.3)。
  • 跨机传输的是原文 markdown (raw/reviewed-docs/*.md, 见 §2.4: 内部 KB 保留原文)。传输方式已定 (项目主理 2026-07-07): 复用 vm-data-backup 分支机制 —— 把 raw/reviewed-docs/ 加进 vm_backup_cron.shDATA_DIRS, 原文 .md 随现有备份链推到私有 backup 分支; 开发机 pull 该分支 → sage-wiki 编译。复用已验证通道, 仅动一个 cron 的目录清单 (非评审运行时)。带外 rsync 作为备选未采纳。
  • sage-wiki 编译在开发机 → 富集落 _wiki/。回到 VM 的评审仍走 grep-fallback (不含新源, SR-6), 故富集惠及 sage-wiki 支撑的评审, 不改 VM 评审行为 (§3.4)。

⚠️ 原文 .md 在 vm-data-backup 私有备份分支上被跟踪 (私有 repo 内, 非 main, 非公开层), 与该分支已承载的 cases/reports 文本同级。绝不进 www/handbook / 外网 —— 内部原文的安全靠私有存储 + 敏感度分级, 不靠删内容 (§2.4)。

2.4 · 敏感度模型 (2026-07-07 二次修订 · 项目主理定) ★

修订起因: 一版把 redact_check入库拦截闸 (命中机构/财务 → 降级人工)。但项目主理指出: 企业 KB 要的正是内部高敏战略/财务/组织文档, 而 redact_check 的设计用途是公网出站闸 (CLAUDE.md §9.2 "输出到外部网络必经"), 用它拦内部入库, 恰好把最有价值的内容全拦了。

定案 (前提: 本 repo 为 private, 内部 KB _wiki/ 不对外发布):

环节错的做法 (旧)定案
redact 命中机构/财务拦截 → 降级人工不拦, 升敏感度分级 (confidential → tian_only), 内容原样进
verdict敏感就进不去纯 score (是否值得沉淀); 敏感战略文档该自动进
保护手段删/脱敏内容敏感度分级 (谁能看) + 私有 repo / 私有分支 存储
真正的脱敏闸错放在入库留在公网出口 (www/handbook 的 check_public_safe + redact_check, 已存在)

一句话: 内部 KB 存原文 (分级管控), 只有到公开层 (handbook) 才脱敏。redact_check 是出口闸不是入口闸


3. Consequences

3.1 · 优势

  • 每天流过的企业知识被结构化沉淀进 KB, entities/people/concepts 随运营自然丰富。
  • 复用成熟范式 (现有材料过滤层的三通道 + 阈值 + 敏感度分级), 不发明新机制。
  • 与判断产出边界零冲突 —— reports 一行不碰; 与运营零冲突 (§7)。

3.2 · 接受的 tradeoff

  • 管线成本: 多一条 filter + 一个 watched 目录 + 一份 rules 配置要维护。
  • 人工环节: 0.3–0.7 灰区文档进 .review/ 需人工裁决 (脱敏效果、是否该进)。这是刻意的 —— 机密文档不做无人值守全自动。
  • 永久保留的存储与合规: 提交文档从"评完即弃"变为"永久保留原文副本 (私有存储)", data owner = 项目主理, 需承担第三方业务文档长期留存的合规责任。
  • 富集只落 sage-wiki 侧 (见 §3.4): 为守绝对零影响, 不改 VM grep-fallback 的目录清单 → 富集只惠及 sage-wiki 支撑的评审, 不自动惠及 VM grep-fallback 路径。

3.3 · 不变的承诺

  • reports/ / cases/ 永远在 ignore 内; 报告永不 ingest。
  • Wiki→reports 的唯一合法触碰仍只是 §3.2 的 metadata 回链。
  • 任何出站/入库仍过 redact_check fail-close。
  • 不改任何在跑的服务代码 (§7 SR-2)。

3.4 · Invariant impact ★

受影响的既有 invariant变化新增 invariant
"sage-wiki watch 源是固定 4+N 类 raw"新增 1 类 watched 源 raw/reviewed-docs/ (watch:false)该源内每个文件带敏感度分级 frontmatter (confidential/tian_only); 内容为原文 (§2.4)
"评审提交文档评完即弃 (.review-inbox ephemeral)"失效 — 现永久保留原文副本保留的是原文 + 分级 + provenance link; owner = 项目主理; 仅存私有 repo/私有分支
"§2.1 ignore = reports/cases 不进 Wiki"不变明确: reviewed-docs ≠ reports; 管线禁止reports/cases/*/ 直接取判断产出
"Wiki 知识层内容已脱敏 (§6.1 指公开层)"重定位 (§2.4)内部 KB (私有) 存原文; 脱敏只在公网出口 (www/handbook 双闸)。redact 命中 → 升 tian_only, 不删
★ 新红线: KB 原文私有边界新增raw/reviewed-docs/ 与其派生 _wiki/ 实体, 只存私有 repo / 私有分支, 禁进 www/handbook/ 或外网; 边界由 check_public_safe + redact_check (只扫 www/handbook) 把守
"评审 Phase 1 context 来源" (VM 走 RAW_DIRS_FOR_WIKI_FALLBACK grep)不变禁止raw/reviewed-docs/ 加进 RAW_DIRS_FOR_WIKI_FALLBACK —— 保 VM 评审上下文零变化 (见 §7)

本 ADR 有两条核心红线: ①管线物理隔离 review 产出与提交文档 (filter 只读"提交文档持久副本", 绝不扫 reports/ / reviews/ / case.json, 白/黑名单钉死); ②内部 KB 原文只在私有边界内 (§2.4 新红线), 脱敏只发生在公网出口。


4. Alternatives Considered

方案结论原因
A. 把 watcher 直接指到 cases/.review-inbox/❌ 拒未脱敏 / 未去重 / 与 reports 邻接, 违 §2.1 D7 边界
B. 连报告一起 ingest❌ 拒毁版本不可变性 / 评委独立性 / 归因轨迹 (§3.3 明令禁止)
C. review-worker 收尾钩子推送文档❌ 拒碰生产热路径, 违第 0 红线; 且无必要 (.review-inbox 已持久, 独立 cron 只读即可)
D. 人工逐篇挑进 raw/clippings⚠️ 部分不 scalable; 但可作 M2 dry-run 阶段的人工兜底
E. 受控 filter 管线 · 独立 cron 只读取源 (本 ADR)✅ 采纳复用材料过滤层范式, 零钩子 + 敏感度分级 + 灰区人工, 边界与运营皆不破

5. Migration Plan

每步之前, 现有多场景评审 + 飞书机器人运营零影响 (§7 SR 保证)。

里程碑内容门槛
M0本 ADR 双签 (CTO 会签) + §7 前置项确认 (sage-wiki 部署位置)通过才进 M1
M1reviewed_docs_filter.py 实现 + config/reviewed_docs_filter_rules.yaml + 单测 (纯离线, mock LLM); 只读 .review-inbox (done/ 门控), 只写自留地全绿 + SR 自检
M2在历史提交文档持久副本上 dry-run, 人工抽检脱敏效果与分级准确率抽检达标
M3raw/reviewed-docs/ 加进 vm_backup_cron.sh DATA_DIRS (传输); 开发机 config.yaml 加 source (watch:false) + 首批灰度 (单场景)观察一周无污染
M4独立 cron/unit 定时跑 (夜间错峰) + 资源限额 + 扩展全场景

原 M4「review-worker 收尾钩子」已删除 (评审严格评审结论): .review-inbox 已持久且被只读共享, 独立 cron 扫 done/ 即可取源, 无需任何生产代码钩子

骨架 (scripts/reviewed_docs_filter.py) 随本 ADR 提交但未启用 —— config.yaml 的 ignore/sources 不动, 骨架不被任何运行路径 import。M0 前它是惰性设计稿。


6. 关键反共识立场

"评审文档应原样全量进 KB 才不丢信息" —— 这是错的。

KB 的价值不在原始 PDF 的堆积, 而在脱敏 + 结构化后的 entities / people / concepts。原样全量堆进去反而: 污染知识层 (未脱敏机密、重复文档、评审噪声)、埋合规雷 (第三方经营机密持久化且被索引)、稀释信噪比。丰富 KB ≠ 灌满 KB。


7. 零影响实施约束 (SR · 第 0 红线) ★

严格评审 (2026-07-07) 结论: 绝对零影响可达成, 且是架构级保证而非纪律级, 基于三条既有护栏 + 五条硬约束。

7.1 · 三条既有架构护栏 (代码事实, 非承诺)

  1. 评审运行时不依赖 sage-wiki: run_pipeline_local 明写"不依赖 sage-wiki", 有 wiki_query_fallback (grep 退化)。改 sage-wiki 侧配置无法让评审崩溃, 最坏是它自己降级。
  2. 提交文档已持久、只读共享: cases/.review-inbox/ 无清理 cron, 已被 worker + dashboard 只读共享。再加一个只读消费者零冲突。
  3. grep-fallback 扫固定目录清单: RAW_DIRS_FOR_WIKI_FALLBACK 硬编码 3 目录, 不含 reviewed-docs → 加新源后 VM 评审上下文一个字节不变

7.2 · 五条硬约束 (实施必须满足)

SR约束
SR-1 只读上游 / 只写自留地.review-inbox / 队列 / cases/ 一律只读; 只写 raw/reviewed-docs/ (原文 markdown + 分级) + 去重台账。经 vm-data-backup 私有分支跟踪跨机 (§2.3), 不进 www/handbook / 外网
SR-2 零钩子不改 review_worker.py / feishu_events.py / feishu_ws_client.py / boss_server.py 一行; 取源靠独立 cron 扫 done/
SR-3 独立进程 + 限额 + 开关独立 cron/unit, CPUQuota+MemoryMax, REVIEWED_DOCS_INGEST_ENABLED 默认关, systemctl stop 秒级回滚
SR-4 错峰 / 非实时watch:false (定时编译); 过滤器夜间跑; channel-3 LLM 限速, 不与运营时段/网关争限流
SR-5 只取 done只处理 job 已 done/ 的文档, 避免读到下载中/评审中的半成品或失败件
SR-6 不动 fallback 清单禁止raw/reviewed-docs/ 加进 RAW_DIRS_FOR_WIKI_FALLBACK (保 VM 评审上下文零变化); 富集只经 sage-wiki 落 _wiki/

7.3 · 前置确认项 (进 M1 前)

  • sage-wiki compile 部署位置 — ✅ 已确认 (2026-07-07): 生产 VM 上无 sage-wiki 进程 (systemctl/pgrep 核实), 评审走 grep-fallback → sage-wiki 编译在开发机, 加源不影响 VM。
  • 修正 (2026-07-07 · 数据流评审): 但过滤器 (分级) 必须跑在 VM (文档只在 VM, PDF/docx 二进制不应跨机)。故 SR-3/SR-4 是 VM 上的真约束, 不是"自律" —— 过滤器作为 VM 上独立 cron, 靠资源限额 + 夜间错峰 + 默认关开关与评审运营隔离。零影响仍成立 (只读 + 零钩子 + 独立进程 + 限额), 但靠的是 SR-1~5 的隔离, 而非"物理不同机"。跨机的是原文 markdown (私有分支, §2.3/§2.4)。
  • 传输方式 — ✅ 已定 (项目主理 2026-07-07): 复用 vm-data-backup 分支 (§2.3)。
  • CTO 会签: 本 ADR 触 §2.1 D7 边界, 项目主理已认可, 待 CTO 会签补齐 (§10.2)。

判断力工程化 · Judgement, Engineered · 主站 · GitHub