dcdc8d1ddd
全栈知识治理平台首次入库(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 干净
8.4 KiB
8.4 KiB
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和 Publicationupdated_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
截图视觉检查未发现横向裁切、遮挡、乱码或阻断问题。
已发现并修复的问题
- PostgreSQL 审核参数同时参与比较与 VARCHAR 插入时类型推断冲突;为参数加显式 cast。
- data-modifying CTE 同语句从基表读取新 batch 看不到新 snapshot;改为直接从
created_batch RETURNING返回。 - 前端 Page parser 使用 object spread 意外保留
rawItems,可能泄漏服务端额外字段;改为显式逐字段构造 Page。 - disposable API 的 pgpass 原文件只匹配持久数据库名;使用单次 0600 临时 pgpass 精确匹配 disposable DB,测试后删除,没有改动原密钥文件。
最终边界
业务人工审核决定 0
业务封批 0
生产发布 未执行
生产 WeKnora 未连接
Release Worker false
release Jobs 0
PP 源文件 未修改
卷 保留
commit / push 未执行
凭据输出 0