From 18276d0839ce44b4fbf36675ced45884ab379cae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A7=9A=E7=AB=A0=E6=B5=A9?= Date: Thu, 29 Oct 2026 13:01:51 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=8C=89=E7=94=A8=E6=88=B7=E5=86=B3?= =?UTF-8?q?=E5=AE=9A=E6=94=B6=E7=AA=84=E6=95=B4=E5=BA=93=E8=BF=98=E5=8E=9F?= =?UTF-8?q?=E8=8C=83=E5=9B=B4=E5=B9=B6=E8=AE=B0=E5=BD=95=E6=89=A7=E8=A1=8C?= =?UTF-8?q?=E5=99=A8=E8=AF=81=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 发布管理不承担 Wiki 语义撤销:V03-a 的原始失败证据保留,但移到"模块范围外", 不再阻断发布,也不改判为通过。矩阵同步补上执行器运行时可用性与按版本恢复入口的 真实证据(候选栈),并把尚未跑的部分(真实封存身份复核、新构建上的真实恢复) 写在"已实现·未跑"。正式 release-worker 的崩溃根因按实测写清:目标库主机 prod-pg 不可解析,修正配置属于正式栈变更,需要部署窗口。 --- CHANGELOG.md | 38 +++++++++++++++++++++++++++++++ docs/library-acceptance-matrix.md | 32 ++++++++++++++++++++++---- 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fbd316..ed9693e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,43 @@ # Changelog +## 开发快照(发布执行器可用性、整库还原入口与诊断) + +### Added + +- **封存执行器的运行时可用性(迁移 074 `library_executor_status`)**:页面上的 + "可以发起封存"不再等于 `LIBRARY_AGENT_SOCKET` 非空。主机侧 agent 新增 + `health` 动作(不占封存操作锁、不跑子进程),worker 每 30 秒探测一次并把 + "指向哪个实例、归档在哪、是否降级/正在跑、观测时间"落库;API 只读这份观测。 + socket 只挂在 worker 容器里,所以由 worker 观测、页面读结果,而不是让 API + 假装能 dial。观测过期、不可达、实例不符、降级、正忙时页面与 + `POST /library/captures` 用同一份判定拒绝,并逐条给出原因。 +- **封存执行前后的身份复核**:封存结果由 agent 附上自报身份(`agent_identity`)。 + worker 在停写入者之前再探测一次,执行后再用结果里的身份复核;不一致时作业失败 + 且**不登记**为测试封存——心跳只能证明"刚才",从心跳到停写入者之间 socket + 可能被换掉。 +- **按版本恢复的页面入口**:`GET /api/v1/library/restore-availability` 说明 + "这份快照现在能不能恢复"(双闸、该快照的恢复授权、目标实例是否在维护)。 + 页面据此启用"恢复至该版本",管理员可签发 30 分钟有效期的 restore 授权; + 工程师只看到条件,不获得入口。 +- 可选 `LIBRARY_SOURCE_PROJECT`:声明封存执行器应指向的实例名(默认等于 + `LIBRARY_SOURCE_INSTANCE`)。它描述封存源,与同步目标 `LIBRARY_TARGET_*` 分开。 + +### Changed + +- `LIBRARY_EXECUTOR_STATUS_MAX_AGE`(默认 120 秒)控制执行器观测的有效期; + 未设置不等于"永不过期",过期即"无法确认"。 +- 页面/接口不再出现写死的"封存通道未接线""生产恢复未接线":不能发起时给出真实原因、 + 执行器身份与观测时间。 + +### Fixed + +- **正式 release-worker 启动失败无法定位**:配置里的目标库指向不存在的主机时, + 日志只有一句 `connect release target database`。现在错误里带库端点 + (`host:port/db`,去口令)与路由标识,并保留底层原因;原因文本先经 + `pgdsn.Redact` 抹掉口令(pgx 的解析错误可能原样回显连接串),可诊断不等于泄露。 + 共享的 `internal/pgdsn` 替换了 cmd/worker 里只留库名的旧实现。 +- `libraryctl` 用法文本补上 `dead-letters` 子命令。 + ## 开发快照(死信精确解除:保留上游行,只按指纹放行) ### Added diff --git a/docs/library-acceptance-matrix.md b/docs/library-acceptance-matrix.md index 557c443..c9aef2c 100644 --- a/docs/library-acceptance-matrix.md +++ b/docs/library-acceptance-matrix.md @@ -1,7 +1,15 @@ # 整库同步验收矩阵(真实证据对照,2026-10-29 重排) 本文件是**唯一口径**:状态只写实际发生的事,四类严格分开,不用"部分通过"含糊过去。 -**2026-10-29 父审后重跑:V03-a(Wiki 撤销语义)不通过,单独列在「一·补」,不在「已完成」表里。** + +**2026-10-29 用户决定(覆盖历史验收口径)**:发布管理**不承担** Wiki 语义撤销—— +它只负责把测试端已确认的整库快照**原样还原**生产。因此撤销后正文里是否残留 +撤销方独有事实,属于**上游知识质量**问题,不在本模块验收范围内:V03-a 保留原始 +失败证据(见「一·补」下方的"模块范围外"表),不改成通过,也不再阻断发布。 +同时**不**新增 LLM 重写、人工逐页复核闸门,也不把升级 WeKnora 作为前置条件。 +保留的门槛是:整库文档/分块/索引/资源/Wiki 正文·来源·链接·目录一致、稳定切点、 +实际维护与排空、准确快照授权、独立预备份与恢复、失败回滚、作业互斥与重启接管、 +真实 UI 进度与存储安全。效果问答/性能/A06 不是门槛。 | 口径 | 含义 | | --- | --- | @@ -49,6 +57,8 @@ A06(内容、问答、引用图片效果、性能报告)已由用户取消 | **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 心跳 | **本轮真跑(候选栈 0.1.187 构建)**:`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` | @@ -59,7 +69,13 @@ A06(内容、问答、引用图片效果、性能报告)已由用户取消 | ID | 要点 | 承载位置 | 本轮真实结果 | | --- | --- | --- | --- | -| **V03-a** | 撤销一份共享贡献后,保留另一份贡献、清除撤销方独有正文/引用/实体边、目录正确 | 由 WeKnora 源侧执行(`cleanupWikiOnKnowledgeDelete` + `EnqueueWikiRetract`),治理侧只比对/搬运 | **本轮不通过(2026-10-29 重跑)**:真实 `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…`)。封存逐字节一致只说明"存了真实状态",不等于撤销语义通过。证据 `kg-final-gaps/evidence/14-wiki-residue-evidence.json` + `01-wiki-source-after-r3.json` | +| **(无)** | 本模块没有"不通过"项:撤销语义已明确移出范围(见上表下方"模块范围外"),不在此改写为通过 | — | — | + +### 模块范围外(用户 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`,不涂改 | ## 二、缺代码 @@ -74,6 +90,8 @@ A06(内容、问答、引用图片效果、性能报告)已由用户取消 | --- | --- | --- | | S03-b | 死信/孤儿任务阻断的负向演练(本轮只验证了真实死信阻断) | 真实阻断已发生并记录;系统化的负向矩阵未跑 | | 排空时序(历史结论) | 旧做法"202 之后抢时序上传"在 1faf513 上重跑 6 次全部 `Broken pipe`(`drain-task-final-1faf513*.json` 保留,不记通过) | 已被 S06-a 的确定性做法取代:先证明请求已被闸门接收,再启动维护。旧证据保留,不覆盖 | +| 封存执行期身份复核(真实封存) | 代码与单测在位(agent 附身份、worker 执行前探测+执行后复核),本轮**没有**在候选栈发起真实封存(会产生新快照与停写入者窗口),因此"换 socket 被挡住"只有单测证据 | +| 按版本恢复的真实执行(新构建) | `restore-availability` 真实返回、恢复投递路径有单测;真实恢复作业仍在旧构建上验过(R01),本轮未重跑,不把旧证据算作新构建证据 | | U05 | 正式 8088 页面验收 | 正式栈仍是 0.1.114,本轮未替换;维护面板/逐页 Wiki 差异只在测试与候选构建里验证过 | ## 四、需授权 / 需环境 @@ -97,9 +115,13 @@ api env `LIBRARY_AGENT_SOCKET=/run/library-agent/agent.sock`,worker 挂载 本轮没有启动任何共享维护,也没有改回该单元——需要用户决定:正式上线前把单元恢复为 WKNFull 版 (备份已在位),或给候选构建单独的 socket 路径。证据 `00-identity-final.json` 的 `formal_stack` 段。 -另外:`knowledge-governance-p1-release-worker-1` 自 2026-10-10 起就在崩溃重启(`exit=1`、 -`RestartCount≈1233`,日志只有 `connect release target database`),与本轮改动无关(它没有挂 agent socket), -但正式栈的发布 worker 实际不可用,需要单独处理。 +另外:`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 +属于正式栈变更,需要部署窗口授权**,本轮没有执行。 ---