11 KiB
11 KiB
整库同步验收矩阵(真实证据对照)
入口级真实服务验收(2026-10-28,候选 API :18089,真实 PG/ES/MinIO,code_sha=ea4cffb)
| 项 | 状态 | 证据(~/.hermes/handoffs/kg-candidate-e2e/) |
|---|---|---|
| A0 首次发布(生产空基线) | 已实现 / 真实服务已验证 | evidence/A0_baseline.json |
| A1 撤销(自洽派生快照) | 已实现 / 真实服务已验证 | evidence/A1_revoke.json |
| B 按版本恢复(含未授权拒绝) | 已实现 / 真实服务已验证 | evidence/B_restore.json |
| C 写阶段 SIGKILL 接管(复用同一预备份) | 已实现 / 真实服务已验证 | evidence/C_kill_takeover.json |
| D 跨 kind 互斥 + 多 worker 单次执行 | 已实现 / 真实服务已验证 | evidence/D_mutex_multiworker.json |
| E1 版本登记失败不报成功 | 已实现 / 真实服务已验证 | evidence/E1_finalize_fail.json |
| E2 finalize 续作(只收尾) | 已实现 / 真实服务已验证 | evidence/E2_finalize_resume.json |
| E3 预备份登记失败零写入 | 已实现 / 真实服务已验证 | evidence/E3_prebackup_fail_zero_write.json |
| 远程生产写入/恢复/清理 | 未授权,未执行 | — |
| Wiki 撤销贡献语义重算 | 未实现(仅页面级差异) | V03 |
| 跨系统原子切点 | 未实现;按"导出后回读"协议,边界已写明 | — |
对应 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(页面级差异) |
未实现(架构阻塞) | Wiki 页由 WeKnora 在源侧生成,治理侧只搬运快照;"两文档共贡献一页、撤一个另一个保留"必须在源侧重新生成才能验证。本轮未触发源侧生成(属源侧写操作,需原生 Wiki 接口)。页面级差异不等于语义重算,不当作完成 |
| 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 | 按指定版本手工恢复 | POST /library/restores + library.restore 执行器 |
已实现·真实服务已验证 | 候选环境:撤掉全部旧授权→503;签发 restore 授权→202→succeeded,内容回到目标版本(evidence/B_restore.json,作业 librestore-internal-20261028T120300.925270)。远程生产未执行 |
| R02 | 恢复失败显式异常、不回退测试库 | Outcome.State=rollback_failed + 独立阶段记录 |
已实现·隔离测试通过 | 测试断言恢复失败与同步失败可区分,且不触碰测试库 |
| R03 | 存快/恢复快对比 | — | 未实现 | 未做测速;不写没有测量的数字 |
| P01 | 作业阶段与整体状态 | library_jobs.state/stage;页面阶段条 |
已实现·已验证 | 阶段勾选只认当前作业证据;无作业时显示"本次作业尚未开始" |
| P02 | 四类分项计数/字节/错误 | stageSizesFrom(manifest) + library_job_stages |
已实现·真实服务已验证 | 候选环境实测 database 67 行/88086 B、resources 21 行/53490166 B、index 122 行/1624880 B、wiki 63 行/105912 B;prebackup/verify/finalize/rollback 无可定义总量保持 NULL;证据 evidence/A0_baseline.json 的 stages |
| 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 与卡片列出全部缺项;不存在"点了才失败"的假按钮。
- 封存缺项(结清检查不通过、契约不符、导出校验失败)一律阻断封版,不改状态蒙混。