Files
knowledge-governance/docs/library-acceptance-matrix.md
姚章浩 066dc45a25
build / build (push) Successful in 1m34s
fix(release): 删除型索引恢复不再用 ES 统计计数放行
- ES `_stats` 写计数是分片生命周期统计(官方文档:分片迁到另一节点时该分片统计清零),
  索引 uuid 不变不绑定统计生命周期,清零后重新累计到同一数值(ABA)无法排除。
  撤销 r36 的"写计数器栅栏"授权:既不落盘也不读取,统计仅作诊断。
- 删除型恢复(独占 `_create`)只有在本次尝试开始时不存在任何恢复意图、且文档确实缺失时
  才可重做;既存 restore-mark-intent 配缺失文档一律 held、零写入。
- 保留可证明路径:marker 仍在且世代一致的 clean 收尾重试;文档仍是 applied 结果、
  世代一致的 DELETE 补偿重试。
- 新增 ABA 反例(传输层 stats 故障模拟、真实 ES 文档写删、未重启共享 ES);
  B19 / clean / delete 安全正例全回归。

验证(真实 PG/ES/MinIO 隔离夹具):
- ABA 反例:旧代码 RED(restoration must be held, not rebuilt),新代码 PASS
- 索引/恢复回归 13 项 PASS
- 回滚回归 2 项 PASS
- make verify 16 项 success(identity 仅 CI 可核)
未部署、未写生产/云、未重启共享 ES。
2026-11-02 01:19:00 +08:00

26 KiB
Raw Permalink Blame History

整库同步验收矩阵(真实证据对照,2026-10-29 重排)

本文件是唯一口径:状态只写实际发生的事,四类严格分开,不用"部分通过"含糊过去。

2026-10-29 用户决定(覆盖历史验收口径):发布管理不承担 Wiki 语义撤销—— 它只负责把测试端已确认的整库快照原样还原生产。因此撤销后正文里是否残留 撤销方独有事实,属于上游知识质量问题,不在本模块验收范围内:V03-a 保留原始 失败证据(见「一·补」下方的"模块范围外"表),不改成通过,也不再阻断发布。 同时不新增 LLM 重写、人工逐页复核闸门,也不把升级 WeKnora 作为前置条件。 保留的门槛是:整库文档/分块/索引/资源/Wiki 正文·来源·链接·目录一致、稳定切点、 实际维护与排空、准确快照授权、独立预备份与恢复、失败回滚、作业互斥与重启接管、 真实 UI 进度与存储安全。效果问答/性能/A06 不是门槛。

口径 含义
已完成·已验证 有代码 + 真实服务(真实 PG/ES/对象存储/原版 WeKnora API)跑出来的证据,或既有 CI 检查覆盖
缺代码 功能/契约本身没有实现;界面按"未接入"显示,不冒充
已实现·未跑 代码与测试在位,缺真实环境执行证据(不是权限问题)
需授权/需环境 实现所需的动作属于生产写入/读取/恢复,或需要本会话拿不到的资源

A06(内容、问答、引用图片效果、性能报告)已由用户取消,不作为门槛,也不在本表。


一、已完成·已验证

ID 要点 承载位置 证据(本轮或前轮,均可回看)
V01 只有对内/对外两个目标,身份来自配置映射 internal/httpapi/library_*.go;web/src/ReleaseTargets.tsx overview 对非法 scope 返回 400;真实归档 internal/external 各自解析到唯一 KB
V02 解析/索引/Wiki 就绪,验收绑定本版 v071/library_source_settlement.go 结清检查在封存前执行、缺项阻断;页面注明依据哪次快照
V04 完整固定版本:文档+处理结果+资源+索引+完整 Wiki internal/librarysnapshot/* 真实快照 f992d64e…:4 文档/38 分块/122 索引/21 资源/31 Wiki 页/55,309,044 字节,部件摘要逐项校验
V06 只同步知识数据,不含账号/会话/凭据 导出白名单(10 知识表 + 知识域索引 + 资源 + Wiki) 部件清单无 users/sessions/api_keys
B01 每次生产写入前完整预备份,失败零写入 v071.ProductionBackupStore.Prepare + prebackup 阶段 真实 PG/ES 上预备份 3111e823…;故障注入后用它恢复并校验
B03 每版保存完整 Wiki 与引用关联并校验 library_snapshot wiki 部件 + 摘要 真实快照 31 页逐页摘要;manifest 记录数量/字节
S01 数据库/资源/索引/Wiki 真实落地并校验 v071.ProductionLibraryTarget.Apply/Verify 本轮 sync libsync-internal-…1793221776816380302:database 67 行、resources 21、index 122、wiki 63 行全部 succeeded + verify succeeded;目标库 wiki 31 页
S02 生产不再解析/Embedding/生成 Wiki index 阶段直接搬运归档 embedding 真实 ES 写入归档 embedding,未调用模型
S04 各阶段失败/超时/重启可追溯可恢复 library_jobs/library_job_stages + ReconcileLibraryJobs 阶段与错误持久化;worker 清理"队列无对应作业"的孤儿
S05 幂等与互斥(多 worker 安全) 幂等表 + active 唯一索引 真实 PG:同目标第二作业被拒;同键同 digest 复用;换 digest 冲突
R01 按指定版本手工恢复 POST /library/restores + library.restore 真实跑通:撤旧授权→503;签发 restore 授权→202→succeeded,内容回到目标版本(evidence/B_restore.json)
R02 恢复失败显式异常、不回退测试库 Outcome.State=rollback_failed + 独立阶段 隔离测试 + 前轮真半写场景(partial.json)
P01 作业阶段与整体状态 library_jobs.state/stage;页面阶段条 阶段勾选只认当前作业证据;无作业显示"尚未开始"
P02 四类分项计数/字节/错误 stageSizesFrom(manifest) + library_job_stages 真实数据:database 67/88086B、resources 21/53490166B、index 122/1624880B、wiki 63/105912B
P03 同步明细与异常 页面"同步明细"读阶段行 行来自持久阶段,刷新/重启可复现
U01 发布管理为主要入口(两库+单作业区) web/src/ReleaseTargets.tsx 按确认稿布局,父会话已在登录浏览器核验
U02 权限边界 canWrite/canCapture,写操作需 engineer+ 无权限不给封存入口;未接线显示通道状态
U03 操作确认 封存按钮 + 作业号 + notice 同一作业号重放返回已存作业并提示
D01 保留策略(数量/天数) internal/libraryretention 未设置=0 按"全部保留",不编默认值
D02 占用测量 internal/librarysnapshot/usage.go 版本数/去重内容/blob/未引用/清单;两份真实清单 55,309,693 字节
D03 依赖保护 libraryretention.Build 的 Protected/ProtectedBy 真实归档两版均因"最近测试封存"受保护
D04 清理预览 Build 的 Candidates/ReclaimPreviewBytes keep=1 时仍 0 候选;回收预览只计独占字节
D05 容量门禁 CheckCapacity + sync gate 预算未设置→阻断;超预算→阻断并给预计字节
D06 测试残留口径 未引用 blob 统计 真实归档未引用 blob 为 0(口径,不等于扫过全部残留)
S03 实例级维护窗口:关入口→排空→静默证明→停写者→写入→校验→开入口 internal/libraryfreeze + librarymaintenance + 迁移 070–072 前轮 7 场景真跑全绿(normal/kill/applyfail/partial/crossscope/recover_refuse/recover_ok),本轮 sync/drain 场景继续复用;quiesce 证据、post_stop_*、journal、gate drain.json 均可回看
V03-b 治理侧能把上述语义变化说清楚(不是页面级"无变化") internal/librarydiff/wiki.go CompareWiki;GET /library/overview 的 diff.wiki 逐页比对正文/来源/引用/出入边/目录,输出 sources_removed、citations_before→after、changed;单测 wiki_test.go、视图单测 library_wiki_diff_test.go;页面逐行展示(wikiContributionLines + 测试)
S06 页面/API 发起封存 → 主机 agent → 实例级窗口封存(真实冻结) POST /library/captures + cmd/libraryagent(0600 socket、固定命令)+ libraryctl capture(实例级:闸门/后台静默/指纹) 本轮终态(0.1.186 e508abd)真跑:POST /api/v1/library/captures(job lib-internal-20261029T0716)202 → worker → agent → CLI → 关闸门排空 → 等后台静默 → 停 kgmaint-app(exit=1、drain_verified=true、stop_verified=true、restored=true)→ 导出 → 恢复写入者与入口;作业 libseal-lib-internal-20261029T0716 succeeded,快照 0f0a3b68…。证据 kg-final-gaps/evidence/04-inflight-v05-final.json、journal freeze-kgmaint/lib-internal-20261029T0716.json
S06-a 排空证明取自真实在途请求(不靠 202 后抢时序) 闸门 drain.json + 客户端真实上传握手 本轮终态真跑:先发一半 multipart 正文 → 闸门 conn:open active=1 → 再发起封存 → 入口关闭 → 补完正文,应用 200 并完成解析/嵌入 → drain.json phase=drained active_at_close=1 served=143 drain_ms=352;journal quiesce.samples=18 stable_ms=1617 且停写者后指纹不变(post_stop_digest == digest)。窗口内派生任务真的跑完(探针文档 f7fed988… completed / 7 分块),且该文档出现在被封存的快照里
V03-c 带"撤销后共享页"的整库封存 → 独立目标同步 → 恢复,逐项真实读回 libraryctl 封存 + ProductionLibraryTarget + libraryrelease 本轮终态真跑(字节一致性,不是撤销语义):KB e64e82b5(9 Wiki 页、1 文档、2 分块、1 资源)→ 快照 0f0a3b68… 与源逐页一致(05-snapshot-compare.json ok=True)→ 同步到独立实例 kgseal libsync-internal-1793229249632461601 succeeded → 目标逐页/索引/资源字节一致(07-target-compare.json ok=True,含目标桶对象 sha256)→ librestore-internal-1793229274077866298 succeeded → 目标仍逐项一致。注意:该共享页正文仍带撤销方残留(见 V03-a 不通过),本行只证明"搬运/恢复逐字节一致"
S06-b 主机侧封存/恢复必须与 worker 讲同一份维护声明 internal/librarymaintenance/env.go(LIBRARY_TARGET_* 唯一解析处) 缺项时 capture 在开窗口前拒绝并点名;agent 启动打印维护目标;单测 5 项(逐项缺失/空白/口令空格/队列库号)
Neo4j 启用场景 启用图谱的库必须被真实拒绝 v071/library_export.go 读 indexing_strategy.graph_enabled 本轮真跑:在 kgmaint 建 graph_enabled=true 的真实 KB 8de41ca7…,用真实 CLI 预检 → 退出码 1、LIBRARYCTL_FAILED: Neo4j graph snapshot is not supported(evidence/10-neo4j-refuse.txt)。不是 skip
执行器可用性(运行时观测) 页面的"可发起封存"来自 worker 的真实探测,不是配置字符串 internal/libraryexecutor + agent health + 迁移 074 library_executor_status + worker 30s 心跳 本轮真跑(候选栈,代码 SHA 4c79052 / 0.1.192 的工作树构建):GET /library/overview 返回 capture_available=true 且 executor={instance:kgmaint-weknora, project:kgmaint-weknora, source_app:kgmaint-app, observed_at:…};停候选 agent 后同一接口转 false、原因 主机侧封存执行器不可达:library agent is unreachable,此时 POST /library/captures 返回 503 library_capture_unavailable;重启 agent 后自动恢复 true。证据 $TMPDIR/kg-candidate-verify/evidence/{01,03,04,05}-*.json
按版本恢复入口 页面不再把"恢复至该版本"写死 disabled;条件来自双闸/授权/维护 GET /api/v1/library/restore-availability + web/src/ReleaseTargets.tsx 接口真实返回 200(候选栈,缺授权时逐条列出原因);页面按 allowed 启用、管理员才见"签发恢复授权(30 分钟)",授权与执行是两步。证据 02-restore-availability.json + 前端用例 libraryRestore.test.ts / ReleaseTargets.test.tsx
U04 维护级别/进度/恢复错误真实呈现 MaintenanceCard(web/src/ReleaseTargets.tsx)、/api/v1/library/maintenance 显示实例级/库级、持有 scope+作业、阶段、入口开/关、服务、开始/释放、进度(阶段名中文化)、恢复错误与处理记录;仅"窗口仍持有且作业失败"时给"按预备份恢复";无记录时"未接入 + fail closed"。组件测试 6 项

| V05 | 导出中源变更必须被入口/写入者阻断,切点一致 | 闸门 drain.json + 真实并发客户端 | 本轮终态真跑:入口关闭的同一刻(固定协调点,非 sleep)对专用源发 8 写 + 4 读 → 8 写全部失败(7 URLError/1 RemoteDisconnected)、4 读 RemoteDisconnected;写入者被停下的那一刻(轮询容器状态捕获 running→exited→running)再发 4 写 + 2 读 → 全部 URLError。事后源库 v05 文档 0 / 分块 0,快照与源逐项一致(ok=True),在途文档 f7fed988… completed/7 分块且出现在快照里。证据 04-inflight-v05-final.json | | B02 | 源测试桶删对象后,归档自包含且目标应用能读回同样字节 | 归档 resource 部件 + 目标应用下载接口 | 本轮终态真跑:源对象 10001/d4fbe69d…/ab2b628f….md(507B,sha256 25a55cd8…)先备份再 mc rm(stat 已 404)→ 同步仍 succeeded(字节只可能来自归档)→ 目标桶 kgseal-1029a 同键 507B、sha256 一致 → 目标应用自己的 GET /api/v1/knowledge/{id}/download 恢复前后都 200 / 507B / sha256 25a55cd8…。修复前该接口真实 500(code 1007 invalid MinIO file path),见 0.1.184/0.1.185 两条修复。证据 11-b02-delete-and-sync.json、12-b02-restore-download.json、07-target-compare.json | | 死信精确解除(治理侧) | 保留上游死信行,只按精确指纹解除 | 迁移 073 + internal/librarydeadletter + POST/GET /library/dead-letter-releases + libraryctl dead-letters + -released-dead-letters | 已实现并有真实验证的部分:libraryctl dead-letters 在真实源上读出 0 条死信与观测摘要;治理 API GET 返回 instance=kgmaint-weknora、releases=[];POST 无写意图头 403;带真实观测但引用不存在的死信 → 409「观测里没有这条死信」。单测覆盖:摘要被改写、源侧未结清、重放早于失败、重放后又出现同键新死信、实例不一致、通配指纹。未演练:真实死信→重放→解除→放行(本轮没有死信,也没有源侧管理员凭据) |

一·补 失败 / 不通过(不得标通过)

ID 要点 承载位置 本轮真实结果
(无) 本模块没有"不通过"项:撤销语义已明确移出范围(见上表下方"模块范围外"),不在此改写为通过 — —

模块范围外(用户 2026-10-29 决定;证据保留,不改判)

ID 要点 本轮真实结果(原样保留)
V03-a 撤销一份共享贡献后,清除撤销方独有正文/引用/实体边 上游不通过,模块范围外:真实 DELETE /api/v1/knowledge/{id} 后,共享页 entity/fa-bu-zha-men 的来源/引用/边/目录都按上游 retract 更新(source_refs 只剩保留文档、引用 2→1、9 页/18 边无死链),但正文仍保留撤销方独有的两句事实 ZEBRA-A-7731/ZEBRA-A-9910(version=3、3733 字节、sha256 5fd27348…)。这是上游 retract 走 LLM 重写的非确定性结果,治理侧只按字节搬运,不能也不应改写它。证据 kg-final-gaps/evidence/14-wiki-residue-evidence.json + 01-wiki-source-after-r3.json,不涂改

二、缺代码

ID 缺口 现状与影响
R02-b 删除型索引恢复的自动重试 应用期删掉了目标文档、恢复写入是独占 _create。持久意图已落盘而文档缺失时,服务端没有可持久、不可重用的"这份写入没落地"证据:缺失与"从未写过"同形;ES _stats 写计数是分片生命周期统计(官方文档:分片迁到另一节点时该分片统计会被清零),索引 uuid 不变不绑定统计生命周期,清零后重新累计到同一数值(ABA)不能排除。现状 fail-closed:既存 restore-mark-intent 一律 held(rollback_failed、零写入、零误归属),不自动重试,需人工按预备份核验后重新规划;本次尝试开始前不存在任何恢复意图时仍可正常重建。这是开发缺口(r37 反例:同 uuid 同计数 + 真实写删,恢复仍须 held),不是用户接受的能力收窄;是否引入可校验的持久 not-dispatched 状态与派发原子协议,由后续设计决定。保留的可证明路径:真实 marker 仍在且世代一致的 clean 收尾重试、文档仍是 applied 结果且世代一致的 DELETE 补偿重试
R03 存快/恢复快对比 A06 性能报告已由用户取消,不作为门槛。已记实测耗时(小测试库,不是压测):封存 15.8s(含停写~5s)、同步 13.6s(预备份 13.4s 占主要)、恢复 13.8s;证据 13-r03-durations.json。没有做高负载压测,也不写没有测量的数字
死信解除·真实重放演练 没有可解除的真实死信,也没有源侧系统管理员凭据 契约与执行侧已实现(见下节新增行):上游保留原行、治理侧审计+指纹绑定、未结清/变化/新死信仍阻断。本轮没有真实死信(dead_letters=0),无法演练"真实重放成功→解除→放行"整条链路;上游只有 系统管理 runtime run_now(需要源侧管理员权限)与整队列 purge(销毁证据,不采用)。治理平台故意不持有源侧管理员凭据(放大授权),因此这一步阻塞在真实死信 + 重放执行方,不伪造成功

三、已实现·未跑

ID 要点 为什么未跑
S03-b 死信/孤儿任务阻断的负向演练(本轮只验证了真实死信阻断) 真实阻断已发生并记录;系统化的负向矩阵未跑
排空时序(历史结论) 旧做法"202 之后抢时序上传"在 1faf513 上重跑 6 次全部 Broken pipe(drain-task-final-1faf513*.json 保留,不记通过) 已被 S06-a 的确定性做法取代:先证明请求已被闸门接收,再启动维护。旧证据保留,不覆盖
封存执行期身份复核(真实封存) 期望身份随 capture 请求送进 agent,由它在操作互斥内、任何源操作之前比对(swap_test.go 用两个真实 agent 的 socket 替换做负例,断言错误 agent 的 capture 调用 0 次);真实封存尚未在最终构建上跑,本轮没有在候选栈发起真实封存(会产生新快照与停写入者窗口),因此"换 socket 被挡住"只有单测证据
按版本恢复的真实执行(新构建) restore-availability 真实返回、恢复投递路径有单测;真实恢复作业仍在旧构建上验过(R01),本轮未重跑,不把旧证据算作新构建证据
S04-b 重启接管(不同快照、after:database 真中断) 真实作业已经证明"写链路能续完",但脚本级验收还没拿到 exit 0:当轮判据绑在"只有一条代码路径会打印"的文案上(library job <id> resumed after worker restart),真实走的是"队列行已存在"那条,于是 worker 只留下汇总行 takeover sweep: 1 resumed ⇒ 脚本 exit 5。判据已改成"认领行 + 决策行 + 时间戳晚于杀点"(scripts/takeover_log_contract.py,含 11 条正负例自检,进 make verify),prebackup 也不再强制 skipped(真实是复用后重跑整条链路,记 succeeded),改为证明复用同一份(快照 id/清单字节+mtime/首次登记时刻不变 + backup_reused=true)。下一轮演练(目标 fc5955…,4/38/31)由父在 UI 发起,才是脚本级验收
U05 正式 8088 页面验收 正式栈仍是 0.1.114,本轮未替换;维护面板/逐页 Wiki 差异只在测试与候选构建里验证过

四、需授权 / 需环境

ID 事项 缺什么
D07 实际回收(真删对象/版本) 自动清理默认关闭;删除属于真实清理,需单独授权
远程生产 生产写入/恢复/清理 用户授权范围只到本机专用验收实例;远程生产一律未执行
生产目标维护 对共享业务栈开维护窗口 本轮明确不停 WKNFull-app;维护只在 kgmaint 专用实例上跑
生产封存/同步真实链路 需要在生产机部署 libraryagent 并接线 需要用户批准的部署窗口与凭据录入

四·补 运维风险(本轮核对,未擅自处理)

正式 8088 栈(knowledge-governance-p1-api-1 / -worker-1)当前引用同一个 agent socket: api env LIBRARY_AGENT_SOCKET=/run/library-agent/agent.sock,worker 挂载 /home/zheromiku/.local/share/knowledge-governance/agent -> /run/library-agent。而主机侧 user 单元 ~/.config/systemd/user/knowledge-governance-library-agent.service 本轮已把目标改成 kgmaint 验收实例 (-source-app kgmaint-app、-project kgmaint-weknora、-archive /tmp/kg-e2e/archive, 原 WKNFull 版备份为 *.wkfull.bak)。后果:从正式 8088 发起封存会冻结测试实例,并把快照写进 正式 API 看不到的归档目录(正式 api 的 LIBRARY_ARCHIVE_ROOT=/var/lib/knowledge-governance/library)。 本轮没有启动任何共享维护,也没有改回该单元——需要用户决定:正式上线前把单元恢复为 WKNFull 版 (备份已在位),或给候选构建单独的 socket 路径。证据 00-identity-final.json 的 formal_stack 段。

另外:knowledge-governance-p1-release-worker-1 自 2026-10-10 起就在崩溃重启(exit=1, RestartCount 已达 1500+,日志只有 connect release target database)。本轮只读定位到根因: config/release.sim.json 的 target.database_url_file 指向 prod-pg:25432,而该主机名在本机与 容器网络里都不存在(getent hosts prod-pg 无结果、容器内 NXDOMAIN);source 指向的 WKNFull-postgres 可解析,所以是目标库配置遗留,不是代码缺陷。错误文本吞掉了主机与原因, 本轮已改为带端点 + 路由 + 脱敏原因(可在下次重启时直接看到),但修正正式配置或停用该 worker 属于正式栈变更,需要部署窗口授权,本轮没有执行。


五、本轮新增结论(写在这里而不是报告顶部)

  1. Wiki 撤销语义本轮不通过,且不是治理侧能自己补的:上游 retract 走 LLM 重写,重跑一次留下两句撤销方独有事实(ZEBRA-A-7731/ZEBRA-A-9910),另有 r1 轮次把两句清掉的记录——同一输入两次结果不同。原版 v0.7.1 的 Wiki API 只有页 CRUD、rebuild-links(只重算 [[slug]] 边,metadata-only)、auto-fix(只修 lint 可修项),没有"按剩余来源重算页面正文"的安全 API(internal/router/router.go:2354 起的路由表 + service/wiki_page.go:759)。因此:①不得把 V03 标通过;②不得用关键词硬删掩盖;③可选方案见交付报告(外部最小治理:保留旧版本+关联撤销作业+受影响页重建或阻断发布+验证与审计,需用户拍板产品语义)。
  2. 治理侧不能只报页面级差异:撤销共享贡献时页面仍是"更新",页面级计数会显示成"无变化"。已改为逐页语义比对,能指出"来源 -1、引用 2→1、正文变了、出边少了一条"。
  3. 封存链路本轮真的打通了,而且不是放松校验:CLI 改为实例级窗口(闸门 + 后台静默 + 目标指纹),"写者 exit=1"由闸门的 drained/active_at_close 证据解释,而不是被忽略;排空证明改成"先在途、再关入口"的确定性顺序,不再靠 202 之后抢时序。
  4. 接线后暴露的四个真缺陷(都已修,都有用例):jobs.id 列宽 36 让封存作业根本投不进去;v0.7.1 的 app 写索引不带 tenant_id 导致导出 0 条;全新实例的空索引被当成"索引被改坏";恢复作业 id 带 . 被维护窗口拒。另有资源定位符仍写来源桶——同步过去的目标取不到图/附件。
  5. 死信解除已从"缺代码"变成"有代码、真实验证了一半":迁移 073 记录精确解除(保留上游行、绑定实时行指纹、重放引用、源侧观测摘要、操作人);封存时每条实时死信都必须被精确解除命中,行变化/新行/未结清照旧阻断;libraryctl dead-letters 生成只读观测,libraryctl -released-dead-letters 逐字节复核。没有演练的部分是"真实死信→重放→解除→放行":本轮源侧 dead_letters=0,且重放需要源侧系统管理员权限(/system/admin/runtime/queues/{queue}/tasks/{id}/actions/run_now),治理平台故意不持有该凭据。不伪造成功,也不 SQL 删行冒充。
  6. 同步过去的资源"能被应用读出来"是这轮才真正验的:资源行里既有 physical_path 也有独立的 storage_backend_id 列,两者都指向来源实例的 storage_backends 主键;只换桶或不换列,目标应用都 500(code 1007 invalid MinIO file path)。已在同一份行变换里同时改后端 id 与桶,解析不到就拒绝写入。

六、2026-10-30 补录:中断接管这一轮到底验到了什么

已经实测(可回看,不是推断):2026-10-29T19:56Z 的 after:database 演练 (作业 librestore-internal-1793303791259342087,目标 0d982f76…,与中断前的生效版本不同):

  • 宿主机向 worker 容器 PID1 发 SIGKILL,docker events 有 die exitCode=137,restart policy 拉起 (同容器、同镜像,RestartCount 0→1)——不是 docker kill、不是人工 docker start;
  • 同一作业被启动扫描认领并续完:database/resources/index/wiki/verify/finalize 全 succeeded, 作业终态 succeeded,生效版本 source_job_id 就是本作业,维护两把锁都已释放;
  • 写集合摘要 ec149a69… 与预备份 69eb5a90… 身份在接管前后一致(预备份清单 mtime 仍是崩溃前 19:56:45Z,说明没有重做备份);
  • 目标内容 knowledges=1 / chunks=2 / wiki_pages=9(按该快照 manifest 推导);
  • 只读补验 7 项全绿(~/.hermes/handoffs/release-takeover-evidence-next/readonly-verify-20261029.json): 写集合独立校验、目标/预备份逐部件字节+sha256、治理库归属与阶段、目标库逐 id+内容、 目标索引文档集合、目标桶对象字节+sha256。

还没成立(不许当通过):

  • 当轮脚本判据是错的(exit 5,老文案只在一条路径打印)⇒ 这一轮不能算"脚本级验收通过", FAIL 证据原样保留在 drills/20261029T195605Z/;
  • 接管后的 prebackup 版本行 created_at 被当轮二进制重写成接管时刻(已修:预备份行取 LEAST, 并写 backup_reused=true)——旧现场保持原样,不改写;
  • pending_final(只差收尾)路径与 foreign_effective(拒绝接管)的端到端仍未在真实演练里跑过;
  • 下一轮不同快照演练(fc5955… → 4/38/31)待父在 UI 发起。