36 KiB
36 KiB
用户操作流程与验收清单
按流程逐项验收用。每条给出:入口 → 用户步骤 → 期望 → 验收证据 → 状态。
状态标记:✅ 已实测(附证据)|⏳ 待验收|⚠️ 已知限制。
深度细节见各自专题文档(P3…/P5…/P6…/P8…/PRODUCTION_BACKUP_RECOVERY.md/WIKI_CO_TRANSPORT…)。
统一入口:http://127.0.0.1:8088/(测试栈;右侧面板可直接操作)。角色:管理员 / 文档工程师 / 只读。
A. 内容进入
A1 取件(钉钉知识库 / PP 清单)
- 入口:来源与目录 → 内容来源(勾选条目;钉钉扫码会话失效时先刷新会话——注意:走 dws 取件后钉钉这条不再依赖浏览器会话)
- 步骤:选来源 → 展开目录 → 勾选 → 取件(后台入队)
- 期望:解析监控出现"处理中";失败进死信,可重排
- 证据:
解析监控 → 死信队列;重排轮次键artifact-fetch:<version>:r<n> - 状态:✅(死信重排修复
cddc4c9) - 2026-10-10 端到端实测(界面操作):勾选
App账号注册.adoc→ 标记"对内" → 取件- 首次取件终态失败
artifact_fetch_rejected: credentials(1/8 次即终态)——已定位并修复:artifactfetch的 runner 给子进程的是白名单环境(防凭据外泄),但没透传ARTIFACT_DINGTALK_FETCHER/DWS_BIN/DWS_CONFIG_DIR/DWS_HOME/DWS_DISABLE_KEYCHAIN, dws 找不到配置目录与文件型 keychain → 报"未登录" → 被映射成credentials终态 (且按设计不回落老路径)→ 钉钉取件在真实链路上整体失败。脚本单跑正常,因为绕过了白名单 (提交d29e04e;同时失败时把 stderr 尾部脱敏后带进错误,否则只能看到裸 code) - 重排(重新入队)后:
artifact.fetch1 次完成 → 产物sn-753f….docx4799 B、file认作 Microsoft Word 2007+、zip 12 项;content_objects记validated_format=docx、content_state=verified、sha256=5d8f38d0…✓ - 教训:dws 取件的端到端证据必须在"平台真实调用路径"里取(脚本直接跑会漏掉环境白名单这类差异)
- 首次取件终态失败
- 第二遍(2026-10-10,另一条路由):
技术文档/人形适配大寰电爪相关资料/DH-AG95夹爪适配-指令协议.md(3513 B,drive 直下,不走 adoc/sheet)- 路由回执:"策略已保存 1 份;已记入意图 1 份;排队从源头取件 1 份;列入待入库 1 份"
artifact.fetch一次成功;spoolsn-22da9a36….md3513 B、UTF-8、正文以# DH-AG95夹爪适配-指令协议开头 ✓- 易误判点:
content_objects按 sha256 内容级去重,命中已有行时只更新updated_at/不更新created_at—— 本次复用了 2026-09-14 创建的co-e90af1d6…(sha55fae4b4…、3513 B、md)。核对时必须走source_item_versions.content_object_id → content_objects,不要按created_at过滤列表(我一开始就这么看漏了)
A1 补充:钉钉取件改走 dws(f4e1ecc / 6496ee3 / 9155bd3,2026-10-09)
- 开关:
ARTIFACT_DINGTALK_FETCHER=dws|auto|legacy,线上为 auto(先 dws;仅可重试错误回落老路径)。 - 路由:
adoc→doc export docx;axls→sheet 读取转 xlsx;其余→drive 直下;dlink/hlink→missing;amind/appt→unsupported(详见docs/DINGTALK_DWS_FETCHER.md)。 - 平台侧判定全部保留:后缀路由、PPT 必须 PDF 双胞胎、magic、大小上限、sha256、spool 原子写、空壳检查 → dws 只负责"取字节"。
- 本人复核(2026-10-09,在已部署 worker 内):
- 接线:
dwsv1.0.63(Edition: open)在/usr/local/bin/dws;DWS_HOME=/data/home、DWS_CONFIG_DIR=/data/dws、DWS_DISABLE_KEYCHAIN=1;宿主两份 state 已按文档挂载 ✓ - 鉴权(必须带
HOME=DWS_HOME,直接docker exec dws会误报"未登录"):authenticated:true、refresh_token_valid:true、refresh_expires_at 2026-11-08、账号 姚章浩 / 深圳市越疆科技股份有限公司 ✓ - 真实调用:
dws wiki +space-list --limit 1→ok:true,返回"公司级技术支持知识库" ✓ - 回归测试:
artifact_fetch_test.py18 项、test_dws_error_map.py19 断言全绿 ✓
- 接线:
- 运维依赖(验收时作为背景知识):
- refresh token 30 天轮换:到期前 7 天按 runbook
dws auth login --device续期(本人浏览器授权);出现code=credentials立即停批,不要重试风暴,授权后--retry-failed续跑。 - 在线文档并发建议 ≤4(当前
ingestion_concurrency=2✓ 满足);8 路混合时巨型文档曾现export_failed(已判可重试)。 - 回退开关:
ARTIFACT_DINGTALK_FETCHER=legacy可完全绕过 dws。 - CI:Gitea Run #6/#7/#8 全 success(#8 = 含本清单的
b1b4ca5)✓
- refresh token 30 天轮换:到期前 7 天按 runbook
A2 标注与目录范围(路由到哪个库)
- 入口:来源与目录 → 勾选 → 标记:
对内/对外/不需要(目录级标记决定整目录) - 步骤:标注 → 生成修订
- 期望:标记按 系统设置 → 测试知识库绑定 分发到对应测试库;
不需要不入库 - 证据:
GET /api/v1/source-catalog/routing-capabilities;绑定未配时标记被拒 - 状态:✅ 本期实测(界面勾选 → "对内" → 目录刷新完成;
internal_enabled/external_enabled均 true)
A3 生成修订 / 新版本(发布准备)
- 入口:发布管理 → 生成新版本 →
批准/驳回 - 期望:只有批准后的变更集才能进入密封与批次
- 证据:变更集版本号与审核动作记录
- 状态:✅(见
P5_REVIEW_AND_SEAL_ACCEPTANCE.md) - ⚠️ 顺序约束(2026-10-10 实测踩到):
生成新版本是生成即固化的——它把当时的 "测试是否就绪 / 是否批准"快照写进条目。若在处理完成/审核批准之前生成,则该条目会被 记为not_ready,且此后确认冻结不会重算(冻结沿用生成时的条目), 重生成才是唯一的刷新方式。正确顺序:处理完成 → 批准 → 生成新版本 → 确认冻结 → 建批次。 实测:批准前生成 v2(新增1/阻断195,本条 not_ready)→ 批准后重生成 v3(新增2/阻断194, 本条ready/can_release=t)→ 冻结 → 定批次 ✓
B. 入库与监控
B1 待入库 → 开始处理 → 完成
- 入口:文档工作台(待入库列表)→ 选中 → 开始处理
- 期望:上传 → 解析 → 索引 →
completed;目标库里能看到知识条目与 wiki 页 - 证据:单文档 E2E
tp-3056261d46396a0695497f38421346b3→processing_state=completed;知识cf0af40f-7c0c-4526-ad6a-4515b3b2ca00(4 chunks,wiki 9 页) - 证据(2026-10-10 界面实测):
解析监控 → 待入库(1)→ 开始处理 →tp-c3412382b66f55404d2b51672ffd0549→parse_status=completed、ingest_state=uploaded、poll_sequence=4、last_remote_status=completed; 知识98be235b-68cf-43e1-94ca-419f5b97fddb;任务链test.upload→test.poll×4 →test.validate全 completed ✓ - 证据(2026-10-10 第二遍):
tp-466164a074cb22efb→processing_state=completed(polls=8、remote=completed、 测试库0c84a098…);任务链test.upload → test.poll×8 → test.validate全 completed ✓ - 证据(2026-10-10 第三遍,PDF/MinerU):
tp-4aad3a6663efe94ccc76b96…→processing_state=completed(polls=6、remote=completed); 审核页给出「知识读取:通过;内容处理:通过;搜索验证:需人工确认」✓ → PDF/MinerU 解析链路通 - 状态:✅ 2026-10-08 / 2026-10-10 实测(三份小文档:docx 转换路 + md 直下路 + pdf/MinerU 解析路)
B2 解析监控与补救
- 入口:解析监控 → 处理中 / 需要你出手 / 需下架 / 死信 / 已完成 / 知识库差异 / 知识库解析进度
- 步骤:看"需要你出手" → 重排失败项 / 处理需下架项
- 期望:失败可重排;"需下架"列出仍留在库里的禁止项
- 证据:死信与重排链路(
cddc4c9) - 状态:✅ 链路|⚠️ "重排"按钮行为目前只有单测覆盖(页面当时无失败项可点)
- 2026-10-10 界面实测(第三遍:禁止导入 → 需下架):把已入库的
DH-AG95夹爪适配-指令协议.md改成「禁止导入」 → 回执「策略已保存 1 份、标记禁止 1 份、取件 0、待入库 0」✓,目录表格变为「禁止导入」✓- 发现真问题(已修):
需下架车道恒为 0。车道 SQL 判retrieval_state='enabled',但retrieval_state在这套状态机里描述的是是否发布到生产(unpublished/disabling/disabled/failed),全仓没有任何代码写过'enabled'—— 实测线上 5/5 发布单元都是unpublished,界面上「仍在知识库里的文件会出现在这里」的承诺不成立。 修为与设计注释一致的口径:仍在测试库存活(completed+ 有knowledge_id+ 未disabling/disabled)+ 来源项policy_state='blocked'; 线上库对照:旧判据 0 → 新判据 1,命中正是那支被禁止导入的.md✓;页面随即显示需下架(1)· 对内知识库 · 1 份仍在检索中✓ - 仍未闭环(待排期):① 车道只按库计数,没有条目级列表;② 移除动作(
test.remove工作流,已实现且 worker 已注册) 目前只由变更集删除路径触发,页面没有入口;③ 该工作流是DeleteKnowledge(从测试库删知识条目,重新标注可再入库), 与旧文案"停用检索(可恢复)"的措辞不同 —— 文案已按事实改写(WeKnoraMonitor.tsx/SourceCatalogBrowser.tsx)
- 发现真问题(已修):
C. 发布与回滚
C1 审核 → 密封 → 建批次 → 锁定
- 入口:发布管理 → 创建草稿批次 → 密封 → 锁定
- 期望:密封后批次不可改;锁定后才能授权生产发布
- 证据:批次
rb-9678722c…(1 项);变更集rcs-832f0cf9…v1(196 项:1 可发布 / 195 阻塞) - 证据(2026-10-10 界面实测):
批准→生成新版本(v3rcs-69c1810b…,新增2/阻断194)→确认冻结(state=confirmed、confirmed_by=admin)→ 勾选本条 + 批次名验收-App账号注册-20261010→创建草稿批次→锁定清单→ 批次rb-d6eb1c91ee49ab3aedaa16d3c3c91f85(sealed、1 项、 绑定 v3、review_id=rv-e4b38040…、action=upsert、decided_visibility=internal)✓ - 证据(2026-10-10 第二遍,
.md):批准.md→生成新版本(v4rcs-2b22276e…,新增3/阻断193)→确认冻结→ 批次rb-f1819fb0c4196ae6e22e600874954a0c(验收-DH-AG95指令协议-20261010,sealed、1 项、 仅tp-466164a074cb22efb、绑定 v4)→锁定清单✓;顺序规则再次验证:批准前生成的 v3 里该条仍not_ready, 批准后重生成 v4 才ready/can_release=t✓ - 证据(2026-10-10 第三遍,PDF):v5
rcs-8869e6f0…(新增4/阻断192,含相机线束固定孔位尺寸图.pdfready) → 批次rb-9dfcff203f5fc5e0b4063d3d8b09410b(验收-相机线束孔位图-20261010,sealed、1 项)→锁定清单✓ - 状态:✅ 2026-10-08 / 2026-10-10 实测(三份文档各一次)
C2 授权发布(双闸 + 页面确认语句)
- 入口:发布管理 → 授权发布 → 逐字输入确认语句
publish-to-production→ 确认执行 - 期望:执行
completed+verified;目标库出现该文档;不出现"一键发布" - 证据:执行
rx-dd47920a5b5f5019af4f197fd0c2f92c;目标库0b217e8a…文档数 2069→2070;两个闸门PRODUCTION_RELEASE_REQUESTS_ENABLED/PRODUCTION_BACKUP_RESTORE_VERIFIED均为 true - 状态:✅ 本期实测(页面通道由管理员会话记录操作人;另支持 0600 Bearer 通道)
- 2026-10-10 界面实测(含首个真实跨环境 wiki 发布):授权前留档 2m52s →
guardcheck两库 PASS → 输入publish-to-production→ 确认执行- 首次执行失败:项级
release_verification_failed,worker 日志release wiki replace scope in_scope=0 foreign=8 foreign_ref_stripped=0 untouched=1 skipped_library=1 degraded=true→ 已定位并修复:写入侧(replaceWiki)按设计保留目标库外来源 wiki 页, 而校验侧VerifyWiki仍要求"生产页集合与包内快照完全相等" → 跨来源共库必然误判。 修复:校验改为与写入侧同一套归属口径(共用packageWikiOwners)—— "快照内页必须都存在 + 多出来的页只有在不属于本包时才放行",本包拥有却残留/缺失仍判失败, 撤权仍禁止任何页引用被撤权文档(提交eabe55b) - 重排后完成:执行
rx-63b815604766c750f95c6bba8682a4fe→completed(1/1、failed 0、 项级verified、production_revision=rv-e4b38040…、bundle_sha256=19a85aea…), worker 日志in_scope=1 foreign=8 … degraded=true无失败行 - 页面原文:该执行
发布 已完成 1/1;每项结果App账号注册.adoc → 发布并验证通过 · 目标库 0b217e8a… · 生产可用✓ - 第二遍(2026-10-10,
.md)修复后首次即成功:留档20261010T023538Z-0b217e8a(PG knowledges 3830→3831、wiki_pages 1982→1983,与上一轮发布/回滚后的库状态吻合)→guardcheck两库 PASS → 执行rx-bc714172a3b0c77885ef18a30dd3ac6b→completed首轮通过(1/1、failed 0、项级verified), worker 日志同样in_scope=1 foreign=8 … degraded=true且无失败行 → 页面发布 已完成 · 1/1、每项结果DH-AG95夹爪适配-指令协议.md → 发布并验证通过 · 生产可用✓ - 第三遍(2026-10-10,PDF):留档
20261010T030026Z-0b217e8a(PG knowledges 3831→3832、wiki_pages 1983→1990) →guardcheck两库 PASS → 执行rx-7044688b5b9432c1cb04f8cf251c3679→ 首轮completed(1/1、failed 0、项级verified、production_revision=rv-aac1a725345c7dbf56c03bde1f5d5442); worker 日志in_scope=8 foreign=8 … degraded=true无失败行(这次包内 wiki 8 页,归属门禁在更大页集上同样正确)✓ - ⚠️ 第三遍踩到真问题(已修,见 F.3g):授权发布被回绝
production release requests are disabled—— 因为我用deploy-api-web.sh重建 api 时没叠compose.release-gates.yaml,两道生产门禁被静默关掉; 补上门禁文件重新 up 后重试即成功 ✓(页面当时只在点击处回一句英文错误,很容易误判成功能坏了)
- 首次执行失败:项级
C2b 下架(delete 动作)★2026-10-10 首次实测
- 入口:发布管理 → 发布计划 里对「删除」行勾选 「选择删除…」 → 勾选 「确认删除生产知识」(二次确认框)
→ 填批次名 → 创建草稿批次 → 锁定 → 留档 → 授权发布(同一固定语句
publish-to-production) - 期望:执行项
action=delete、production_revision=absent、state=verified;目标库该知识停用(行保留,可恢复) - 证据(2026-10-10):先把 PDF 重新发布使生产侧"存在"(
rx-80ad81d5…,目标行enable_status=enabled)→ 在来源目录把它改为禁止导入 → 计划给出相机线束固定孔位尺寸图.pdf → action=delete / production_state=present / can_release=true✓ → v8rcs-8702357179…(delete_count=1、113 项)→ 批次rb-8c1ad1c9ba849c7cfe3a5045b53eb880(验收-下架孔位图-20261010、sealed、1 项、action=delete、绑定 v8)→ 留档20261010T033100Z-0b217e8a+ 门禁 PASS → 执行rx-6c19232a4ce1a19f937292a0a60b6c84→completed(1/1、failed 0、项级verified/delete、production_revision=absent);worker 日志in_scope=11 foreign=8 … degraded=true✓ → 独立核对目标库:相机线束固定孔位尺寸图.pdf.pdf行仍在、parse_status=completed、enable_status=disabled✓(下架=停用检索、不删行,可恢复) - ⚠️ 过程中踩到并修掉 Bug #6(见 F.3h):禁止导入只写
source_items.policy_state,而两处"期望策略"解析 (计划 + 建批 delete 就绪判定)都不看它 → 计划不给 delete、建批直接 422
C9 数据源配置:列出来 → 勾选 → 变成来源 ★2026-10-10 面板实测
- ① 来源卡片不再做文件格式筛选(格式由「来源与目录」的目录级标注决定,就近覆盖上级)。
- ②③ 「可加入的来源」按当前钉钉账号列出知识库与钉盘空间:
知识库 18(组织 17 + 我的知识库 1)、钉盘 7(我的文件 + 6 个组织空间);
已登记的三条钉钉来源自动标「已是来源」并禁用勾选。
列不出来时给原因而不是空白:dws 未登录/权限不足 → 503 + 提示;钉盘被拒时只丢钉盘那一栏
(
drive_notice),知识库照常显示;被上限截断时提示"可能不全"。 - ④ 勾选 →
加入为来源(选中 N)→ 走既有登记路径,首次目录扫描自动排队。 实测:勾选「视觉文档」→ 新来源sc-8a4be5b8293d1c9a048c3c7e9b194155(dingtalk、enabled)source.catalog.refresh已完成。扫码会话失效时会直接弹二维码,扫完自动重试本次登记。
- 后端:
GET /api/v1/dingtalk-spaces/available(管理员、只读,dws)。api 与 worker 共用同一份 dws 状态(bind mount 同一份:refresh token 轮换制,不能各留一份)。
C8 一键发布(建批+锁定+授权合成一个动作)★2026-10-10 实测
- 入口:审核行上的
发布到生产(管理员 + 生产门禁开启时显示),或工具栏「发布到生产(选中 N 项)」。 - 证据:点行级按钮 → 确认弹窗输入固定语句 → 提交 → 库内一次得到:
批次
rb-bee80550b6fae758a4b1076db1c6bc36(立即发布 · 2026/10/10、sealed、1 项、绑定冻结版本)- 执行
rx-3d831129e01322a8dfcf08b09cd4adbe(publish、completed、项级verified、production_revision=rv-934f2a64…) → 随后在页面上回滚:rx-43835fac7d218c008933f1cb93c75b2b→rolled_back、项级production_revision=absent(回滚状态由适配层读回校验verify restored后才置位)。
- 执行
- 与之前对照:同一条文档从"已批准"到"发出",此前需 找条目→勾选→填名→建批→滚到清单→找批次→授权→输语句→提交(~9 次交互); 现在 3 次(点发布 → 输固定语句 → 提交)。
- 约束未放松(服务端测试固化):请求门禁关闭 → 403;备份恢复验证未过 → 412;非管理员 → 401;错语句/空选择 → 400; 建批失败(门禁不通过)→ 422;密封后不满足生产门禁 → 409。
C7 批量审核 + 建批即锁定 ★2026-10-10 实测(发布管理减负 P0-3)
- 界面:审核区块新增「全选可批准(N)」「批量批准选中(N)」「批量驳回选中(N)」;建批按钮改为「创建并锁定清单」。
- 证据(建批即锁定):勾选 2 条已批准 → 填名 → 一次点击 → 批次
rb-95210ddcc14bbcb6afee323acd87b945(验收-批量两项-20261010)出来就是sealed(2 项、sealed_by=admin),没有单独的"锁定"这一步; 且复用同一份冻结版本rcs-028ac704…(计划摘要未变 → 同版本复用)。 - 判据修正:界面「可批准」原先把已驳回的也算进去(
review_state !== 'approved'),已改为只含pending+ 门禁通过—— 已驳回的不会被"全选"顺手翻回批准。 - 语义边界(集成测试固化):批量批准按人工身份写入,人工可推翻自己先前的驳回;
system:auto发起的批量批准对人工驳回过的那条必须跳过(Decided=0 / Skipped=1)。
C6 建批时冻结 + 自动批准 ★2026-10-10 实测(发布管理减负 P0-1 / P0-2)
- 期望:不再有
生成新版本/确认冻结两步;对内知识验收通过后由系统自动批准;建批即绑定一份已确认版本。 - 证据(P0-2,界面 + 库):界面里给
ATOM-备忘录笔记.adoc标「对内」→ 待入库 →开始处理; 处理完成(completed/unpublished,验收chunks_present=passed、knowledge_exists=passed、retrieval_hit=manual_required) → 审核记录rv-934f2a64…/approved/reviewer_ref=system:auto/approved_for_release(未点任何人工批准) - 证据(P0-1,界面 + 库):勾选该条 → 填名 →
创建草稿批次(一次点击,无任何冻结步骤) → 批次rb-a1c0012153e476f9a37e9c6d5f97cbe4(draft)自动绑定rcs-028ac7045f9d2e533b28402b391accdf(confirmed、112 项、绑定时刻确认)→ 清单内含ATOM-备忘录笔记.adoc / add / can_release=true - 对照:同一场景(批准晚于上一次冻结)在今天上午必然 422
release change set must be confirmed and cover every requested publication - 单文档交互次数:今天上午 ~9–11 次(含两次踩顺序陷阱)→ 现在 ~4–5 次(勾选、填名、建批、锁定、授权)
C5 测试库侧移除(解析监控 → 需下架 → 逐条下架)★2026-10-10 首次实测
- 入口:解析监控 → 需下架 车道逐条列出「来源侧被判禁止导入、但知识仍存活在测试库里」的条目
(
GET /api/v1/test-publications?removal=required,口径与车道计数同源)→ 每条 下架(从测试库移除) → 页内二次确认(取消在左、确认在右)→ 走既有test.remove工作流(删除测试库知识并读回校验) - 期望:条目置
disabling→ 工作流完成后disabled;车道计数递减;生产知识库不受影响 - 证据(2026-10-10,两条都经界面走完):
- 点击前车道
需下架(2):相机线束固定孔位尺寸图.pdf、DH-AG95夹爪适配-指令协议.md(与直接查库的候选一致) - 第 1 条(PDF):点下架 → 车道回到 1 →
test_publications.retrieval_state=disabled(03:57:03Z);jobstest.remove/completed/ attempt 2(第 1 次test_remove_pending=远端仍在处理,重试通过); 工作流以GetKnowledge读回 404 判成功 - 第 2 条(md):点下架 → 确认态出现但未执行(核库:仍
unpublished、移除任务数仍 1)→ 点确认 →disabling→disabled(04:08:55Z);jobjob-67e7e62c…completed(attempt 2) - 界面终态:
需下架(0)+ 空态文案;页面提示「已受理下架…」
- 点击前车道
- ⚠️ 过程中踩到并修掉 Bug #7(二次确认按钮出现在原按钮位置,连点即误执行;已把「取消」放左)
与 Bug #8(
jobs部分唯一索引 + 空串 business_* → 第二次移除被静默吞掉、条目永久卡死;已改 NULL + 落行校验)
C3 查看结果 → 回滚
- 入口:发布管理 → 查看结果 → 需要时 回滚 → 确认语句
rollback-production-release - 期望:回滚后目标库该知识停用(不删知识行),wiki 页保持
- 证据:
rx-f1d1d669…→rolled_back,authorized_by=admin,prior_execution_id=rx-dd47920a…;目标库该知识enable_status=disabled、chunks 4/0 enabled、wiki 9 页完整 - 证据(2026-10-10 界面实测):输入
rollback-production-release→ 执行rx-71d13453f5c684a7fa6f9c8337610d78→rolled_back(1/1、failed 0、项级rolled_back);页面回滚 已回滚、每项结果App账号注册.adoc → 已恢复上一版本 · 目标库 0b217e8a… · 已恢复; 独立核对目标库:knowledges行仍在、parse_status=completed、enable_status=disabled✓(首发布回滚=停用,不删行) - 证据(2026-10-10 第二遍,
.md):回滚+rollback-production-release→ 执行rolled_back(1/1、failed 0、项级rolled_back); 独立核对目标库:行仍在(titleDH-AG95夹爪适配-指令协议.md.md)、parse_status=completed、enable_status=disabled✓ - 证据(2026-10-10 第三遍,PDF):执行
rx-21be23f095075701aba8a62d58f3dd7b→rolled_back(1/1、failed 0); 独立核对目标库:相机线束固定孔位尺寸图.pdf.pdf行仍在、parse_status=completed、enable_status=disabled✓ - 状态:✅ 2026-10-08 / 2026-10-10 实测(三份文档各一次发布+回滚,目标库均为"停用不删行")
C4 重排失败执行
- 入口:发布管理 → 失败执行 → 重排 → 确认语句
retry-production-release - 期望:只重置失败项;
verified/rolled_back项保持完成;重排不改写AuthorizedBy(历史不可篡改) - 证据:
internal/httpapi/production_action_test.go双通道用例 - 状态:✅ 单测覆盖 + 2026-10-10 真实失败项实测(上面 C2 的失败执行即用
重排+ 固定语句retry-production-release重跑成功;同一条执行号rx-63b81560…由failed转为completed,authorized_by=admin未被改写)
D. 系统设置
D1 服务配置(测试 / 生产端点与 ID)
- 入口:系统设置 → 服务配置(管理员)
- 规则:只配四项(测试地址、生产地址、生产 ID、知识库 ID);保存时真探测,无效才拒;凭据只写不读
- 状态:✅(见
P41/P42与ui_settings_*测试)
D2 测试知识库绑定(对内 / 对外)
- 入口:系统设置 → 测试知识库绑定 → 选库 → 保存绑定
- 期望:保存立即生效并重排"还没上传"的待入库项;对内 ≠ 对外
- 状态:✅ 本期实测
D3 生产知识库绑定(源库 → 目标库)
- 入口:系统设置 → 生产知识库绑定 → 对内/对外各选一个生产库
- 期望:发布写入被冻结到该项的
target_knowledge_base_id;未绑定时按同 ID 语义并在契约检查处失败关闭 - 状态:✅(
P8_PRODUCTION_KB_MAPPING_ACCEPTANCE.md;迁移 000044)
D4 存储与备份(整库逻辑备份的定时)★本期新增
- 入口:系统设置 → 存储与备份(管理员)
- 步骤:设置 定时时间 + 储存天数(+ 每月归档保留、启用开关)→ 保存并下发到主机;另可 重新下发当前设置 / 立即备份一次
- 期望:保存即写库并下发到目标主机 cron;页面显示主机上实际生效的计划、cron 条目、最近一次备份与"已一致/待下发"
- 证据(面板原文):
目标主机 weknora-test · 已连接、主机 cron 服务 active、主机 cron 条目:30 03 * * * root /bin/bash /opt/weknora-test/logical-backup.sh >> …、主机上生效的计划 每天 03:30 · 保留 7 天 · 每月 3 份、与设置是否一致 已一致、最近一次备份 20261009T060736Z / 34 秒 · 742.7 MiB / 覆盖 8 库 / 失败 无 - 实测改动往返:面板改
04:05 / 14 天→ 主机/etc/cron.d/kb-logical-backup变05 04 * * *、参数文件TIME=04:05 / KEEP_DAYS=14✓ → 再改回03:30 / 7 天→ 主机30 03 * * *✓ - 立即备份:按钮变"备份进行中…"→ 约 50 秒后自动刷出新结果(异步 202 + 在途单飞,重复点击不会跑两次)
- 状态:✅ 2026-10-09 面板实测(写操作仅管理员:
PUT/POST /api/v1/backup-schedule*)
D5 刷新策略
- 入口:系统设置 → 刷新策略(文档工程师可改)
- 期望:文档/资源刷新间隔、停滞判定、finalizing 时长;保存先验证再原子启用、旧版本留审计
- 状态:✅(
ui_settings版本化激活测试)
D6 成员与角色
- 入口:系统设置 → 成员与角色(管理员)
- 期望:成员增删、角色(viewer/engineer/admin);管理员初始密码首登强改
- 状态:✅(
users接口与角色网关)
E. 备份与恢复(运维流程)
E1 发布/导入前留档(PG 行 + ES 文档)
- 入口:命令行
bash scripts/target_kb_snapshot.sh(默认云内执行) - 期望:
$KB_BACKUP_ROOT/target-kb-snapshots/<UTC>-<kb8>/出现 8 张表 JSONL +es_documents.jsonl.gz+MANIFEST.json(sha256/每库 ES 计数) +export.sql+README.md - 证据:实测 2 分 52 秒(PG 8 表 44 秒;两库 ES 131,122 条 / 692 MB);
PULL_ES=1拉回本机 19 分 40 秒 - 状态:✅ 2026-10-09 实测
E2 发布前硬门禁
- 期望:写目标库之前必须存在覆盖该库、24h 内、PG 与 ES 两层齐备且哈希可校验的留档;否则
release_target_snapshot_missing(不可重试),目标库一行不碰 - 证据:
go run ./cmd/guardcheck backups/target-kb-snapshots <kb_id>→ 两个绑定库PASS、未绑定库BLOCK;门禁单测 10 条 - 状态:✅ 已上线(release-worker 已带此门禁)
E3 回填演练(证明"存了能回去")
- 入口:
python3 scripts/restore_drill.py --snapshot-dir <留档> --target-url <本地测试库> - 期望:行数与清单逐一致、抽样页面正文/标题逐字段相同、清理后残留 0
- 证据:13,539 行全部回填成功;8 张表与清单逐一致、冲突 0、抽样页 388 字符一致、残留 0(实测值)
- 状态:✅ 2026-10-09 实测
E4 整库逻辑备份(自管,落自己盘上)
- 入口:主机
bash /opt/weknora-test/logical-backup.sh(手动)或按 D4 的定时 - 期望:
$KB_BACKUP_ROOT/rds-logical/<UTC>/<库>.dir(pg_dump -Fd -j4 -Z6)+MANIFEST.json(含failed_databases);按天轮转 - 证据:33 秒 / 742.6 MiB / 214 文件 / 失败 0,覆盖 8 个库;RDS 管理库
rdsadmin自动跳过;中断的运行改名*.incomplete - 状态:✅ 2026-10-09 实测
E5 其余三层(现状)
- ES 快照:仓库
kb_backup(宿主$KB_BACKUP_ROOT/es-snapshots)+ SLMkb-hourly(3 天)/kb-daily(7 天);首个快照 36 秒 / 4.7 GB / 0 分片失败 ✅ - OSS 版本控制:桶
dobot-weknora-test已开启(覆盖/删除可按 VersionId 回滚)✅ - RDS 托管备份:由控制在控制台自管(按你的决定:本期不做,不阻塞)⏳
- 备份目录契约:
scripts/backup_layout.sh定义/srv/kb-backups/{target-kb-snapshots,rds-logical,es-snapshots,logs},换主机(未来的生产云主机)跑同一份 ✅
F. 本期已知限制与边界(验收时不必当缺陷)
- ES 留档字节默认留目标主机(
PULL_ES=0);异地副本不做(你的决定)。 - ES 快照仓与留档同机同盘:整机故障需靠 RDS 托管备份 + OSS 还原。
- wiki 通道的真实跨环境发布已跑通(2026-10-10,见 C2):发现并修复"写入保留外来源页、校验却要求集合相等"的口径冲突(
eabe55b);降级保留(degraded=true)现在是发布常态路径。 3b. 指标条的健康探测有误报:解析监控顶部把 Embedding 模型 / LLM 模型 / OSS / Redis-MQ / WeKnora API 显示为"阻断",但本期入库与发布全链路(上传/解析/索引/发布/回滚)都实际成功 → 探测口径待校正(不作阻塞项)。 3c.系统设置 → 服务配置的"测试端"探测报 404:test_weknora_base_url为空时 api 用TEST_WEKNORA_BASE_URL=http://app:8080探测,而app在治理栈网络内不可解析 → 显示"可达·不可接单";worker 走的是可用路径(本清单 B1/C2 均成功),仅探测口径问题。 3h. 「禁止导入」未进入发布计划的期望策略 → 生产知识下不了架(已修):禁止导入写的是source_items.policy_state='blocked',但"期望策略/desired_policy"的解析只看source_item_scope_overrides/directory_scope_rules/source_items.visibility,两处都不看 policy_state: ① 发布计划(release_plan.go)把被禁止且生产侧已存在的条目算成unchanged/present、can_release=false→ 永远不给 delete; ② 建批的 delete 就绪判定(release_batches.go的releaseDeleteReadyCTEs)同样口径 → 即使计划给了 delete,创建封批仍被拒 422 (实测原文:"创建封批失败(HTTP 422)")。修复=两处都把policy_state='blocked'算进期望策略(同一口径,各一行); 新增集成测试用 policy_state(真实路由的写法)复现,并同时断言"计划出 delete"与"delete 批次可创建", 回退任一处修复该测试即 FAIL ✓。附带效果:从未导入却被标为禁止的 82 条"等待测试"噪音不再占发布计划(195 → 113 项)。 注意:现有 release_authorization 集成测试用source_item_scope_overrides造 blocked(计划能识别), 所以一直没暴露这个"测试与现实写法不一致"的偏差。 3g.deploy-api-web.sh会静默关掉生产门禁(已修):脚本的COMPOSE_FILES默认只叠compose.yaml, 重建 api 时若不叠compose.release-gates.yaml,PRODUCTION_RELEASE_REQUESTS_ENABLED/PRODUCTION_BACKUP_RESTORE_VERIFIED变 false,生产授权接口静默关闭,页面只在点「授权发布」时回一句production release requests are disabled。 修复:脚本加前置保护 —— 正在运行的 api 已开闸而本次未叠门禁文件时直接拒绝 (REFUSED_WOULD_CLOSE_PRODUCTION_GATES,并打印保留门禁的正确命令;确要关闸显式ALLOW_GATE_OFF=1), 结尾新增=== 7b回显重建后的两道门禁状态。三种情形已按同一段判定逻辑验证 ✓ 3f. 集成测试曾改到线上设置(已修 + 已恢复数据):internal/httpapi/ui_settings_integration_test.go只判断TEST_DATABASE_URL是否存在、没有 schema 隔离,而它就做「创建候选并激活」——直接跑在共享/线上库上时, 会把真实的 active 设置挤成 retired。2026-10-10 排查车道问题时踩到:线上 active 变成测试负载 (30/60/3600/14400 +https://weknora.prod.example:8443/weknora),真实的uis-d40ea1fc…(15/30/1800/7200 + 生产端点https://weknora-test.dobot.cn/)被 retired。 处理:先备份backups/ui-settings/ui_setting_revisions.pre-restore.*.jsonl,再用单事务(先 retire 再 activate, 唯一约束uq_ui_setting_active只允许一条 active)恢复,两条 update 各影响 1 行,并复核线上值 ✓; 根因修复=给该用例加 per-test schema 隔离(照internal/monitoring),复跑后线上设置不再被改动 ✓。 规矩:任何"创建并激活"的集成测试必须建独立 schema;只判TEST_DATABASE_URL存在就写共享库的用例一律视为危险。 3i.测试库侧的移除仍无页面入口已闭环(2026-10-10):解析监控 → 需下架 现在逐条列出条目, 每条可「下架(从测试库移除)」并二次确认(POST /api/v1/test-publications/{id}/removal,engineer 权限、 写路由需Idempotency-Key、按条目幂等);实测两条走通(见 C5)。 3e. 发布/回滚结果页不自动刷新:Release Worker 完成后,发布管理的执行行仍显示"待执行"(首次与第二遍都遇到), 需手动刷新当前页面/reload 才看到已完成/已回滚。后端状态是对的(DB 已是终态),属展示层轮询缺口。 3d.release_executions.snapshot_verification_id为空:发布前快照门禁确实生效(缺少/过期会release_target_snapshot_missing),但执行行没有记下"用的是哪份快照",追踪性待补。 - "重排"在页面上无真实失败项可点(单测覆盖);指标条"失败 1"是旧
artifact.fetch死信遗留。 - 自管逻辑备份不能替代 PITR(RDS 控制台那条本期不做)。
验收建议顺序
- D4 存储与备份(本期新增,步骤最短、证据最全)→ 2. E1/E2/E3/E4(留档→门禁→回填→整库)→ 3. C2/C3(授权发布 → 回滚,需闸门开启)→ 4. B1/B2(入库与补救)→ 5. A1–A3、D1–D3、D5、D6(既有流程,按各自专题文档逐条核)。