Files
knowledge-governance/docs/P5_REVIEW_AND_SEAL_ACCEPTANCE.md
T
zheromiku dcdc8d1ddd feat: 知识治理平台(含已验证发布/回滚契约)
全栈知识治理平台首次入库(P1-P10 + 发布链路模拟验证闭环):

- 治理核心:源目录/变更集/人工审核/发布批次/发布执行(fail-closed 闸口)
- 测试通道:WeKnora 测试 KB 上传/轮询/验收;poll 完成时写入
  parser_generation/index_generation,修复 manual/seed 路径发布闸口永久拦截
- 发布适配器 v071(本地 source=测试角色 / 云端 target=生产角色 模拟验证通过):
  * ES 导出/导入 mapping 自适应(.keyword 子字段、可选 tenant_id)
  * OSS locator 支持嵌套 scheme;chunks.seq_id 由目标序列分配
  * bundle 归档同身份重试原子替换;verifier 按 bundle chunk_type 计数
  * 回滚 job payload 支持 prior_execution_id(strict 解码)
- 三通道发布+回滚演练实测:publish 4/4 verified,检索命中,
  rollback 4/4 rolled_back,目标端 PG is_enabled=false、ES is_enabled=false
- 前端 A·Data-console 风格全站统一,120 用例通过
- 门禁:go vet / go test 全包通过,gofmt 干净
2026-09-30 10:54:06 +08:00

8.4 KiB
Raw Blame History

P5 知识工程师审核、封批与发布前门禁验收

范围

P5 在测试发布完成后增加人工控制平面:

当前 Test Publication + 最新 Acceptance run
→ 固定门禁计算
→ 知识工程师批准或驳回
→ 已批准项目创建 draft 批次
→ 封批时再次验证 Publication / Review / Acceptance
→ sealed(尚未发布)

P5 不实现生产复制,不创建 release.* Job,不启用 Release Worker。

数据模型

Migration 6 新增:

publication_reviews
release_batches
release_batch_items

设计约束:

  • publication_reviews 是追加式决定,不覆盖历史决定;
  • 决定只允许 approved / rejected;
  • 可见性只允许 internal / external;
  • 使用固定 decision_code,不保存自由文本或源正文;
  • 批准绑定当时最新 acceptance_run_id 和 Publication updated_at;
  • 完全相同的决定通过唯一键幂等;
  • release_batch_items 锁定 Publication、Review、Source Item Version、Acceptance run、可见性和 Publication 时间戳;
  • 同一 Publication 只能进入一个批次;
  • 批次状态只允许 draft / sealed / cancelled;
  • 策略版本固定为 release-gate-v1;
  • Migration down 顺序为 item → batch → review;
  • 没有历史自动回填,没有把 530 条 PP legacy 项标为“已人工审核”。

Migration round-trip 在 disposable PostgreSQL 验证:

up 6 → down 5 → up 6

回滚 6 时,P4 的 source_scans / source_scan_changes 保持存在。

审核候选门禁

审核队列只纳入至少有一个 Acceptance run 的 Publication。当前持久数据:

Test Publications                  535
PP legacy(无逐条 Acceptance)    530
manual 合成验收项                    5
审核候选                              5

固定 gate code:

ready
publication_not_ready
source_not_current
acceptance_failed
acceptance_incomplete

批准要求:

ingest_state       = uploaded
processing_state   = completed
retrieval_state    = unpublished
当前 Source Item revision = Publication 使用的 Source Item Version revision
source_change      不得为 unavailable / deleted
knowledge_exists   = passed
chunks_present     = passed
retrieval_hit      = passed 或 manual_required

retrieval_hit=manual_required 没有被自动改成 passed;知识工程师点击批准时明确承担人工判断。

驳回固定 code:

needs_correction
classification_changed
acceptance_rejected

批准固定 code:

approved_for_release

封批门禁

创建 draft 时必须:

  • 请求至少 1 项、最多 100 项;
  • Publication ID 不重复;
  • 每项均有当前有效的最新批准;
  • 批准仍绑定当前 Acceptance run 和 Publication updated_at;
  • 每项仍满足完整 release gate;
  • 任一项目不合格则整条 SQL 不创建批次或部分 item;
  • 唯一冲突导致整条语句回滚。

封批时再次验证:

  • batch 当前为 draft;
  • batch 至少有 1 项;
  • 每个锁定的 Review、Acceptance run、Publication timestamp、可见性仍匹配;
  • 当前 Publication 和 Source revision 仍满足门禁;
  • 所有 item 都有效后才原子变为 sealed;
  • 已 sealed 请求幂等返回现有 sealed 记录;
  • 不创建 Job。

P6 在真正发布前仍需再次验证封批快照;P5 的 sealed 只表示“人工封批完成”,不表示生产已发布。

API

GET  /api/v1/review-candidates
POST /api/v1/review-candidates/{publication_id}/decision

GET  /api/v1/release-batches
POST /api/v1/release-batches
GET  /api/v1/release-batches/{batch_id}
POST /api/v1/release-batches/{batch_id}/seal

请求体使用 strict JSON decoder:

  • 最大 64 KiB;
  • 未知字段拒绝;
  • 尾随 JSON 拒绝;
  • 非法输入为 400;
  • 不满足审核/创建条件为 422;
  • 封批快照失效为 409;
  • 不回显 Store 原始错误。

安全响应不包含:

knowledge_id
test_kb_id
acceptance_run_id
publication_updated_at
stable_external_id
canonical_uri_hash
local_spool_ref
raw_record_summary
base_url
secret_ref
API Key / Token

审核 API 的 reviewer_ref 当前是本地治理工作台的调用方提供标识,不等同于企业 SSO 强身份。P6 生产启用前仍需将控制面置于经认证/授权的管理员入口;当前 Release Worker关闭,因此该限制不会形成生产发布通路。

Web 工作台

“发布管理”由占位页升级为真实 P5 工作台:

  • 左侧导航 + 顶部可关闭标签保持不变;
  • 展示审核候选、门禁就绪、待审核和已选数量;
  • 每条显示对象、分块、检索验收;
  • manual_required 显示为“需人工确认”;
  • 人工选择 internal / external;
  • 工程师标识为空时批准、驳回和封批按钮禁用;
  • 只有已批准且当前 gate ready 的项目可勾选入批;
  • 创建 draft 后仍需单独点击“封批”;
  • 页面固定显示“生产门禁保持关闭”“Release Worker保持关闭”“尚未发布”;
  • 不在浏览器中录入或显示 API Key、数据库密码或 WeKnora凭据。

测试与真实证据

自动化测试

Go全仓库test              passed
Go vet                    passed
Go cmd build              passed
Web tests                 35/35 passed
TypeScript typecheck      passed
Vite production build     passed
Compose config            passed
Migration 6 contract      passed
Migration 6 up/down/up    passed(disposable PostgreSQL)

Disposable PostgreSQL Store E2E

验证:

ready → approved → draft → sealed
无批准 → create batch 拒绝
批准后 Publication updated_at 改变 → seal 拒绝
sealed batch list/detail → 读回 1 item
P5 操作新增 Jobs → 0

Disposable API HTTP E2E

使用独立数据库、临时 API 端口和无敏感合成记录:

pending → POST approved
approved → POST draft
 draft  → POST sealed
GET detail items=1
safe projection leaks=0
Jobs=0

该测试完成后:

临时 API                stopped
临时数据库              deleted
临时 pgpass             deleted
持久库人工决定           0
持久库批次               0
持久库批次项目           0

持久本地环境

应用 Migration 6 前备份:

tmp/backups/governance-pre-migration6-20260906T030213+0800.dump
bytes=252653
mode=0600
pg_restore catalog=valid

应用后:

schema_migrations        1,2,3,4,5,6
publication_reviews      0
release_batches          0
release_batch_items      0
source_items             618
content_objects          535
source_item_versions     618
test_publications        535
acceptance_results       15

真实审核队列:

candidates               5
pending                  5
gate ready               5
retrieval manual_required 5

未替知识工程师批准任何持久候选。

Firefox

脚本:

tmp/p5_review_gate_browser_accept.py

截图:

tmp/P5_REVIEW_GATE_TOP_FIREFOX.png
tmp/P5_REVIEW_GATE_FIREFOX.png

验收:

review rows                       5
ready / pending                   5 / 5
actor required                    true
批准/驳回填写actor后可用          true
mutation clicks                   0
batch rows                        0
创建批次按钮                      disabled
safe projection leaks             0
root horizontal overflow          false
table horizontal overflow         false

截图视觉检查未发现横向裁切、遮挡、乱码或阻断问题。

已发现并修复的问题

  1. PostgreSQL 审核参数同时参与比较与 VARCHAR 插入时类型推断冲突;为参数加显式 cast。
  2. data-modifying CTE 同语句从基表读取新 batch 看不到新 snapshot;改为直接从 created_batch RETURNING 返回。
  3. 前端 Page parser 使用 object spread 意外保留 rawItems,可能泄漏服务端额外字段;改为显式逐字段构造 Page。
  4. disposable API 的 pgpass 原文件只匹配持久数据库名;使用单次 0600 临时 pgpass 精确匹配 disposable DB,测试后删除,没有改动原密钥文件。

最终边界

业务人工审核决定       0
业务封批               0
生产发布               未执行
生产 WeKnora           未连接
Release Worker          false
release Jobs            0
PP 源文件              未修改
卷                      保留
commit / push           未执行
凭据输出                0