Files
knowledge-governance/docs/library-acceptance-matrix.md
T
姚章浩 281699a431
build / build (push) Successful in 1m21s
feat(library): 生产整库真实读写/校验/恢复与本机真实服务验收
为什么:生产目标此前是"无条件失败"的占位,编排再完整也不能落地;本轮把它做成真实实现,
并在本机 WeKnora 测试栈的真实 PG/ES 上跑通导入、撤销、预备份与故障恢复。

- ProductionLibraryTarget:Current 读行数+身份摘要;Apply 按阶段真实写入(database/wiki
  同事务先删本库再插、resources 传对象、index 搬运原始文档与向量);Verify 比对身份摘要;
  Restore 按预备份快照回放。
- 撤销真正生效:索引阶段写入后 PruneScope 删除快照里没有的文档。
- ProductionBackupStore:导出前独立完整预备份,导出前后行数不一致即失败。
- worker 用注入配置装配目标与预备份;缺项把变量名写进阶段并失败,不再有占位对象。
- capacity 安全加法防溢出;保留策略组合语义明确(各维度都超限才候选)。
- 新增本机真实服务集成测试(一次性 kg_library_test_* 库 + 随机 ES 索引),
  覆盖导入/校验/撤销/预备份/故障注入/恢复。
2026-10-28 15:54:01 +08:00

9.2 KiB
Raw Blame History

整库同步验收矩阵(真实证据对照)

对应 docs/library-sync-acceptance.md 的 30 个验收项。状态只写实际发生的事:

  • 已实现·已验证:有代码 + 本机真实数据或真实归档/真实 PostgreSQL 跑过的证据,或既有 CI 检查覆盖。
  • 已实现·未验证:代码与测试在位,但还缺真实业务环境的执行证据(例如需要隔离生产栈)。
  • 阻塞(需授权/环境):实现所需的动作属于生产写入、生产读取或生产恢复,当前授权明确禁止。
  • 未实现:还没有代码,界面按"未接入/未知"显示,不冒充完成。

A06(内容、问答、引用图片效果、性能报告)已被用户取消,本矩阵不含该项,也不再作为封版门槛。

状态口径(严格区分四件事):

  • 已实现·已验证:代码 + 本机真实归档/真实 PostgreSQL 或既有 CI 的实跑证据。
  • 已实现·隔离测试通过:代码 + 单元/集成测试(注入假生产目标),没有真实生产执行。
  • 已实现·未验证:代码在位但缺真实环境证据。
  • 未实现 / 真实执行未授权:前者是代码缺口,后者是权限缺口,两者不混用。
ID 验收要点 代码 / 承载位置 状态 证据或缺口
V01 只有对内/对外两个目标,身份来自配置映射 internal/httpapi/library_*.go(scope 只接受 internal/external);web/src/ReleaseTargets.tsx 已实现·已验证 overview 对非法 scope 返回 400;真实归档里 internal/external 各自解析到唯一 KB(0c84a098… / 对外 KB)
V02 全部解析/索引/Wiki 就绪,验收绑定本版 internal/releaseadapter/v071/library_source_settlement.go;页面准备清单 已实现·未验证 结清检查(settlement)在封存前执行且缺项阻断;但对"实时测试库此刻就绪"仍需一次真实封存复核;页面已注明依据的是哪次快照
V03 删除文档后 Wiki 共享正文/实体/边/引用真实变化 wikiDiffOf(页面级差异) 部分实现 真实归档验证:对内 vs 对外 = 新增 31 页 / 撤销 1 页,反向镜像一致。页面级不等于实体/概念/边/引用的语义重算,后者仍需 WeKnora 内部证据,未实现也不声称
V04 完整固定版本:文档集合+处理结果+资源+索引+完整 Wiki internal/librarysnapshot/*(10 表 + 索引 + 资源 + Wiki 部件);artifacts 清单 已实现·已验证 真实快照 f992d64e…:4 文档/38 分块/122 索引/21 资源/31 Wiki 页/55,309,044 字节;部件摘要逐项校验
V05 导出中源变更则拒绝或隔离 internal/libraryfreeze/* + 预备份导出前后行数静默检查 部分实现·未验证 预备份导出前后行数不一致即失败(本机已验证会拒绝);真实并发写入的隔离演练仍未做
V06 只同步知识数据,不含账号/会话/凭据 导出白名单(10 张知识表 + 知识域索引 + 资源 + Wiki) 已实现·已验证 部件清单里没有 users/sessions/api_keys;真实归档部件名可逐项核对
B01 每次生产写入前完整预备份,失败零写入 v071.ProductionBackupStore.Prepare + libraryrelease prebackup 阶段 已实现·本机真实服务已验证 本机真实 PG/ES 上生成预备份 3111e823…(626 字节),带导出前后行数静默检查;故障注入后用它恢复并校验通过。生产目标本身未授权,未对真实生产执行
B02 资源在测试侧删除后仍可恢复 归档内容寻址 blob(library_versions + librarysnapshot 内容去重) 已实现·未验证 归档不依赖测试临时对象;跨版本去重 55,309,693 字节;尚未做"测试侧删除后从归档恢复"的实测
B03 每版保存完整 Wiki 与引用关联并校验 library_snapshot 的 wiki 部件 + 摘要 已实现·已验证 真实快照含 31 页 Wiki 与逐页摘要,manifest 记录数量/字节
S01 数据库/资源/索引/Wiki 真实落地并校验 v071.ProductionLibraryTarget.Apply/Verify(真实 SQL + ES bulk) 已实现·本机真实服务已验证 本机真实 PG/ES:导入 1 文档/1 分块/1 Wiki 页/1 索引文档并逐表身份摘要校验;写入只覆盖知识域表
S02 生产不再解析/Embedding/生成 Wiki 索引阶段直接搬运归档原始文档与向量 已实现·本机真实服务已验证 真实 ES 写入的是归档里的 embedding 数组(未调用任何模型);生产环境本身仍未写入
S03 一致生效与失败补偿边界 — 未实现 跨 PG/ES/资源的一致切点与可见性保护未实现
S04 各阶段失败/超时/重启可追溯可恢复 library_jobs/library_job_stages + ReconcileLibraryJobs 已实现·已验证 阶段与错误持久化;worker 启动清理"队列已无对应作业"的孤儿并写明恢复责任,避免永久占锁
S05 幂等与互斥(多 worker 安全) library_jobs_idempotency、library_jobs_active 唯一索引 已实现·已验证 真实 PostgreSQL 上验证:同目标第二个在飞作业被拒;同键同 digest 重放复用;同键换 digest 冲突
R01 版本恢复整套生产知识状态 ProductionLibraryTarget.Restore 按快照回放四类阶段 已实现·本机真实服务已验证(失败自动恢复) 真实 PG/ES 上注入缺行故障后恢复并校验通过;"按版本手动恢复"入口仍未接线
R02 恢复失败显式异常、不回退测试库 Outcome.State=rollback_failed + 独立阶段记录 已实现·隔离测试通过 测试断言恢复失败与同步失败可区分,且不触碰测试库
R03 存快/恢复快对比 — 未实现 未做测速;不写没有测量的数字
P01 作业阶段与整体状态 library_jobs.state/stage;页面阶段条 已实现·已验证 阶段勾选只认当前作业证据;无作业时显示"本次作业尚未开始"
P02 四类分项计数/字节/错误 library_job_stages(NULL=未知总量) 已实现·已验证 真实库验证阶段行为;无 total 时页面显示"未知总量",不画百分比
P03 同步明细与异常 页面"同步明细"表读阶段行 已实现·已验证 行来自持久阶段,刷新/重启可复现;封存作业显示 export 阶段真实状态
U01 发布管理为主要入口(两库+单作业区) web/src/ReleaseTargets.tsx 已实现·已验证 按确认稿布局;父会话已在登录浏览器核验两库切换与抽屉
U02 权限边界 canWrite/canCapture,POST 需 engineer+ 已实现·已验证 无权限时不给封存入口;未接线时说明通道状态
U03 操作确认 封存按钮 + 作业号 + notice 已实现·已验证 同一作业号重放返回已存作业并明确提示
D01 保留策略(数量/天数) internal/libraryretention;LIBRARY_RETENTION_VERSIONS/DAYS 已实现·已验证(单测+真实归档) 未设置=0 时按"全部保留",不编默认值;设置了才生成候选
D02 占用测量 internal/librarysnapshot/usage.go;系统设置→存储管理 已实现·已验证 版本数/跨版本去重内容/blob 表观与分配/未引用/清单;真实两份清单 55,309,693 字节
D03 依赖保护 libraryretention.Build 的 Protected/ProtectedBy 已实现·已验证 真实归档上 2 个版本都因"最近测试封存"受保护;受保护版本永不进入候选
D04 清理预览 libraryretention.Build 的 Candidates/ReclaimPreviewBytes;GET /library/storage 已实现·已验证 真实归档:策略 keep=1 时仍 0 候选(两版均受保护);回收预览只计独占字节
D05 容量门禁 libraryretention.CheckCapacity + sync gate 已实现·已验证(单测+真实数据) 预算未设置→阻断并说明;超预算→阻断并给出预计字节
D06 测试残留 归档未引用 blob 统计(UnreferencedBlobs/Bytes) 已实现·已验证 真实归档未引用 blob 为 0;这只是口径,不等于扫描过所有测试残留
D07 实际回收 — 阻塞(需清理授权) 自动清理默认关闭,不提供删除动作

差异比对(本轮新增)

internal/librarydiff 以稳定文档 ID 为身份、以排除 updated_at/updated_by 后的整行摘要为内容, 比较两份归档快照的 knowledges 行数组,输出新增/更新/撤销。真实归档上验证: 对内快照 4 篇对空集为"新增 4",反向为"撤销 4",缺失快照返回原因而不是空差异。 生产权威版本建立后即可直接给出生产→测试差异;在生产版本未知时页面保持"未接入"。 Wiki 页面级差异单独返回(diff.wiki),明确标注"不代表实体/边/引用重算"。

未通过项如何阻断

  • POST /api/v1/library/syncs:闸口关闭、缺恢复演练证据、生产端点未配置、生产权威版本未知、 目标快照无预备份——任一成立即 503 并逐条列原因,不创建作业。
  • 页面"启动同步"按同一 gate 禁用,title 与卡片列出全部缺项;不存在"点了才失败"的假按钮。
  • 封存缺项(结清检查不通过、契约不符、导出校验失败)一律阻断封版,不改状态蒙混。