Merge the regulations knowledge base initiative
Why: Deliver the regulations knowledge base plan U1-U9 and pin the composition in Dev.
Evidence: CI success on f5b5568 (test, test-pg, svc-realcombo); component main CI recorded on the archived task card.
Impact: Specs, four gitlinks (backend 56a7f9f, documents 5bb4877, frontend 50ec836, ui 5c2b103) and the opt-in make test-regulations-kb gate.
Refs: https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/614
This commit was merged in pull request #614.
This commit is contained in:
@@ -0,0 +1,481 @@
|
||||
# feature/regulations-kb 任务卡
|
||||
|
||||
任务主记录:PR #614 https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/614;状态:已完成(合入前闭合);owner:weichen
|
||||
|
||||
## 基线与授权
|
||||
|
||||
- 权威仓:ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-System-Dev.git;目标分支:main;R0(initial_base_sha)= b5e23daed2f0ea46261979de1d62e4de0cfa88f9
|
||||
- 工作区:/home/weichen/projects/Agent-System-Dev-wt-feature-regulations-kb(worktree);分支:feature/regulations-kb
|
||||
- 分支类型:initiative;initiative_id:feature-regulations-kb;root_target:main;immediate_target:main;accepting_requirements:false
|
||||
- 需求分流:verdict=NEW;selected_initiative=无;requirement_sha256=fa6ff4c75a01064e0aa767dc91455b8e5bcd0f5f29f59958962543c633bf2ba2;triage_receipt=/tmp/regkb-triage-20261018.json;receipt_sha256=907151e982da280292647462e8342fbbd1453a87565c887ef4cb2269f29eae03
|
||||
|
||||
- 授权与交付终点:用户 2026-10-18 指示“按照方案一步一步实现所有内容,并在完成后进行清理”(/goal)。授权范围 = 计划 U1–U9 的实施、验证、Review、各仓 PR 合入与安全收口,含新建 `Agent-System-KB-Regulations` 仓。未授权:生产部署、生产全量语料导入、发布受保护标准原文、法律适用性裁定、新增外部付费调用(真实搜索/MinerU 实网调用前须用户确认提供方与凭据)、高后果双钥匙操作。
|
||||
- 交付模式:goal-first(目标、范围和交付终点一次确认;范围内连续推进)
|
||||
- 实施执行:agent-per-unit(配置:AGENT-EXECUTION.md)
|
||||
- 合入执行:agent(已授权交付范围内,Review 通过、冲突解决且当前 HEAD 的 CI 通过后合入)
|
||||
- 人工决策点:仅限目标/范围/验收变更、重大取舍、高后果操作或无法自动判定的业务验收
|
||||
- 当前阶段:合入核验与收口;当前增量:U1–U9 全部合入组件仓,Dev 承载 U1/U7 规格与 U8 组合
|
||||
- 流程依据:仓库根目录 policy/delivery.md(归档后仍按仓库根目录定位)
|
||||
|
||||
## 目标与非目标
|
||||
|
||||
- 用途与目标:建设可追溯的医疗器械法规知识库,RDM 以“受控语料库 + 真实网络搜索”双源核验法规结论,引用定位到版本、条款与原文片段,审计可重放且可检测篡改。
|
||||
- 方案/计划:[docs/superpowers/plans/2026-10-18-regulations-knowledge-base-plan.md](../docs/superpowers/plans/2026-10-18-regulations-knowledge-base-plan.md)(单一正文,本卡不复制)。
|
||||
- 接纳范围:计划 U1–U9;非目标见计划 Scope Boundaries(分布式向量库、自动法律适用裁定、持续法规监测、生产部署与全量导入)。
|
||||
- 仓库分工:`Agent-System-KB-Regulations`(语料/解析/切片/检索/搜索与抓取证据);Backend(U9 公开扩展契约);RDM(U6/U7 编排、授权、引用、审计);Dev(本卡、U1 盘点规格、U8 组合)。组件仓按各自 AGENTS.md 与 AGENT-EXECUTION.md 交付。
|
||||
- U1 产物位置调整:计划写 `docs/proposals/regulations-kb/corpus-inventory.md`;Dev 无该目录,U1 为只读调查,产物落在 host 豁免路径 `docs/superpowers/specs/2026-10-18-regulations-corpus-inventory.md`,U2 再带入新仓。
|
||||
- 分级测试策略:组件仓单元/集成测试 + 各仓 CI(GATE);U8 组合验证在 Dev 最终窗口运行完整 CI。
|
||||
- 验收条件:计划 Definition of Done;外部凭据缺失项(MinerU、搜索提供方实网)如实标 NOT_RUN 并给出补齐动作。
|
||||
- 追加领域规则:语料原件、dump、索引与秘密不入 Git;法规原文按来源权利限制展示。
|
||||
- 用户决策(2026-10-18,AskQuestion):① 授权 host 用 `~/.secrets/gitea` HOME 段 token 为新仓设置 Actions 机密 `SUBMODULE_TOKEN`(已设置,值未回显);② 搜索提供方先实现可插拔适配器(含智谱 web_search 实现)与模拟测试,实网联调 NOT_RUN,待用户确认后再跑;③ U3 用已有 MinerU 输出离线导入,同时实现 MinerU API 适配器(模拟测试),实网调用 NOT_RUN。
|
||||
- 新仓:`weichen/Agent-System-KB-Regulations`(private,2026-10-18 经 API 创建);空根提交与 `dm governance init` 原样骨架由 host 绕过钩子提交(执行器尚不在 HEAD),其余经 agent-exec。分支保护待用户设置。
|
||||
- 生命周期:U1–U9 合入或显式延期后置 `accepting_requirements=false`,`FINAL=1` 收口。
|
||||
|
||||
## 子任务登记
|
||||
|
||||
| 子任务分支 | 必需 | 状态 | PR |
|
||||
|---|---|---|---|
|
||||
| 无(各单元在组件仓独立分支交付,见「跨仓交付登记」) | 否 | — | — |
|
||||
|
||||
## Agent 实施收据
|
||||
|
||||
路由与 fail-stop 规则见根目录 AGENT-EXECUTION.md 与 policy/delivery.md;每次尝试一行,原始日志留在源码外收据路径。
|
||||
|
||||
| 单元 ID | 预期范围 | 配置摘要 | 角色 | 候选顺序 | attempt | CLI/模型 | 终态 | transport | fallback | 源码外收据路径 |
|
||||
|---|---|---|---|---|---|---|---|---|---|---|
|
||||
| dev-u8-regulations-composition | modules/{backend,documents,frontend,ui}、tests/integration/regulations-kb、tests/test_regulations_kb_pin.py、Makefile、PROJECT.md | caefcb72b970 | implementation | cursor→agy→pi | 1 | cursor(fresh_session,session not-observable) | success | 05a60f7 | never | /tmp/regkb-u8dev-receipt.json(收口后清理) |
|
||||
| dev-u8-regulations-scan-default | run.sh、README、pin 测试(扫描默认目录去掉服务端 bin/) | caefcb72b970 | implementation | cursor→agy→pi | 1 | cursor(fresh_session) | success | 4764cb4 | never | /tmp/regkb-u8dev-fix-receipt.json(收口后清理) |
|
||||
| dev-u8-merge-prep-frontend-pin | modules/frontend 还原到分支基线 92864db 以干净合并 main #617 | caefcb72b970 | implementation | cursor→agy→pi | 1 | cursor(fresh_session) | success | c1181d4 | never | /tmp/regkb-u8dev-prep-receipt.json(收口后清理) |
|
||||
| dev-u8-readd-frontend-pin | modules/frontend → 50ec836(426d104 后代) | caefcb72b970 | implementation | cursor→agy→pi | 1 | cursor(fresh_session) | success | 9dd9f1a | never | /tmp/regkb-u8dev-readd-receipt.json(收口后清理) |
|
||||
| 组件仓单元 | U2–U7、提供方、组合与 KB/RDM U8 | 各仓 AGENT-EXECUTION.md | implementation | cursor→agy→pi | 各 1 | cursor | success | 见各仓 PR 与任务卡 | never | 各仓任务卡 |
|
||||
|
||||
## 关联方向与规划
|
||||
|
||||
- 适用状态:适用
|
||||
- 主记录路径/版本:docs/superpowers/plans/2026-10-18-regulations-knowledge-base-plan.md(本 PR 合入版本)
|
||||
- 对应里程碑:法规知识库 U1–U9
|
||||
|
||||
## 需求分析
|
||||
|
||||
| ID | 描述 | 项目符合度及依据 | 优先级 | 验收条件 | 依赖 | 结论 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| R1 | 受控法规语料:来源/许可盘点、解析切片、检索与版本发布(U1–U5) | 符合计划,KB 仓独立 | P0 | 计划 U1–U5 测试场景 | — | 已交付 |
|
||||
| R2 | RDM 双源核验:缺任一通道报降级,不得显示已核验;审计批次防篡改(U6) | 符合 | P0 | U6 场景 | R1、R5 | 已交付 |
|
||||
| R3 | 结构化引用:对话/文档/审计中定位到版本、条款与片段(U7) | 符合 | P0 | 引用合同 + U7 场景 | R2 | 已交付 |
|
||||
| R4 | 组合、恢复、隐私与发布就绪(U8) | 符合 | P0 | 组合门禁 PASS | R1–R3 | 已交付(部署/发布另行门禁) |
|
||||
| R5 | EXT-20 公开扩展契约与提供方(U9) | 符合 | P0 | Backend/Documents 合入 | — | 已交付 |
|
||||
|
||||
## 方案与计划
|
||||
|
||||
- 方案引用:`docs/superpowers/plans/2026-10-18-regulations-knowledge-base-plan.md`(本分支 f61737b)
|
||||
- 实施计划引用:同上 U1–U9;U1 产出 `docs/superpowers/specs/2026-10-18-regulations-corpus-inventory.md`
|
||||
- 测试计划引用:同上 Verification Contract;各组件仓 CI 为 GATE
|
||||
|
||||
### 跨仓交付登记
|
||||
|
||||
| 单元 | 仓库/分支 | PR | 状态 |
|
||||
|---|---|---|---|
|
||||
| U1 | Dev `feature/regulations-kb`(规格文档) | [Dev #614](https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/614) | 已提交,随本 PR 合入 |
|
||||
| U2 | KB-Regulations `feature/u2-foundation` | [KB #1](https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-KB-Regulations/pulls/1) | 已合入 7e962de |
|
||||
| U3 | KB-Regulations `feature/u3-parse-chunk` | [KB #2](https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-KB-Regulations/pulls/2) | 已合入 2f92a9f |
|
||||
| U5 | KB-Regulations `feature/u5-web-evidence` | [KB #3](https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-KB-Regulations/pulls/3) | 已合入 d208f40 |
|
||||
| U9 | Backend `feature/regulations-kb-ext20` | [Backend #212](https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Backend/pulls/212) | 已合入 56a7f9f |
|
||||
| U9 | Documents `feature/regulations-kb-ext20-proposal` | [Documents #113](https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Documents/pulls/113) | 已合入 5bb4877 |
|
||||
| U4 | KB-Regulations `feature/u4-retrieval` | [KB #4](https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-KB-Regulations/pulls/4) | 已合入 6c3fbbe |
|
||||
| U6 | RDM `feature/regulations-kb-dual-source` | [RDM #434](https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-RDM/pulls/434) | 已合入 703e41d(Backend pin 56a7f9f) |
|
||||
| EXT-20 提供方 | KB-Regulations `feature/kbreg-provider` | [KB #5](https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-KB-Regulations/pulls/5) | 已合入 d6d7056 |
|
||||
| U7 前端 | Frontend `feature/regulations-kb-citations` | [Frontend #109](https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Frontend/pulls/109) | 已合入 2d65a81 |
|
||||
| U7 契约 | Dev `docs/superpowers/specs/2026-10-18-regulations-citation-contract.md` | [Dev #614](https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/614) | 已提交 06dd79c |
|
||||
| U7 RDM | RDM `feature/regulations-kb-citations` | [RDM #437](https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-RDM/pulls/437) | 已合入 3cc91de |
|
||||
| 组合注册 + RDM U8 测试 | RDM `feature/regulations-kb-composition`(KB gitlink、kbreg 插件、组合测试) | [RDM #438](https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-RDM/pulls/438) | 已合入 ece91da |
|
||||
| U8 KB 运维与恢复测试 | KB-Regulations `feature/u8-operations` | [KB #6](https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-KB-Regulations/pulls/6) | 已合入 5dddad2 |
|
||||
| U7 前端卡状态修正 | Frontend `fix/close-regulations-kb-citations-card` | [Frontend #110](https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Frontend/pulls/110) | 已合入 50ec836 |
|
||||
| U8 Dev 组合 | Dev `feature/regulations-kb`(四个 gitlink + `make test-regulations-kb`) | [Dev #614](https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/614) | 随本 PR 合入 |
|
||||
|
||||
## 阶段记录
|
||||
|
||||
| 阶段 | 对象版本 | 状态 | 决策/执行者 | 时间 | 依据 |
|
||||
|---|---|---|---|---|---|
|
||||
| 需求拆解 | 计划 f61737b | 完成 | 用户 /goal + host | 2026-10-18 | 计划 U1–U9 |
|
||||
| 需求评估 | 计划 f61737b | 完成 | host | 2026-10-18 | 需求表 R1–R5 |
|
||||
| 需求表确认 | 计划 f61737b | 完成 | 用户(/goal 一次确认 + AskQuestion 三项决策) | 2026-10-18 | 基线与授权 |
|
||||
| 方案设计 | 计划 + 引用合同 06dd79c | 完成 | host | 2026-10-18 | docs/superpowers |
|
||||
| 实施计划 | 计划 U1–U9 | 完成 | host | 2026-10-18 | 跨仓交付登记 |
|
||||
| 实施与自检 | 各仓 PR head | 完成 | cursor worker(新进程/隔离工作区) | 2026-10-18 | Agent 实施收据 |
|
||||
| 正式测试与验收 | Dev 4764cb4 + RDM ece91da + KB 5dddad2 | 完成(SELF 本地;GATE 见各仓 CI) | host | 2026-10-18 | 证据表 |
|
||||
| 代码 Review | 各单元 diff | 完成 | host 主模型(未复用实施会话) | 2026-10-18 | 合入与清理 |
|
||||
| 合入 | Dev #614 | 进行中 | host | 2026-10-18 | 当前 HEAD CI 通过后合入 |
|
||||
| 合入核验与收口 | — | 待执行 | host | — | 清理记录 |
|
||||
|
||||
## 探索试验与迭代
|
||||
|
||||
| 增量/试验 | 假设 | 范围 | 判断和停止条件 | 授权/决策依据 | 结果 | 变更影响 | 需重审补测 |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| 无 | — | — | — | — | — | — | — |
|
||||
|
||||
## 同步记录
|
||||
|
||||
| 节点 | sync_base_sha | tested_head_sha | checked_at |
|
||||
|---|---|---|---|
|
||||
| 启动 | b5e23daed2f0ea46261979de1d62e4de0cfa88f9 | b5e23daed2f0ea46261979de1d62e4de0cfa88f9 | 2026-10-18T09:17:44Z |
|
||||
|
||||
## 证据(Evidence)
|
||||
|
||||
<!-- CMD="<命令>" make evidence 写入;手抄/转写输出视为无效证据(AGENTS.md 证据与验证门禁)。 -->
|
||||
| 时间(UTC) | 命令 | 被测HEAD | exit | 来源 | sha256(16) |
|
||||
|---|---|---|---|---|---|
|
||||
|
||||
## 交付调度
|
||||
|
||||
- 调度状态:未入队;调度记录:无
|
||||
- entry_id:无;attempt_id:无;窗口执行者:无
|
||||
- 固定候选:无(base/head、组件与相关配置引用实际尝试)
|
||||
- 调度依据:policy/delivery.md#合入调度
|
||||
- 固定后证据:源码外 RECEIPT;实际结果后按授权原样导入和闭合
|
||||
|
||||
## 结果与验证
|
||||
|
||||
- 结果:U1 盘点规格与 U7 引用合同(本 PR);KB-Regulations #1–#6(基础契约、解析切片/MinerU 适配、网络搜索与 SSRF 安全抓取、检索/发布门禁、EXT-20 提供方、运维与恢复测试);Backend #212、Documents #113(EXT-20);RDM #434(双源核验与封印审计批次)、#437(结构化引用)、#438(kbreg 组合与组合测试);Frontend #109/#110(引用渲染);本 PR 固定 backend 56a7f9f、documents 5bb4877、frontend 50ec836、ui 5c2b103,并新增 `make test-regulations-kb`(固定 RDM ece91da、KB 5dddad2)。
|
||||
- 验证:GATE——KB main 5dddad2(test、test-pg、governance)、d6d7056;RDM main 3cc91de、ece91da(build-and-test 首跑因既有不稳定测试 TestSlowLedgerPersistsLifecycle 失败,重跑 job 6149 通过;governance);Frontend 2d65a81、50ec836(governance);Dev 本 PR 当前 HEAD CI 见合入记录。SELF——Dev `make test` exit 0(umask 022;此前两次失败分别因嵌套子模块未物化与本机 umask 077 使 Backend TestDSNFileMode 误报,均已如实记录);`make test-regulations-kb` PASS(一次性 pgvector pg16,三阶段 kb-test-pg / rdm-kbreg 12 个目标测试 / 客户端制品凭据扫描)。NOT_RUN——真实智谱搜索、MinerU 实网调用与真实嵌入(待用户确认提供方与凭据)。
|
||||
- 影响与剩余项:新仓 Agent-System-KB-Regulations 分支保护待用户设置;RDM 需求文档同步为非阻塞后续;部署、版本发布、生产语料导入与业务/法务验收为后续独立门禁。非阻塞记录:RDM TestSlowLedgerPersistsLifecycle 存在内存终态先于台账回写的竞态(waitDone 只等内存状态)。
|
||||
|
||||
## 规划进展与下一步
|
||||
|
||||
- 本次推进/剩余:计划 U1–U9 全部交付;剩余为实网联调与部署类后续门禁
|
||||
- 首选下一任务:真实搜索/MinerU/嵌入实网联调(需用户确认提供方、凭据与费用)
|
||||
- 推荐依据:计划 Verification Contract 中唯一 NOT_RUN 的能力验证
|
||||
- 前置条件/待确认:用户批准外部付费调用并经环境注入凭据
|
||||
- 预期产物/验收条件:KB `KBREG_*` 实网冒烟记录,不入库任何凭据
|
||||
- 重复任务核对:无在途同类任务
|
||||
- 启动授权:未授权(建议不自动启动新任务,仍须明确授权)
|
||||
|
||||
## 合入与清理
|
||||
|
||||
- Review 记录:host 主模型逐个审阅各单元 diff(Dev 05a60f7/4764cb4/c1181d4/9dd9f1a,组件仓见各 PR),实施均由独立 cursor worker 新进程完成,审阅未复用实施会话;Dev U8 审阅发现扫描默认目录含服务端 bin/ 必然误报,已由 dev-u8-regulations-scan-default 修复;其余无阻塞项。
|
||||
- 冲突记录:main #617 将 modules/frontend 改钉 426d104,与本分支 50ec836 冲突;准备单元还原到基线后干净合并(d5d6f70),再由单元钉回 50ec836(426d104 的后代,仅加卡状态修正);modules/ui 两侧同为 5c2b103。
|
||||
- CI 记录:NOT_RUN(当前 HEAD 完整 SHA、全部必需检查、运行链接、执行身份及 GATE 结果)
|
||||
- 合入记录:NOT_RUN(交付授权范围、PR、被核验 HEAD、合入 SHA、目标分支及内容核验)
|
||||
- 清理记录:NOT_RUN(授权依据、写者退出确认、worktree/分支/任务卡处置)
|
||||
|
||||
<!-- Local receipt: SELF. Digests detect corruption; they do not authenticate a reviewer or CI. -->
|
||||
```json
|
||||
{
|
||||
"summary_schema": 1,
|
||||
"source": "SELF",
|
||||
"timestamp": "2026-10-18T09:17:02.121735+00:00",
|
||||
"command": "make precheck",
|
||||
"exit_code": 0,
|
||||
"cwd": "/home/weichen/projects/Agent-System-Dev",
|
||||
"before_head": "b5e23daed2f0ea46261979de1d62e4de0cfa88f9",
|
||||
"after_head": "b5e23daed2f0ea46261979de1d62e4de0cfa88f9",
|
||||
"branch": "main",
|
||||
"target_branch": "main",
|
||||
"target_head": "b5e23daed2f0ea46261979de1d62e4de0cfa88f9",
|
||||
"root_target": "main",
|
||||
"immediate_target": "main",
|
||||
"before_tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"after_tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"output_tail": [
|
||||
"make[1]: Entering directory '/home/weichen/projects/Agent-System-Dev'",
|
||||
"[repo] branch=main head=b5e23daed2",
|
||||
"[remote] origin/main=b5e23daed2 ahead=0 behind=0",
|
||||
"[tree] clean submodules_drift=0 uninit=3",
|
||||
"[warn] 3 个子模块未初始化——构建/测试前需物化(不阻断写入)",
|
||||
"[worktrees] linked=8",
|
||||
"[recycle] merged un-recycled branches: feature/layered-python-env",
|
||||
"[initiatives] local cards (not authoritative): none",
|
||||
"[hooks] core.hooksPath=scripts/hooks(pre-commit/post-merge 实际接线)",
|
||||
"[facts] policy/facts.md 6 条事实均在有效期内",
|
||||
"[required-reading] core/baseline.md, workflows/delivery.md §1, policy/delivery.md",
|
||||
"[R0] b5e23daed2(完整:b5e23daed2f0ea46261979de1d62e4de0cfa88f9)",
|
||||
"[worktree] before-sync: recursive component checks passed",
|
||||
"[verdict] READY — 保留本次 precheck receipt 后建任务工作区:PRECHECK_RECEIPT=/tmp/task-precheck.json make task-start NAME=feature/your-branch",
|
||||
"make[1]: Leaving directory '/home/weichen/projects/Agent-System-Dev'"
|
||||
],
|
||||
"output_sha256": "cd85b90ba7dbefab03e6e67bc8d02a3ad658a219dd81d4547f5126d876af5d9c",
|
||||
"receipt_sha256": "ae2713785b994cb723da45b2f9ebf2a2144ea6aed2efb91f1592c7f4819e8e4e",
|
||||
"receipt_path": "/home/weichen/.cache/agent-system-dev/evidence/ae2713785b994cb723da45b2f9ebf2a2144ea6aed2efb91f1592c7f4819e8e4e.json"
|
||||
}
|
||||
```
|
||||
| 同步(记录前对象) | ba81d638a6c845d0acde6896f4001bed096ba26c | fd2c13f4d883b1bff29d6ab0f82d64483e31ca24 | 2026-10-18T11:40:44Z |
|
||||
|
||||
<!-- Local receipt: SELF. Digests detect corruption; they do not authenticate a reviewer or CI. -->
|
||||
```json
|
||||
{
|
||||
"summary_schema": 1,
|
||||
"source": "SELF",
|
||||
"timestamp": "2026-10-18T11:57:02.728215+00:00",
|
||||
"command": "make test",
|
||||
"exit_code": 2,
|
||||
"cwd": "/home/weichen/projects/Agent-System-Dev-wt-feature-regulations-kb",
|
||||
"before_head": "4764cb48118975b0bd05395eaafd31c545c242ed",
|
||||
"after_head": "4764cb48118975b0bd05395eaafd31c545c242ed",
|
||||
"branch": "feature/regulations-kb",
|
||||
"target_branch": "main",
|
||||
"target_head": "a5f3ce5ac1d1a5f366b08d8e87a1379f84ac7cdf",
|
||||
"root_target": "main",
|
||||
"immediate_target": "main",
|
||||
"before_tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"after_tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"output_tail": [
|
||||
"make[1]: Entering directory '/home/weichen/projects/Agent-System-Dev-wt-feature-regulations-kb'",
|
||||
"python3 scripts/check-worktree.py verify",
|
||||
"ERROR: uninitialized submodule: /home/weichen/projects/Agent-System-Dev-wt-feature-regulations-kb/modules/frontend/deps/development-guidelines; initialize and inspect it first",
|
||||
"make[1]: *** [Makefile:227: test-worktree] Error 1",
|
||||
"make[1]: Leaving directory '/home/weichen/projects/Agent-System-Dev-wt-feature-regulations-kb'"
|
||||
],
|
||||
"output_sha256": "97d03ed7bcee4e2a490075e1dc6dd6c7fba3ccdbfc81a5d2feb1c25322f3f32e",
|
||||
"receipt_sha256": "56b0266357675abe038512ea28113c8586de5ddadb48872fd50cd1287da139a5",
|
||||
"receipt_path": "/home/weichen/.cache/agent-system-dev/evidence/56b0266357675abe038512ea28113c8586de5ddadb48872fd50cd1287da139a5.json"
|
||||
}
|
||||
```
|
||||
|
||||
<!-- Local receipt: SELF. Digests detect corruption; they do not authenticate a reviewer or CI. -->
|
||||
```json
|
||||
{
|
||||
"summary_schema": 1,
|
||||
"source": "SELF",
|
||||
"timestamp": "2026-10-18T12:05:04.108178+00:00",
|
||||
"command": "make test",
|
||||
"exit_code": 2,
|
||||
"cwd": "/home/weichen/projects/Agent-System-Dev-wt-feature-regulations-kb",
|
||||
"before_head": "4764cb48118975b0bd05395eaafd31c545c242ed",
|
||||
"after_head": "4764cb48118975b0bd05395eaafd31c545c242ed",
|
||||
"branch": "feature/regulations-kb",
|
||||
"target_branch": "main",
|
||||
"target_head": "a5f3ce5ac1d1a5f366b08d8e87a1379f84ac7cdf",
|
||||
"root_target": "main",
|
||||
"immediate_target": "main",
|
||||
"before_tracked_diff_sha256": "e5b70873c6221fa2a87e84096e16c18a4aa9687792c533b0751fc35d78810d3a",
|
||||
"after_tracked_diff_sha256": "e5b70873c6221fa2a87e84096e16c18a4aa9687792c533b0751fc35d78810d3a",
|
||||
"output_tail": [
|
||||
"用法:identity <ensure|verify|capabilities> --instance-id ID [--dbref REF] [--data DIR] [--dsn-file FILE]",
|
||||
"ensured instance_id=svc-t1-abcdef123456 dbref=sqlite",
|
||||
"identity verify: system identity mismatch: 库内 instance_id=\"svc-t1-abcdef123456\" dbref=\"sqlite\" ≠ 期望 \"svc-t1-zzzzzz999999\" / \"sqlite\"",
|
||||
"identity verify: system identity mismatch: 库内 instance_id=\"svc-t1-abcdef123456\" dbref=\"sqlite\" ≠ 期望 \"svc-t1-abcdef123456\" / \"pg\"",
|
||||
"identity verify: identity database missing: /tmp/TestVerifyMissingDBCreatesNothing4144307923/001/absent/agent-system.db",
|
||||
"--- FAIL: TestDSNFileMode (0.00s)",
|
||||
" identity_test.go:149: 0644 的 dsn 文件必须拒绝",
|
||||
"ensured instance_id=svc-dsnenv-abcdef123456 dbref=sqlite",
|
||||
"verified instance_id=svc-dsnenv-abcdef123456 dbref=sqlite schema_version=36",
|
||||
"FAIL",
|
||||
"FAIL\tagent-system-backend/pkg/identity\t0.073s",
|
||||
"? \tagent-system-backend/web\t[no test files]",
|
||||
"FAIL",
|
||||
"make[1]: *** [Makefile:150: test-backend] Error 1",
|
||||
"make[1]: Leaving directory '/home/weichen/projects/Agent-System-Dev-wt-feature-regulations-kb'"
|
||||
],
|
||||
"output_sha256": "58e94f00eb461e5e952041ad5f8fa26609b119f1d7b84675c7bf2e64ec5c5e6b",
|
||||
"receipt_sha256": "6d89985942566c6003a138a4292cd61e5d0133d95ddde21fb49701acbbe7cd84",
|
||||
"receipt_path": "/home/weichen/.cache/agent-system-dev/evidence/6d89985942566c6003a138a4292cd61e5d0133d95ddde21fb49701acbbe7cd84.json"
|
||||
}
|
||||
```
|
||||
|
||||
<!-- Local receipt: SELF. Digests detect corruption; they do not authenticate a reviewer or CI. -->
|
||||
```json
|
||||
{
|
||||
"summary_schema": 1,
|
||||
"source": "SELF",
|
||||
"timestamp": "2026-10-18T12:15:32.512450+00:00",
|
||||
"command": "make test",
|
||||
"exit_code": 0,
|
||||
"cwd": "/home/weichen/projects/Agent-System-Dev-wt-feature-regulations-kb",
|
||||
"before_head": "4764cb48118975b0bd05395eaafd31c545c242ed",
|
||||
"after_head": "4764cb48118975b0bd05395eaafd31c545c242ed",
|
||||
"branch": "feature/regulations-kb",
|
||||
"target_branch": "main",
|
||||
"target_head": "a5f3ce5ac1d1a5f366b08d8e87a1379f84ac7cdf",
|
||||
"root_target": "main",
|
||||
"immediate_target": "main",
|
||||
"before_tracked_diff_sha256": "42a6b8866c32451b0dc56320446448cc2ce4350bc918c331660f707d8dd9bf6d",
|
||||
"after_tracked_diff_sha256": "42a6b8866c32451b0dc56320446448cc2ce4350bc918c331660f707d8dd9bf6d",
|
||||
"output_tail": [
|
||||
"added 162 packages in 630ms",
|
||||
"",
|
||||
" RUN v4.1.11 /home/weichen/projects/Agent-System-Dev-wt-feature-regulations-kb/modules/ui",
|
||||
"",
|
||||
"",
|
||||
" Test Files 19 passed (19)",
|
||||
" Tests 178 passed (178)",
|
||||
" Start at 12:22:06",
|
||||
" Duration 1.52s (transform 691ms, setup 0ms, import 2.26s, tests 3.11s, environment 6.10s)",
|
||||
"",
|
||||
"knip unused exports 57 <= 57",
|
||||
"cd deps/agent-command && go vet ./... && go test -count=1 ./...",
|
||||
"ok \tagent-command\t0.003s",
|
||||
"ok \tagent-command/conformance\t0.002s",
|
||||
"make[1]: Leaving directory '/home/weichen/projects/Agent-System-Dev-wt-feature-regulations-kb'"
|
||||
],
|
||||
"output_sha256": "a72815b5e648b64aba5b4ce14f222f3e756c959ecc60f383c139231bca7a503d",
|
||||
"receipt_sha256": "f25d5268ba68318504588ef006d34ef83956535a71237780d51ecc52c0bce76c",
|
||||
"receipt_path": "/home/weichen/.cache/agent-system-dev/evidence/f25d5268ba68318504588ef006d34ef83956535a71237780d51ecc52c0bce76c.json"
|
||||
}
|
||||
```
|
||||
|
||||
<!-- Local receipt: SELF. Digests detect corruption; they do not authenticate a reviewer or CI. -->
|
||||
```json
|
||||
{
|
||||
"summary_schema": 1,
|
||||
"source": "SELF",
|
||||
"timestamp": "2026-10-18T12:25:15.292941+00:00",
|
||||
"command": "/tmp/regkb-pg-run.sh make test-regulations-kb",
|
||||
"exit_code": 0,
|
||||
"cwd": "/home/weichen/projects/Agent-System-Dev-wt-feature-regulations-kb",
|
||||
"before_head": "4764cb48118975b0bd05395eaafd31c545c242ed",
|
||||
"after_head": "4764cb48118975b0bd05395eaafd31c545c242ed",
|
||||
"branch": "feature/regulations-kb",
|
||||
"target_branch": "main",
|
||||
"target_head": "a5f3ce5ac1d1a5f366b08d8e87a1379f84ac7cdf",
|
||||
"root_target": "main",
|
||||
"immediate_target": "main",
|
||||
"before_tracked_diff_sha256": "2cea7a6a2f3deef1d75ddd4348dfd1fa9a712b05c43a1ceccd62ec5bb3ad016d",
|
||||
"after_tracked_diff_sha256": "2cea7a6a2f3deef1d75ddd4348dfd1fa9a712b05c43a1ceccd62ec5bb3ad016d",
|
||||
"output_tail": [
|
||||
"ok \tagent-system-kb-regulations/tests/webcapture\t0.005s",
|
||||
"ok \tagent-system-kb-regulations/tests/websearch\t0.156s",
|
||||
"make[2]: Leaving directory '/tmp/regkb-kb-5dddad2'",
|
||||
"PASS kb-test-pg",
|
||||
"=== stage rdm-kbreg ===",
|
||||
"ok \tagent-system-rdm/plugins/kbreg\t0.006s",
|
||||
"ok \tagent-system-rdm/internal/rdmapp\t0.039s",
|
||||
"ok \tagent-system-rdm/plugins/rdm\t0.041s",
|
||||
"PASS rdm-kbreg",
|
||||
"=== stage client-asset-secret-scan =<redacted>",
|
||||
"scan: /tmp/regkb-rdm-ece91da/.build/product/frontend/dist",
|
||||
"scan: 已核对 0 个凭据变量:<无>",
|
||||
"PASS client-asset-secret-scan",
|
||||
"regulations-kb: PASS",
|
||||
"make[1]: Leaving directory '/home/weichen/projects/Agent-System-Dev-wt-feature-regulations-kb'"
|
||||
],
|
||||
"output_sha256": "e63740d8864124a5082254e4da011ea44539f30e86f1147086cf9e4522affc3e",
|
||||
"receipt_sha256": "1b63184493f6cf51a4d98a6e9b556201a5a7961392200986e90315aaf2ae515d",
|
||||
"receipt_path": "/home/weichen/.cache/agent-system-dev/evidence/1b63184493f6cf51a4d98a6e9b556201a5a7961392200986e90315aaf2ae515d.json"
|
||||
}
|
||||
```
|
||||
|
||||
<!-- Local receipt: SELF. Digests detect corruption; they do not authenticate a reviewer or CI. -->
|
||||
```json
|
||||
{
|
||||
"summary_schema": 1,
|
||||
"source": "SELF",
|
||||
"timestamp": "2026-10-18T12:40:24.125853+00:00",
|
||||
"command": "make task-sync",
|
||||
"exit_code": 0,
|
||||
"cwd": "/home/weichen/projects/Agent-System-Dev-wt-feature-regulations-kb",
|
||||
"before_head": "d5134671ab6b45e6791c1ebcf8fcb5a10d6253d0",
|
||||
"after_head": "d5134671ab6b45e6791c1ebcf8fcb5a10d6253d0",
|
||||
"branch": "feature/regulations-kb",
|
||||
"target_branch": "main",
|
||||
"target_head": "a5f3ce5ac1d1a5f366b08d8e87a1379f84ac7cdf",
|
||||
"root_target": "main",
|
||||
"immediate_target": "main",
|
||||
"before_tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"after_tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"output_tail": [
|
||||
"make[1]: Entering directory '/home/weichen/projects/Agent-System-Dev-wt-feature-regulations-kb'",
|
||||
"[worktree] before-sync: recursive component checks passed",
|
||||
"[worktree] before-update: recursive component checks passed",
|
||||
"[worktree] materialize: recursive component checks passed",
|
||||
"[worktree] after-sync: recursive component checks passed",
|
||||
"[evidence] WARN JSON receipt line 161: unverified: recorded component state was not at its pinned SHA ——关键检查须重跑并以 make evidence 重新写入",
|
||||
"[evidence] WARN JSON receipt line 203: unverified: recorded component state was not at its pinned SHA ——关键检查须重跑并以 make evidence 重新写入",
|
||||
"[evidence] WARN JSON receipt line 234: recorded HEAD predates non-card changes ——关键检查须重跑并以 make evidence 重新写入",
|
||||
"[evidence] WARN JSON receipt line 275: recorded HEAD predates non-card changes ——关键检查须重跑并以 make evidence 重新写入",
|
||||
"[evidence] WARN JSON receipt line 316: recorded HEAD predates non-card changes ——关键检查须重跑并以 make evidence 重新写入",
|
||||
"[synced] sync_base=a5f3ce5ac1d1a5f366b08d8e87a1379f84ac7cdf tested_head=d5134671ab6b45e6791c1ebcf8fcb5a10d6253d0 checked_at=2026-10-18T12:40:58Z changed=0 sync_target=main",
|
||||
"[next] 跑正式验收(make test 等),证据写入任务卡",
|
||||
"make[1]: Leaving directory '/home/weichen/projects/Agent-System-Dev-wt-feature-regulations-kb'"
|
||||
],
|
||||
"output_sha256": "9e703c40b238a0b62b878f7ea256da658543ff7bbbdced7550e4827f3b248c59",
|
||||
"receipt_sha256": "4e28bf18dd14890939bd04bf1910e874af9b29ced4b77128429e9825cda3791b",
|
||||
"receipt_path": "/home/weichen/.cache/agent-system-dev/evidence/4e28bf18dd14890939bd04bf1910e874af9b29ced4b77128429e9825cda3791b.json"
|
||||
}
|
||||
```
|
||||
|
||||
<!-- Local receipt: SELF. Digests detect corruption; they do not authenticate a reviewer or CI. -->
|
||||
```json
|
||||
{
|
||||
"summary_schema": 1,
|
||||
"source": "SELF",
|
||||
"timestamp": "2026-10-18T12:41:05.196483+00:00",
|
||||
"command": "make test",
|
||||
"exit_code": 0,
|
||||
"cwd": "/home/weichen/projects/Agent-System-Dev-wt-feature-regulations-kb",
|
||||
"before_head": "0f6310aad06e9d3c8e8eea07612f0760df9b19e6",
|
||||
"after_head": "0f6310aad06e9d3c8e8eea07612f0760df9b19e6",
|
||||
"branch": "feature/regulations-kb",
|
||||
"target_branch": "main",
|
||||
"target_head": "a5f3ce5ac1d1a5f366b08d8e87a1379f84ac7cdf",
|
||||
"root_target": "main",
|
||||
"immediate_target": "main",
|
||||
"before_tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"after_tracked_diff_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"output_tail": [
|
||||
"added 162 packages in 711ms",
|
||||
"",
|
||||
" RUN v4.1.11 /home/weichen/projects/Agent-System-Dev-wt-feature-regulations-kb/modules/ui",
|
||||
"",
|
||||
"",
|
||||
" Test Files 19 passed (19)",
|
||||
" Tests 178 passed (178)",
|
||||
" Start at 12:47:18",
|
||||
" Duration 1.58s (transform 1.02s, setup 0ms, import 2.77s, tests 3.48s, environment 5.76s)",
|
||||
"",
|
||||
"knip unused exports 57 <= 57",
|
||||
"cd deps/agent-command && go vet ./... && go test -count=1 ./...",
|
||||
"ok \tagent-command\t0.002s",
|
||||
"ok \tagent-command/conformance\t0.002s",
|
||||
"make[1]: Leaving directory '/home/weichen/projects/Agent-System-Dev-wt-feature-regulations-kb'"
|
||||
],
|
||||
"output_sha256": "8fe21499ad31119df362f6f54d111368de6f081512939afd2289ef45d74f901c",
|
||||
"receipt_sha256": "e43b0140f620e8db23c2505152b9ae42189a0f1160acb916cb1d648f7d66bd90",
|
||||
"receipt_path": "/home/weichen/.cache/agent-system-dev/evidence/e43b0140f620e8db23c2505152b9ae42189a0f1160acb916cb1d648f7d66bd90.json"
|
||||
}
|
||||
```
|
||||
|
||||
<!-- Local receipt: SELF. Digests detect corruption; they do not authenticate a reviewer or CI. -->
|
||||
```json
|
||||
{
|
||||
"summary_schema": 1,
|
||||
"source": "SELF",
|
||||
"timestamp": "2026-10-18T12:47:22.351043+00:00",
|
||||
"command": "/tmp/regkb-pg-run.sh make test-regulations-kb",
|
||||
"exit_code": 0,
|
||||
"cwd": "/home/weichen/projects/Agent-System-Dev-wt-feature-regulations-kb",
|
||||
"before_head": "0f6310aad06e9d3c8e8eea07612f0760df9b19e6",
|
||||
"after_head": "0f6310aad06e9d3c8e8eea07612f0760df9b19e6",
|
||||
"branch": "feature/regulations-kb",
|
||||
"target_branch": "main",
|
||||
"target_head": "a5f3ce5ac1d1a5f366b08d8e87a1379f84ac7cdf",
|
||||
"root_target": "main",
|
||||
"immediate_target": "main",
|
||||
"before_tracked_diff_sha256": "6b88a13df7ae72fb457b9506c3627fbc3789863e5a024b64a8934ccce11a1429",
|
||||
"after_tracked_diff_sha256": "6b88a13df7ae72fb457b9506c3627fbc3789863e5a024b64a8934ccce11a1429",
|
||||
"output_tail": [
|
||||
"ok \tagent-system-kb-regulations/tests/webcapture\t0.006s",
|
||||
"ok \tagent-system-kb-regulations/tests/websearch\t0.156s",
|
||||
"make[2]: Leaving directory '/tmp/regkb-kb-5dddad2'",
|
||||
"PASS kb-test-pg",
|
||||
"=== stage rdm-kbreg ===",
|
||||
"ok \tagent-system-rdm/plugins/kbreg\t0.004s",
|
||||
"ok \tagent-system-rdm/internal/rdmapp\t0.036s",
|
||||
"ok \tagent-system-rdm/plugins/rdm\t0.042s",
|
||||
"PASS rdm-kbreg",
|
||||
"=== stage client-asset-secret-scan =<redacted>",
|
||||
"scan: /tmp/regkb-rdm-ece91da/.build/product/frontend/dist",
|
||||
"scan: 已核对 0 个凭据变量:<无>",
|
||||
"PASS client-asset-secret-scan",
|
||||
"regulations-kb: PASS",
|
||||
"make[1]: Leaving directory '/home/weichen/projects/Agent-System-Dev-wt-feature-regulations-kb'"
|
||||
],
|
||||
"output_sha256": "6f8c741beb6d20a67cda276273bd492b6addc4f94f3a4ac522e25be6bed32e40",
|
||||
"receipt_sha256": "b108ee5862b15614431152bc83dd59aff7991abc7de5487722ec1cbcf1b908a6",
|
||||
"receipt_path": "/home/weichen/.cache/agent-system-dev/evidence/b108ee5862b15614431152bc83dd59aff7991abc7de5487722ec1cbcf1b908a6.json"
|
||||
}
|
||||
```
|
||||
|
||||
## 闭合记录(合入前折叠)
|
||||
|
||||
- 本卡在 PR #614(https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/pulls/614)合入前闭合并归档,随该 PR 一同合入。
|
||||
- 该 PR 的合并提交即本任务的落地记录。
|
||||
- 合入后无需回填,也无需单独的闭合 PR。
|
||||
@@ -13,7 +13,7 @@ PLUGINS := plugins
|
||||
COMBO := core=$(shell git -C $(CORE) rev-parse --short HEAD 2>/dev/null)+backend=$(shell git -C $(BACKEND) rev-parse --short HEAD 2>/dev/null)+frontend=$(shell git -C $(FRONTEND) rev-parse --short HEAD 2>/dev/null)+ui=$(shell git -C $(UI) rev-parse --short HEAD 2>/dev/null)+agentcmd=$(shell git -C deps/agent-command rev-parse --short HEAD 2>/dev/null)+documents=$(shell git -C modules/documents rev-parse --short HEAD 2>/dev/null)+native=$(shell git -C deps/agent-native rev-parse --short HEAD 2>/dev/null)+squad=$(shell git -C deps/agent-squad rev-parse --short HEAD 2>/dev/null)+intent=$(shell git -C deps/agent-intent rev-parse --short HEAD 2>/dev/null)
|
||||
VERSION := $(shell git describe --tags --always --dirty 2>/dev/null)+$(COMBO)
|
||||
|
||||
.PHONY: help sync status build frontend svc svc-list svc-info svc-commits svc-history svc-update svc-recover svc-watchdog test-backend test-backend-pg test-multi-instance test-lifecycle test-frontend test-ui test-core test-agentcmd test-pins test-libs dev pin clean setup precheck task-triage task-triage-decide task-start task-resume task-sync task-close task-finish task-pr-check ci-wait facts-verify evidence version agent-exec-validate agent-exec-apply agent-exec-admit
|
||||
.PHONY: help sync status build frontend svc svc-list svc-info svc-commits svc-history svc-update svc-recover svc-watchdog test-backend test-backend-pg test-multi-instance test-lifecycle test-regulations-kb test-frontend test-ui test-core test-agentcmd test-pins test-libs dev pin clean setup precheck task-triage task-triage-decide task-start task-resume task-sync task-close task-finish task-pr-check ci-wait facts-verify evidence version agent-exec-validate agent-exec-apply agent-exec-admit
|
||||
|
||||
version:
|
||||
@echo "agent-system $(VERSION)"
|
||||
@@ -87,6 +87,7 @@ help:
|
||||
@echo "make build 构建单二进制 bin/agent-system(契约同步→前端构建→embed→静态链接)"
|
||||
@echo "make test 全量测试(boundaries + pins + libs + core + backend + frontend + ui + agent-command)"
|
||||
@echo "make test-governance 临时真实仓库中的任务、证据、写守卫与 CI 凭据回归"
|
||||
@echo "make test-regulations-kb 法规知识库组合门禁:需 KBREG_TEST_DATABASE_URL、SVC_RDM_SRC_DIR、KB_SRC_DIR(不纳入 make test)"
|
||||
@echo "make svc 服务级操作:make svc ENV=<name> [ACTION=deploy|start|stop|restart|status|logs] [ARGS='--from dev@<sha> --tag ...']"
|
||||
@echo "make svc-list 服务总览:make svc-list [ARGS='--tag core'];数据库运维:scripts/svc.sh db create|dsn|backup|backups|restore|clone|copy|ls|set"
|
||||
@echo "make svc-info 综合信息报告(只读):make svc-info [ARGS='pg1 --reveal']——运行服务/数据库实例与内部库/配置快照"
|
||||
@@ -164,6 +165,14 @@ test-lifecycle:
|
||||
bash scripts/fetch-rdm-pin.sh tests/integration/lifecycle/rdm.pin >/dev/null
|
||||
python3 tests/integration/lifecycle/lifecycle_suite.py
|
||||
|
||||
# 法规知识库组合门禁(U8):固定 RDM/KB 修订上的 KB test-pg、RDM kbreg 与客户端制品凭据扫描。
|
||||
# 缺环境直接失败,不静默跳过;不纳入 make test。见 tests/integration/regulations-kb/README.md。
|
||||
test-regulations-kb:
|
||||
@test -n "$${KBREG_TEST_DATABASE_URL}" || { echo "test-regulations-kb: KBREG_TEST_DATABASE_URL 未设置(一次性 PostgreSQL+pgvector 必需,不静默跳过)"; exit 1; }
|
||||
@test -n "$${SVC_RDM_SRC_DIR}" || { echo "test-regulations-kb: SVC_RDM_SRC_DIR 未设置(RDM 检出必需,不静默跳过)"; exit 1; }
|
||||
@test -n "$${KB_SRC_DIR}" || { echo "test-regulations-kb: KB_SRC_DIR 未设置(KB-Regulations 检出必需,不静默跳过)"; exit 1; }
|
||||
bash tests/integration/regulations-kb/run.sh
|
||||
|
||||
# 双进程 HTTP 级验收(协作存储方案 U7):两个真实 serve 进程共享隔离 PG。
|
||||
# 缺环境时明确失败而非静默跳过;见 tests/integration/multi-instance/README.md。
|
||||
test-multi-instance:
|
||||
|
||||
+16
@@ -82,3 +82,19 @@ U2 起实施与部署分别评审。
|
||||
- [渐进工作台界面重设计 r0.2](modules/documents/docs/proposals/2026-10-12-work-companion-ui-design.md):用户已授权连续实施;[计划 r1](modules/documents/docs/proposals/2026-10-12-work-companion-ui-plan.md)覆盖任务摘要、对话/输入、窄屏和真实状态投影;进展见对应任务卡。
|
||||
|
||||
- [系统项目、成员工作入口与私域协作闭环 r1](modules/documents/docs/proposals/2026-10-13-system-project-membership.md):2026-10-13 用户批准阶段 1–9 连续推进;统一全局项目身份与名称、成员个人会话、每项目两树一网和私域权限;当前组合验证/CI/tag 消费推进中,部署与线上修复未授权。
|
||||
|
||||
## 法规知识库组合
|
||||
|
||||
[法规知识库计划](docs/superpowers/plans/2026-10-18-regulations-knowledge-base-plan.md) U8 的固定组合:
|
||||
|
||||
- `modules/backend` 56a7f9f(EXT-20 法规检索/搜索扩展合同)、`modules/documents` 5bb4877(EXT-20 提案)、
|
||||
`modules/frontend` 50ec836 与 `modules/ui` 5c2b103(法规引用渲染)。
|
||||
- RDM ece91da(含 kbreg 组合)与 KB-Regulations 5dddad2,固定在
|
||||
`tests/integration/regulations-kb/components.pin`;KB 经 RDM 的 `pins/agent-system-kb-regulations`
|
||||
gitlink 接入,门禁要求该 gitlink 是 `kb_sha` 的祖先。
|
||||
- 凭据变量:`KBREG_DATABASE_URL`、`KBREG_EMBED_API_KEY`、`KBREG_SEARCH_ZHIPU_API_KEY`、`KBREG_MINERU_TOKEN`
|
||||
(测试库用 `KBREG_TEST_DATABASE_URL`)。按环境注入、轮换与撤销见 KB 仓 `docs/operations/runbook.md`;值不入仓、不回显。
|
||||
- 门禁:`make test-regulations-kb`(需 `KBREG_TEST_DATABASE_URL`、`SVC_RDM_SRC_DIR`、`KB_SRC_DIR`,不纳入 `make test`),
|
||||
说明见 `tests/integration/regulations-kb/README.md`。真实搜索/嵌入/MinerU 调用 NOT_RUN,待 owner 批准。
|
||||
|
||||
部署、版本发布与业务/法务验收是后续独立门禁,本组合门禁通过不代表其中任何一项完成。
|
||||
|
||||
@@ -0,0 +1,390 @@
|
||||
---
|
||||
title: "feat: Build a traceable medical-device regulations knowledge base"
|
||||
date: 2026-10-18
|
||||
type: feat
|
||||
artifact_contract: ce-unified-plan/v1
|
||||
product_contract_source: ce-plan-bootstrap
|
||||
execution: code
|
||||
origin: ../Agent-System-RDM/docs/requirements/01-用户需求与系统需求.md, ../Agent-System-RDM/docs/requirements/02-产品概念与形态定义.md, ../Agent-System-RDM/docs/requirements/03-产品设计方案.md
|
||||
---
|
||||
|
||||
# Build a Traceable Medical-Device Regulations Knowledge Base
|
||||
|
||||
## Goal Capsule
|
||||
|
||||
- **Objective:** RDM users can rely on relevant medical-device regulations, standards, and review guidance with precise, reproducible citations in conversations and documents, backed by complete audit evidence.
|
||||
- **Means:** Create an independently versioned regulations knowledge component and integrate it with RDM's mandatory knowledge-base plus real-web-search verification flow (KTD1, KTD2).
|
||||
- **Authority:** Source documents and issuing authorities govern legal text and status; the versioned corpus governs the text indexed for knowledge-base retrieval; verified network captures provide the second source; RDM project/resource authorization governs access to project work and audit data.
|
||||
- **Stop conditions:** Do not publish uncertain or unlicensed corpus material; do not report dual-source verification when either channel, version mapping, or excerpt comparison is incomplete; stop on access-control failure or an unreconciled source conflict.
|
||||
- **Execution profile:** Cross-repository work in `Agent-System-KB-Regulations`, `Agent-System-RDM`, and the base repository when a public shared-regulations retrieval or real-web-search extension is required.
|
||||
- **Finishing responsibility:** The implementation owner completes component tests, RDM integration, exact-composition verification, review, and authorized release steps. Runtime deployment and business acceptance remain separate from this plan.
|
||||
|
||||
---
|
||||
|
||||
## Product Contract
|
||||
|
||||
### Summary
|
||||
|
||||
Build a controlled, versioned medical-device regulations knowledge base that RDM can query alongside a real network search. Every generated regulatory claim must carry structured citations that resolve to exact source text, clause location, edition, verification status, and immutable audit evidence.
|
||||
|
||||
### Problem Frame
|
||||
|
||||
RDM already models a regulatory dual-channel check, but its current network leg is based on model-proposed URLs and excerpts followed by fetching and excerpt matching. This does not establish that an actual search occurred. Precise citations also require more than vector retrieval: source editions, clause hierarchy, paragraph anchors, parsed text, and exact evidence must survive re-indexing and later audit.
|
||||
|
||||
The current requirements already call for local regulations knowledge, knowledge-base plus network cross-checking, citations, and project isolation (`UR-14`, `SR-F3`, `SR-N4`; see origin documents above). The regulations directory currently exposes a manifest and a PostgreSQL dump; the manifest reports 2,907 documents, 312,919 chunks, and 279,184 nodes. These are inventory claims, not validation of the dump contents, source-file availability, legal status, permissions, or parsing accuracy. Those must be verified before corpus publication.
|
||||
|
||||
### Requirements
|
||||
|
||||
- R1. Regulations, standards, and review guidance relevant to RDM work must use both the controlled regulations knowledge base and a real network search. The system must distinguish actual search from model-generated URLs or recollection.
|
||||
- R2. Every regulatory citation must resolve to a specific regulation identity and edition, clause path, exact excerpt, source locator, and verification batch. The system must separately check whether the cited excerpt supports the generated claim; authentic text and matching dual sources alone do not establish claim support or legal applicability. Unsupported/uncertain claims must be marked unverified or routed for review. Generated summaries may aid retrieval but must never be presented or audited as legal source text.
|
||||
- R3. The corpus must preserve original assets or an authorized immutable source representation, extracted text, hierarchy, source provenance, effective status, and content hashes independently from rebuildable search indexes.
|
||||
- R4. Ingestion must preserve meaningful legal structure: regulation, part/chapter/section, clause, subclause/item, paragraph, list, and table relationships when present. Retrieval chunks must retain heading context and map back to one or more exact source nodes.
|
||||
- R5. Parsing, normalization, chunking, embedding, and ranking versions must be recorded. Re-indexing must not rewrite evidence used by prior answers, documents, or audits.
|
||||
- R6. A dual-source result is verified only when both sources are fetched or retrieved from pinned corpus/network evidence, mapped to the same regulation edition and clause, and their relevant text is compared. Missing, stale, disputed, inaccessible, or conflicting evidence must be explicit and must not be labeled verified.
|
||||
- R7. Conversation and document citations must use one structured citation contract, preserve the edition and excerpt used at creation time, and provide an authorized path to inspect the source evidence.
|
||||
- R8. Audit records must reconstruct the question, corpus revision, search provider/query/results, retrieved clause IDs, source snapshots and hashes, comparison result, generated claims and citations, actor, authorization outcome, and any human resolution. Published evidence batches must detect unauthorized modification independently of mutable database rows.
|
||||
- R9. Corpus access and audit disclosure must follow resource-level and project-level authorization. Public or shared regulations do not grant access to private project documents, conversations, or audit records.
|
||||
- R10. MinerU may be used as a replaceable parsing adapter for supported assets. Its token is server-side only; parsing limits, task lifecycle, failures, and output provenance must be handled without exposing credentials or treating parser output as authoritative legal truth.
|
||||
- R11. The regulations knowledge component must be independently versioned and testable. Its first deployment may remain local and use PostgreSQL/pgvector; a separate always-on network service is not required unless performance or operational evidence justifies it.
|
||||
- R12. Outbound search queries must use the minimum regulatory context needed and exclude confidential project/user content by default. Source fetching must enforce SSRF protections at DNS resolution, connection, and every redirect.
|
||||
- R13. Corpus and evidence retention must follow source-specific rights, retention, revocation, and takedown obligations. Withdrawal or expiry must not silently rewrite historical evidence; its current availability and legal retention basis must be auditable.
|
||||
|
||||
### Key Decisions
|
||||
|
||||
- K1. Independent knowledge component: use a dedicated regulations knowledge repository rather than placing corpus ingestion, parsing, and indexing inside RDM. This was accepted after considering the tighter RDM-only alternative; it gives the corpus pipeline and retrieval index an independent lifecycle while leaving RDM workflows in RDM. Governs R3, R4, R5, R10, R11. (session-settled: user-approved — chosen over keeping the entire corpus pipeline in RDM: ingestion, corpus versioning, and index rebuilds have a distinct lifecycle.)
|
||||
- K2. Source assets are not Git source: large source documents, database dumps, runtime indexes, and secrets remain in controlled asset/storage systems or immutable releases. Git stores schemas, parsers, metadata contracts, migration/configuration, test fixtures that are distributable, and corpus manifests. Governs R3, R5, R10, R13.
|
||||
- K3. PostgreSQL-first retrieval: begin with PostgreSQL relational source records, full-text search, and pgvector where current capacity tests support it. Keep vector indexes derived and rebuildable; move them to a dedicated vector service only if measured needs require it. Governs R3-R5, R11.
|
||||
- K4. Structure-first chunking: retain exact paragraph/clause nodes and construct retrieval chunks from legal structure rather than fixed-width text windows. Include heading breadcrumbs in retrieval text, but keep headings distinguishable from quoted source text. Governs R2-R5.
|
||||
- K5. Separate source and summary: store document/section summaries as generated retrieval aids with their model/prompt provenance. Do not require paragraph summaries by default, and never use any summary as the evidence for a legal citation. Governs R2, R4, R6.
|
||||
- K6. Fail closed on evidence state: only mark dual-source verified when both legs have valid evidence and matching edition/clause/text. A single source, inaccessible channel, unresolved edition, or substantive disagreement produces an explicit degraded/disputed state. Governs R1, R6-R8.
|
||||
- K7. RDM owns product integration: the knowledge repository owns corpus, retrieval, and ingestion; RDM owns relevance routing, dual-source orchestration, user/project authorization, conversation/document citation rendering, and business audit projection. Governs R1, R6-R9, R11-R13.
|
||||
|
||||
### Actors
|
||||
|
||||
- A1. RDM user asks a regulatory question or requests work that implicates regulations, standards, or review guidance.
|
||||
- A2. RDM agent retrieves and uses verified evidence but cannot invent legal identity, version, clause, or quotation.
|
||||
- A3. Corpus maintainer reviews source provenance, legal identity/status, parsing quality, licensing, and publication.
|
||||
- A4. RDM reviewer resolves legal applicability or substantive conflicts that automation cannot safely decide.
|
||||
- A5. Knowledge component and web-search provider return independently attributable evidence.
|
||||
- A6. Base-platform owner publishes compatible shared-regulations retrieval and web-search capabilities when the current public extension contract cannot provide them safely.
|
||||
|
||||
### Key Flows
|
||||
|
||||
- F1. Dual-source regulatory answer: a regulatory-relevant task is detected; RDM queries a pinned corpus revision and executes a real web search; source documents are fetched/parsed and mapped to clauses; evidence is compared; the model produces claims bound to citation objects; citation validation runs before the answer is shown; the evidence batch is persisted for audit.
|
||||
- F2. Corpus publication: an authorized asset batch is inventoried; exact source and rights are recorded; documents are parsed; structure and metadata pass quality gates or enter quarantine; stable nodes and retrieval chunks are generated; full-text/vector projections and evaluation results are built; a reviewed corpus revision is published without deleting prior revisions.
|
||||
- F3. Document citation lifecycle: a generated document stores citation IDs and pinned evidence/version references; preview/export resolves those references; later source changes flag potentially stale citations but never silently rewrite the historical document.
|
||||
- F4. Audit replay: an authorized auditor opens a regulatory claim and sees the exact evidence available at the time, retrieval/search provenance, comparison, citation mapping, and any human decision, subject to disclosure controls.
|
||||
|
||||
### Acceptance Examples
|
||||
|
||||
- AE1. Given both channels return the same current edition and exact clause text, when the RDM agent answers, then each regulatory assertion has a citation that opens the matching clause excerpt and both evidence records.
|
||||
- AE2. Given the corpus has a clause but real web search is unavailable, when a regulatory task runs, then the result is explicitly single-source/degraded and cannot be labeled dual-source verified.
|
||||
- AE3. Given web search finds an amended edition that conflicts with an older corpus edition, when comparison runs, then the system records both editions and the conflict, prevents a green verified state, and exposes the item for human review.
|
||||
- AE4. Given a vector index is rebuilt with a new chunking or embedding version, when an auditor opens an older answer, then the original citation still resolves to the prior corpus revision, source node, excerpt, and hashes.
|
||||
- AE5. Given an unauthorized user requests another project's regulatory audit detail, when authorization is evaluated, then the request is denied or redacted without exposing project content or restricted source text.
|
||||
- AE6. Given MinerU rejects a file, times out, or returns structurally incomplete parsing, when ingestion runs, then the job remains failed/quarantined with a reason and no unreviewed chunks enter the published corpus.
|
||||
- AE7. Given a real clause citation whose text does not support the generated claim, when citation validation runs, then citation authenticity may pass but claim support fails; the claim is marked unsupported/unverified or routed for review, and is not presented as a supported regulatory conclusion.
|
||||
|
||||
### Success Criteria
|
||||
|
||||
- Every displayed regulatory quotation resolves to a fixed source node and edition; citation verification can confirm the excerpt against the recorded source text/hash.
|
||||
- No scenario with one unavailable source, unresolved edition, or unresolved conflict is shown as dual-source verified.
|
||||
- Rebuilding an index does not alter previously stored audit batches, document citations, or source snapshots.
|
||||
- Reviewers can reconstruct each accepted claim from corpus revision, exact web evidence, comparison state, and citation links without relying on model conversation history.
|
||||
- Retrieval and parsing thresholds are established from a labeled representative sample before production publication; no unsupported precision/recall threshold is invented in advance.
|
||||
|
||||
### Scope Boundaries
|
||||
|
||||
In scope: independent regulations knowledge component; corpus inventory and ingestion; legal-document metadata and version relationships; MinerU adapter; structure-aware parsing and chunking; full-text/vector retrieval; real web search evidence; dual-channel verification contract; structured citations in RDM conversation/document paths; immutable audit projection; evaluation, security, and recovery tests.
|
||||
|
||||
#### Deferred for Later
|
||||
|
||||
- Advanced audit anchoring beyond the independently verifiable tamper-evidence baseline required for published evidence batches.
|
||||
|
||||
#### Deferred to Follow-Up Work
|
||||
|
||||
- Dedicated distributed vector database or always-on remote KB service unless measured scale, availability, or consumer requirements demand it.
|
||||
- Automated legal applicability decisions or unattended legal conflict adjudication.
|
||||
- Broad monitoring dashboards beyond the operational signals needed to run ingestion, search, and index publication.
|
||||
- Continuous regulatory change surveillance and automatic bulk re-ingestion after publication; initial release supports controlled, explicit corpus updates.
|
||||
|
||||
#### Outside This Plan
|
||||
|
||||
- Modifying or deploying production services, importing the full corpus, publishing protected standards, or approving legal interpretations.
|
||||
- Moving all RDM project knowledge, templates, or audit storage into the regulations component.
|
||||
- Using MinerU as a source of legal authority, network search engine, or legal-status classifier.
|
||||
|
||||
### Dependencies and Open Questions
|
||||
|
||||
- The actual dump schema, row quality, source-file availability, and database-to-file provenance in `../Agent-System-Regulations` must be verified before choosing a production import path. The local manifest is not sufficient evidence.
|
||||
- Rights and permitted excerpt/display/export limits must be established for every source class, especially standards and third-party review guidance. This is a publication blocker, not an implementation default.
|
||||
- A real web-search provider and authoritative-source allowlist must be selected. Existing RDM code can fetch model-proposed URLs but has no verified real-search capability in the inspected flow. If no existing base extension supports search, raise and implement a base extension through its approved process.
|
||||
- The initial local deployment and backup topology, corpus owner, update approval role, and recovery objective must be fixed before production publication.
|
||||
- Sample-driven thresholds for OCR fidelity, clause extraction, retrieval recall, citation accuracy, and stale-edition suppression are set after a representative labeled corpus is available.
|
||||
|
||||
---
|
||||
|
||||
## Planning Contract
|
||||
|
||||
### Key Technical Decisions
|
||||
|
||||
- KTD1. Repository boundary: `Agent-System-KB-Regulations` owns corpus ingestion, legal identity/version metadata, parsing, structure, chunking, retrieval indexes, corpus release manifests, and retrieval APIs/contracts. RDM retains its current plugin and owns user-facing workflows, authorization, citations, and audits. A repository boundary does not mandate a network-service boundary.
|
||||
- KTD2. Retrieval source of truth: store canonical source text and legal structure in a versioned relational corpus store; store original binaries in controlled file/object storage where appropriate; treat full-text/vector indexes as disposable projections. A vector payload may cache a short retrieval excerpt plus stable IDs and hashes but cannot be the only copy of source text.
|
||||
- KTD3. Chunk model: preserve the smallest stable source nodes (paragraph/list/table/clause) with parent hierarchy, ordering, page/layout locator, original and normalized text, and hashes. Build retrieval chunks by combining complete adjacent legal nodes, normally targeting approximately 300-800 tokens and allowing longer complete clauses when needed. Never split inside a sentence or legal condition solely to satisfy a fixed token limit. Tune limits on the labeled sample set.
|
||||
- KTD4. Heading context: persist titles as distinct structured fields and include a breadcrumb (regulation > part/chapter/section > clause number/title) in the embedding/search representation. Do not merge synthetic breadcrumbs into the text labeled as a quotation.
|
||||
- KTD5. Summary policy: keep generated regulation/part/section summaries separate from source text, with model, prompt, generation time, and summary hash. Paragraph summaries are optional and excluded from citation evidence and dual-source text comparison.
|
||||
- KTD6. Immutable corpus publication: every release pins source hashes, parsed representation hashes, metadata review state, parser/chunker/index versions, and evaluation result. Rebuild creates a new index/corpus revision; it does not mutate past evidence or citations.
|
||||
- KTD7. MinerU is an adapter in the ingestion pipeline, not a hard dependency for every file type. The adapter records task ID/state, limits, retry outcome, parser version, output hashes, and page/block locators. Secrets are server-side. At the consulted docs snapshot, API documentation described asynchronous task submission/result retrieval; limits stated 50 submitted files/minute, 5,000 files/user/day, and up to 200 MB/200 pages per file. Reconfirm these values during implementation because provider limits can change.
|
||||
- KTD8. Credential lifecycle: MinerU and search credentials are provisioned through protected runtime secret injection, separated by environment, limited to the component that needs them, and revocable/rotatable without source changes. They must not appear in source, fixtures, browser assets, command output, logs, or evidence exports.
|
||||
- KTD9. Search provider contract: network search must return provider, minimized query, timestamp, ranked results, URL/title, and fetch evidence; prioritize official publishers/regulators. Search queries contain only minimum necessary regulatory terms and exclude confidential project/user context by default. Search snippets discover sources but are not authoritative excerpts. Fetch and preserve a permitted source snapshot before it can count as verified evidence.
|
||||
- KTD10. Safe source fetch: validate scheme, host, port, resolved address, response type/size, and each redirect target; reject loopback, private, link-local, multicast, and reserved destinations after DNS resolution and at connection time. Revalidation must prevent DNS rebinding between validation and connection.
|
||||
- KTD11. Citation contract: one immutable citation object is shared by conversation, document, and audit views. It identifies claim-to-excerpt mapping, regulation/version/clause IDs, corpus revision, web source, exact offsets/locator, hashes, and verification state.
|
||||
- KTD12. Verification state: distinguish `verified`, `single_source`, `degraded`, `edition_unresolved`, `conflict`, `unverified`, and `not_applicable`; do not collapse them into a Boolean or infer compliance from clause-number equality alone.
|
||||
- KTD13. Audit persistence: append evidence batches and human resolutions. Store full snapshots only when rights permit; otherwise retain legally allowed excerpts, source locator, hashes, fetch metadata, and an explicit reason the full source is unavailable. Published batch manifests must be tamper-evident through a separately verifiable digest/signature or append-only anchor, not only hashes stored beside mutable rows. Apply source-specific retention, withdrawal, and takedown rules while preserving a non-content audit event where permitted. Never let re-indexing overwrite evidence.
|
||||
- KTD14. Shared integration contract: define a public, read-only regulations retrieval surface that pins corpus revision and returns stable regulation/edition/node IDs, permitted excerpts, locators, hashes, and disclosure metadata. The base contract must not route through owner-scoped project `KnowledgeSearch`. RDM may use only released public extensions; if absent, submit the required base proposal and compatibility tests before RDM integration. Real web search follows the same public extension boundary.
|
||||
|
||||
### High-Level Technical Design
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Asset[Controlled legal assets] --> Intake[Inventory and rights gate]
|
||||
Intake --> Parse[Parser adapters including MinerU]
|
||||
Parse --> Structure[Versioned legal structure and source text]
|
||||
Structure --> Build[Chunk and index builder]
|
||||
Build --> Corpus[(PostgreSQL corpus and full-text index)]
|
||||
Build --> Vector[(Rebuildable vector projection)]
|
||||
RDM[RDM regulatory workflow] -->|query pinned revision| Corpus
|
||||
RDM --> Search[Real web-search provider]
|
||||
Search --> Fetch[Fetch and snapshot permitted evidence]
|
||||
Corpus --> Compare[Clause/version/text comparison]
|
||||
Fetch --> Compare
|
||||
Compare --> Citation[Immutable citation/evidence batch]
|
||||
Citation --> Chat[Conversation citations]
|
||||
Citation --> Docs[Document citations]
|
||||
Citation --> Audit[Authorized audit projection]
|
||||
```
|
||||
|
||||
The relations are versioned rather than overwrite-in-place:
|
||||
|
||||
```text
|
||||
source_asset -> regulation_identity -> regulation_edition -> legal_nodes
|
||||
| |
|
||||
| +-> retrieval_chunks -> full-text/vector projections
|
||||
+-> status/relations (amends, replaces, repeals)
|
||||
|
||||
verification_batch -> corpus_revision + legal_node/excerpt + web_capture + comparison + generated_claims
|
||||
document_version -> citation_ids -> verification_batch/source hashes
|
||||
```
|
||||
|
||||
### Data and Chunking Contract
|
||||
|
||||
The canonical legal node is the smallest accurately locatable source unit. Typical node kinds are document title, part/chapter/section, clause, subclause, paragraph, list item, table, table row/cell, footnote, and annex. The source may lack some levels; preserve actual structure and record extraction gaps rather than inventing empty hierarchy.
|
||||
|
||||
Each node records regulation and edition IDs, parent and sibling order, node kind, displayed clause number/title, original text, normalized search text, source asset hash, page range and parser locator, extraction confidence/review state, and original/normalized text hashes. Table content retains header-to-cell relationships. A missing or ambiguous clause number is represented as such and cannot be fabricated for citation display.
|
||||
|
||||
Retrieval chunks are a separate projection over one or more nodes. They carry ordered node IDs, full heading breadcrumbs, exact composed source text with component spans, chunking version, and embedding model/version. They may overlap only by referencing adjacent nodes where evaluation proves context helps; duplicated overlap text is not independently cited. At citation time, the system resolves the generated claim to exact source-node spans, not just the retrieval chunk.
|
||||
|
||||
Generated summaries are stored in a separate table/object and indexed as lower-trust retrieval hints. Every summary states its coverage, target regulation revision, model/prompt version, and generation provenance. Ranking must not cause a summary to outrank an exact applicable clause without displaying that it is a summary. Summaries never satisfy the source-evidence requirement.
|
||||
|
||||
### Assumptions
|
||||
|
||||
- The source corpus may be imported into a new controlled PostgreSQL database rather than modifying the source dump in place.
|
||||
- First release favors a locally deployable component and a simple supported retrieval interface over a distributed multi-service topology.
|
||||
- The RDM repository remains the owner of project-specific claim records and user-visible conversation/document flows; the regulations repository is the owner of canonical legal corpus and reusable evidence/search contracts.
|
||||
- Some source classes may not permit full-text retention or redistribution; their ingestion may be metadata-only or blocked until rights are resolved.
|
||||
|
||||
### Sequencing and Dependencies
|
||||
|
||||
`U1 corpus/rights audit -> U2 repository contracts and schema -> U3 parsing/structure/chunking -> U4 retrieval and evaluation -> U6 RDM dual-source and audit integration -> U7 conversation/document citations -> U8 composition, security, recovery, and acceptance.` After U2 stabilizes the identifiers/evidence contract, U3, U5, and U9 may proceed in parallel; U4 depends on U3; U6 depends on U4, U5, and U9. RDM must not claim dual-source verification until the public contracts and both evidence legs are integrated.
|
||||
|
||||
---
|
||||
|
||||
## Implementation Units
|
||||
|
||||
### U1. Verify corpus provenance, content, and publication rights
|
||||
|
||||
- **Goal:** Establish a trustworthy import inventory and identify material that can legally and technically be published.
|
||||
- **Requirements:** R3, R5, R10.
|
||||
- **Dependencies:** None.
|
||||
- **Files:** `docs/proposals/regulations-kb/corpus-inventory.md`; source repository's `manifest.json` and database dump are read-only inputs. U2 carries the reviewed inventory into the new repository after bootstrap.
|
||||
- **Approach:** Inspect database schema and representative rows; map documents, editions, chunks, nodes, aliases, relations, and source paths; validate dump integrity and source-file availability; classify rights and disclosure constraints; produce a provenance manifest. Keep original data untouched and quarantine records with ambiguous identity, status, or rights.
|
||||
- **Patterns to follow:** Existing RDM `TemplateAsset` provenance fields and immutable source/output hashes; controlled asset batches rather than copying runtime data into Git.
|
||||
- **Test Scenarios:**
|
||||
- A valid sample asset maps to exactly one source hash and an explicit source/rights record.
|
||||
- Duplicate binary content is deduplicated without merging distinct legal identities or editions.
|
||||
- Missing source, invalid dump row, ambiguous edition, or unknown rights is quarantined and excluded from publishable counts.
|
||||
- **Verification:** Inventory totals reconcile with the imported source snapshot or discrepancies are enumerated; a reviewer can trace each accepted sample back to its original asset and provenance. No product source assets are copied into the new repository during this discovery unit.
|
||||
|
||||
### U2. Establish the independent repository, domain contract, and versioned schema
|
||||
|
||||
- **Goal:** Create the separately versioned regulations knowledge component and its stable source/retrieval contract.
|
||||
- **Requirements:** R3, R5, R11.
|
||||
- **Dependencies:** U1.
|
||||
- **Files:** `Agent-System-KB-Regulations/README.md`; `Agent-System-KB-Regulations/AGENTS.md`; `Agent-System-KB-Regulations/PROJECT.md`; `Agent-System-KB-Regulations/go.mod`; `Agent-System-KB-Regulations/internal/domain/`; `Agent-System-KB-Regulations/internal/store/`; `Agent-System-KB-Regulations/migrations/`; `Agent-System-KB-Regulations/tests/`.
|
||||
- **Approach:** Define stable regulation identity, edition/status, source asset, legal node, retrieval chunk, corpus revision, and evidence provenance entities. Separate canonical data from search projections. Provide local deployment configuration and schema migration/recovery ownership. Keep corpus bytes out of Git; use controlled object/file references and immutable corpus release manifests.
|
||||
- **Patterns to follow:** RDM domain/store separation, immutable hashes, explicit revision contracts, fail-closed validation, and existing PostgreSQL deployment practices.
|
||||
- **Test Scenarios:**
|
||||
- A regulation with multiple editions and amends/replaces/repeals relations persists and reloads without identity collision.
|
||||
- A corpus revision cannot publish when required rights, source hash, status review, or node provenance is missing.
|
||||
- Schema migration and restore tests preserve edition/node identities and immutable historical revisions.
|
||||
- **Verification:** Domain and persistence contracts round-trip against the supported local database, and a clean restore reproduces the same corpus revision hashes.
|
||||
|
||||
### U3. Build structure-aware parsing, chunking, and MinerU adapter
|
||||
|
||||
- **Goal:** Convert approved source assets into locatable legal nodes and retrieval chunks without losing source boundaries.
|
||||
- **Requirements:** R2-R5, R10.
|
||||
- **Dependencies:** U2.
|
||||
- **Files:** `Agent-System-KB-Regulations/internal/ingest/`; `Agent-System-KB-Regulations/internal/parser/`; `Agent-System-KB-Regulations/internal/chunk/`; `Agent-System-KB-Regulations/internal/mineru/`; `Agent-System-KB-Regulations/tests/ingest/`; `Agent-System-KB-Regulations/tests/chunk/`; `Agent-System-KB-Regulations/tests/mineru/`.
|
||||
- **Approach:** Add parser adapters that produce a common block/tree representation. Preserve titles, clause numbers, paragraphs, list structure, tables, page and layout locators, parser version, and confidence. Build chunks from complete legal nodes using the versioned structure-first policy; include heading breadcrumbs in search text while keeping synthetic context separate from quote text. Store document/section summaries separately with model/prompt provenance. Treat MinerU as an asynchronous optional adapter with server-side credentials and explicit limit/retry/error states.
|
||||
- **Patterns to follow:** Existing RDM parsed-document contracts, source/content hash validation, parser adapter boundaries, and quarantine states for incomplete assets.
|
||||
- **Test Scenarios:**
|
||||
- A structured regulation preserves regulation > chapter > clause > paragraph hierarchy and exact source text through parse/chunk/reload.
|
||||
- A long clause is split only at legal paragraph boundaries; every chunk maps back to ordered source nodes and no condition is dropped.
|
||||
- A table retains headings and cell relationships; citations resolve to the correct row/cell source location.
|
||||
- Missing titles, missing clause numbers, low-confidence OCR, and absent page locators are represented as gaps rather than invented metadata.
|
||||
- MinerU timeout, provider rejection, rate limit, invalid result, or output hash mismatch leaves the job non-published and resumable/reviewable without leaking the token.
|
||||
- Summary generation failure does not block exact-source storage and cannot mark a citation as verified.
|
||||
- **Execution note:** Characterize parsing on representative structured, scanned, table-heavy, and long-clause samples before fixing token targets.
|
||||
- **Verification:** Golden parse fixtures prove text/structure/locator fidelity; all published chunks have a source-node map, and parser/chunker versions are reproducible.
|
||||
|
||||
### U4. Implement hybrid retrieval, corpus revisions, and retrieval evaluation
|
||||
|
||||
- **Goal:** Retrieve exact, applicable clause candidates across exact identifiers, full-text, and vector semantics while keeping indexes rebuildable.
|
||||
- **Requirements:** R1-R5, R11.
|
||||
- **Dependencies:** U2, U3.
|
||||
- **Files:** `Agent-System-KB-Regulations/internal/retrieval/`; `Agent-System-KB-Regulations/internal/index/`; `Agent-System-KB-Regulations/internal/publish/`; `Agent-System-KB-Regulations/eval/`; `Agent-System-KB-Regulations/tests/retrieval/`; `Agent-System-KB-Regulations/tests/publish/`.
|
||||
- **Approach:** Implement exact standard/number/clause lookup, metadata/effectivity filters, PostgreSQL full-text and vector candidate retrieval, and explainable reranking. Return stable regulation/edition/node IDs, exact excerpts, heading paths, source locators, hashes, and corpus/index versions. Use document/section summaries only as lower-trust aids. Build a labeled retrieval set and compare clause recall, edition selection, quote localization, and stale-edition suppression before publication.
|
||||
- **Patterns to follow:** Stable snapshot/revision APIs, evidence provenance enums, current RDM query/retrieval adapters, and immutable publish manifests.
|
||||
- **Test Scenarios:**
|
||||
- Exact standard number plus clause query selects the matching edition and node even when semantic similarity ranks another edition highly.
|
||||
- Natural-language query returns relevant clause nodes with heading context and exact excerpts, not only summaries.
|
||||
- A superseded or future edition is excluded or clearly labeled when the query requests current requirements.
|
||||
- Rebuilding an embedding or full-text index creates a new revision and leaves old retrieval evidence readable.
|
||||
- Empty results, malformed filters, unavailable vector index, and partial index build return explicit degraded states without fabricated hits.
|
||||
- **Verification:** Evaluation report includes dataset provenance and per-slice retrieval metrics; publication is blocked if configured acceptance thresholds regress from the reviewed baseline.
|
||||
|
||||
### U5. Provide real web search and immutable web evidence capture
|
||||
|
||||
- **Goal:** Implement the knowledge component's independently attributable network search and evidence-capture provider behind the public contract.
|
||||
- **Requirements:** R1, R6, R8, R12, R13.
|
||||
- **Dependencies:** U2 for the stable regulation/evidence contract; may run in parallel with U3 and U4 after that contract is agreed.
|
||||
- **Files:** `Agent-System-KB-Regulations/internal/websearch/`; `Agent-System-KB-Regulations/internal/webcapture/`; `Agent-System-KB-Regulations/internal/evidence/`; `Agent-System-KB-Regulations/tests/websearch/`; `Agent-System-KB-Regulations/tests/webcapture/`.
|
||||
- **Approach:** Implement the provider adapter and fetch/evidence capture in the knowledge component. Record provider, minimized query, timestamp, ranked results, URL/title, and official-source classification. Exclude confidential project/user context from outbound queries by default; allow only a separately approved policy to add specific sensitive context. Fetch selected pages/files with DNS-resolution and connection-time private/reserved-address rejection, host/scheme/port/size controls, and validation of every redirect target. Retain only rights-permitted snapshots or excerpts plus hashes and fetch metadata, and parse clauses into candidates. Do not treat search snippets, model-generated URLs, or inaccessible pages as verified evidence. U9 owns only the public base contract/compatibility boundary; U6 owns the RDM consumer adapter and workflow integration.
|
||||
- **Patterns to follow:** Existing URL fetch validation/snapshot code in RDM as a starting point only; preserve the distinction between candidate discovery and verified source fetch.
|
||||
- **Test Scenarios:**
|
||||
- A provider response records the exact query/provider/rank/time and returns stable result evidence.
|
||||
- Search timeout, rate limit, invalid URL, redirect to a disallowed host, non-text body, oversized content, or fetch failure cannot count as a verified web source.
|
||||
- A search snippet that is not present in fetched source text remains unverified.
|
||||
- A query containing a confidential project identifier is minimized or rejected before reaching the provider unless an explicit approved policy allows it.
|
||||
- An authentic citation whose excerpt does not support the generated claim passes source-integrity validation but fails claim-support validation and is marked unsupported/unverified or routed for review.
|
||||
- An official source page fetch produces a content hash and a reproducible clause excerpt/locator within applicable retention rules.
|
||||
- DNS answers resolving to private/reserved addresses, a DNS rebinding attempt, or a redirect to a disallowed address are rejected before connection and cannot count as evidence.
|
||||
- An expired or revoked source snapshot is withheld from normal display and records a rights/retention event without silently changing prior batch identity.
|
||||
- **Verification:** Integration tests demonstrate an actual provider search-to-fetch path and prove failure states remain non-verified; provider secrets never appear in logs, storage exports, or client responses.
|
||||
|
||||
### U6. Integrate mandatory dual-source verification and immutable audit batches in RDM
|
||||
|
||||
- **Goal:** Replace model-suggested network candidates as the search mechanism and bind each regulatory conclusion to immutable knowledge-base and web evidence.
|
||||
- **Requirements:** R1, R6, R8, R9, R11-R13.
|
||||
- **Dependencies:** U4, U5, U9.
|
||||
- **Files:** `Agent-System-RDM/internal/domain/regcheck.go`; `Agent-System-RDM/internal/domain/payloads.go`; `Agent-System-RDM/internal/domain/replay.go`; `Agent-System-RDM/internal/rdmapp/regcheck.go`; `Agent-System-RDM/internal/rdmapp/regfetch.go`; `Agent-System-RDM/internal/rdmapp/`; `Agent-System-RDM/plugins/rdm/plugin.go`; `Agent-System-RDM/internal/domain/regcheck_test.go`; `Agent-System-RDM/internal/rdmapp/regcheck_test.go`; `Agent-System-RDM/internal/rdmapp/regfetch_test.go`; `Agent-System-RDM/plugins/rdm/` tests.
|
||||
- **Approach:** Add a versioned evidence-batch model and persist complete source references, edition/node IDs, exact excerpts, source snapshots/hashes, query and fetch metadata, state transitions, and human resolutions. Call shared regulations retrieval through U9 and real web search through its released public contract as separate legs. Compare regulation identity, edition, clause mapping, and relevant text; replace clause-number-only agreement with evidence-level comparison. Retain existing project authorization and audit boundaries. Keep historical batches replayable after corpus re-indexing. Add a separately verifiable tamper-evidence record for published batches and rights-aware retention/withdrawal behavior.
|
||||
- **Patterns to follow:** RDM event-log replay, content-addressed network snapshots, project-authorized snapshot reads, and resource-level authorization.
|
||||
- **Test Scenarios:**
|
||||
- Same-edition, same-clause, matching excerpts from both legs produce a verified batch with both immutable evidence references.
|
||||
- A citation that resolves to authentic matching text but whose excerpt does not support the associated claim is recorded as unsupported/unverified or routed for review; source integrity cannot upgrade claim support.
|
||||
- Knowledge-only, web-only, unavailable search, unknown edition, and mismatched text produce distinct non-verified states.
|
||||
- Same clause number but different edition/text produces conflict, not agreement.
|
||||
- Restart/replay restores all batch metadata, exact citation refs, human resolution, and snapshot hashes.
|
||||
- Mutation of a stored batch or its linked source data is detected by audit verification when mutable database rows and adjacent hashes are changed together.
|
||||
- Source withdrawal/takedown updates current access according to its retention rule while retaining a permitted non-content history event and preserving document/version references.
|
||||
- Unauthorized actor cannot read another project's evidence batch or retrieve private source text through an audit command.
|
||||
- Existing malformed/model-generated network output cannot satisfy the real-search requirement.
|
||||
- **Verification:** Domain and application tests prove state invariants, persistence replay, source validation, and project isolation; the command-bus integration proves the public RDM command path enforces them.
|
||||
|
||||
### U7. Add structured citations to conversation, documents, and audit views
|
||||
|
||||
- **Goal:** Present one stable citation object consistently in generated answers, document content, preview/export, and audit inspection.
|
||||
- **Requirements:** R2, R7-R9.
|
||||
- **Dependencies:** U6.
|
||||
- **Files:** `Agent-System-RDM/internal/domain/`; `Agent-System-RDM/internal/rdmapp/`; `Agent-System-RDM/plugins/rdm/plugin.go`; `Agent-System-RDM/web/app.js`; `Agent-System-RDM/web/index.html`; `Agent-System-RDM/web/app.css`; `Agent-System-RDM/web/workbench_test.mjs`; `Agent-System-Frontend/src/`; `Agent-System-Frontend/test/`; `Agent-System-Documents/docs/proposals/` if a shared renderer/API extension is required.
|
||||
- **Approach:** Bind claim spans to citation IDs; render concise regulation/edition/clause/status marks with expandable exact excerpt and authorized source details. Persist citation IDs and evidence revisions in document versions and exports. Mark citations stale when a later corpus revision changes status or text, but preserve the original basis and require explicit review before refreshing it. Use existing RDM audit workspace/read-model patterns for source history rather than introducing a new write authority.
|
||||
- **Patterns to follow:** Existing RDM command-bus UI, three-pane audit workspace and shared snapshot rules, document citation/trace contracts, and UI design tokens/components in the consuming frontend.
|
||||
- **Test Scenarios:**
|
||||
- An answer with two regulatory claims renders two distinct citation marks linked to their claim spans and correct clause excerpts.
|
||||
- A generated document stores the citation and pinned edition; preview/export preserves it across reload.
|
||||
- A later corpus update marks the citation for review without mutating the saved document or historic audit batch.
|
||||
- A user without source-text disclosure permission sees the permitted metadata/redaction reason but not restricted excerpt or original content.
|
||||
- Missing or invalid citation IDs are surfaced as unverified and cannot be rendered as valid legal references.
|
||||
- **Verification:** Browser and document round-trip tests prove citation persistence, navigation, redaction, stale marking, and export consistency.
|
||||
|
||||
### U8. Validate composed deployment, recovery, privacy, and release readiness
|
||||
|
||||
- **Goal:** Prove the complete local RDM + regulations component works with recoverable data/index lifecycle and protected evidence.
|
||||
- **Requirements:** R1-R13.
|
||||
- **Dependencies:** U1-U7, U9.
|
||||
- **Files:** `Agent-System-KB-Regulations/deploy/`; `Agent-System-KB-Regulations/docs/operations/`; `Agent-System-KB-Regulations/tests/integration/`; `Agent-System-RDM/tests/integration/`; `Agent-System-Dev/tests/`; `Agent-System-Dev/PROJECT.md`; `Agent-System-Dev/` component pins and composition configuration.
|
||||
- **Approach:** Pin compatible component revisions; provision a disposable local corpus/database; build a new index revision; run dual-source and citation flows end-to-end; exercise backup/restore, source/index rebuild, provider/parser outages, and authorization. Keep legal source data and secrets outside test output and source-control history. Separate local test acceptance from deployment and business/legal approval.
|
||||
- **Patterns to follow:** Existing Dev composition verification, RDM PostgreSQL and audit replay tests, fixed component pins, and resource/project authorization tests.
|
||||
- **Test Scenarios:**
|
||||
- A full regulatory question returns both channel records, exact cited clause, claim mapping, and audit-batch replay through the composed product.
|
||||
- One channel is deliberately disabled and the UI/agent reports degraded verification without presenting a green dual-source result.
|
||||
- Backup/restore followed by index rebuild preserves corpus revision hashes and historical citation resolution.
|
||||
- Cross-project and restricted-source access cases are denied/redacted through the real command/API composition.
|
||||
- MinerU/search credentials are absent from client assets, logs, command output, test fixtures, and audit exports.
|
||||
- Credentials are injected per environment, scoped to the required component, and can be rotated/revoked without changing source or leaving old credentials usable.
|
||||
- **Verification:** Exact composition tests and security/recovery checks pass on the pinned candidate; release, deployment, and user/legal acceptance are explicitly recorded as separate later gates.
|
||||
|
||||
### U9. Publish the shared regulations retrieval and search extension contract
|
||||
|
||||
- **Goal:** Provide an authorized public integration surface for RDM to query the shared read-only legal corpus and perform real web search without misusing owner-scoped project knowledge APIs.
|
||||
- **Requirements:** R1, R6, R8, R9, R11, R12.
|
||||
- **Dependencies:** U2 for stable identifiers and evidence schema; can be designed alongside U3-U5.
|
||||
- **Files:** `Agent-System-Documents/docs/proposals/`; applicable base-repository extension contracts under `Agent-System-Backend/pkg/extension/`; base-repository contract tests.
|
||||
- **Approach:** First verify whether an existing public Host or API contract can express shared corpus retrieval with revision pinning, stable source-node references, excerpt disclosure policy, and audit provenance, plus access to the knowledge component's real-search provider with minimized query input and evidence provenance. Do not use the existing owner-scoped project `KnowledgeSearch` as a substitute. If it cannot represent these capabilities, document the scenario, required public surface, reason existing registration points do not compose, and compatibility plan in the base proposal process; implement/release the base contract before RDM consumes it. No backend-internal import or private credential bypass is allowed. U5 owns search-provider behavior; U9 owns only the public contract and compatibility tests; U6 owns the RDM consumer adapter and orchestration.
|
||||
- **Patterns to follow:** RDM's extension boundary and approved base-extension proposal process; versioned public command/Host contracts and cross-repository compatibility tests.
|
||||
- **Test Scenarios:**
|
||||
- A consumer queries a pinned shared corpus revision and receives stable regulation/edition/node IDs, permitted excerpt, locator, hashes, and disclosure state.
|
||||
- An unauthorized or unsupported request cannot access restricted source text or use a project ID to widen shared corpus access.
|
||||
- Search receives only permitted minimized query fields and returns provider/query/result provenance; provider failure remains a non-verified result.
|
||||
- Compatibility tests prove the released base surface is consumable by the pinned RDM adapter without importing backend internals.
|
||||
- **Verification:** A versioned public contract and compatibility tests exist before U6; if base changes are needed, RDM integration uses only the released compatible contract. This unit does not implement a second provider, fetcher, or RDM adapter.
|
||||
|
||||
---
|
||||
|
||||
## Verification Contract
|
||||
|
||||
| Gate | Evidence required | Applies to |
|
||||
|---|---|---|
|
||||
| Corpus admission | Source hashes, source/rights inventory, schema/data reconciliation, quarantined-record report | U1, U2 |
|
||||
| Parser/chunk quality | Golden fixtures for clauses, paragraphs, headings, lists, tables, OCR, locators, and provenance; no lost or invented source text | U3 |
|
||||
| Retrieval quality | Labeled set with exact/semantic queries; report retrieval, edition, locator, stale-source, and summary-vs-source behavior | U4 |
|
||||
| Search evidence | Provider search, minimized query/result metadata, fetched source, source policy, SSRF negative cases, hash and excerpt/locator verification | U5, U9 |
|
||||
| RDM invariants | Dual-source state matrix, event replay, authorization denial/redaction, tamper-evidence verification, rights-aware withdrawal, command-bus tests | U6 |
|
||||
| User-visible citations | Browser/document round trip, stable source navigation, permissions, stale citation display, export | U7 |
|
||||
| Composition/recovery | Fixed component pins; full-path tests; disposable DB backup/restore and rebuild; secret lifecycle and leak checks | U8, U9 |
|
||||
| Delivery trust | Current target synchronization, independent review, and required exact-head CI/REPLAY evidence under each repository's delivery policy | All release candidates |
|
||||
|
||||
Planning does not run these tests. Implementers should use each target repository's current authoritative test commands and policies when the work starts. The three uninitialized Dev submodules reported by precheck must be safely materialized before a future composition build; no submodules were changed for this plan.
|
||||
|
||||
## Definition of Done
|
||||
|
||||
- U1-U9 are complete or explicitly deferred with owner and rationale; no unresolved launch-blocking rights, source identity, or extension-contract decision remains.
|
||||
- The published corpus release is reproducible from approved source assets, versioned metadata, parser/chunker versions, and evaluation record.
|
||||
- Every retrieval result contains stable source-node and revision references; exact excerpts resolve independently of vector-index contents.
|
||||
- Real web search and knowledge-base evidence are independently recorded, and dual-source status cannot be inferred from model output or clause-number equality alone.
|
||||
- Conversation, document, and audit citations share the same immutable evidence identities and enforce RDM project/resource permissions.
|
||||
- Required component and composition checks pass on exact pinned revisions; review, CI, deployment, and business acceptance are reported as distinct states.
|
||||
- No source assets, secrets, or abandoned experimental ingestion/index outputs are left in Git or the final product artifact.
|
||||
- Published evidence tampering is detectable; confidential project context is not sent to external search by default; fetch redirects and DNS resolution cannot reach private/reserved network targets.
|
||||
|
||||
## Appendix
|
||||
|
||||
### Existing Evidence and Integration Anchors
|
||||
|
||||
- RDM requirements: `../Agent-System-RDM/docs/requirements/01-用户需求与系统需求.md` (`UR-14`, `SR-F3`, `SR-N4`); `../Agent-System-RDM/docs/requirements/02-产品概念与形态定义.md` (shared pgvector regulations library); `../Agent-System-RDM/docs/requirements/03-产品设计方案.md` (M11 dual-channel requirements and local regulations storage).
|
||||
- Current RDM flow: `../Agent-System-RDM/internal/rdmapp/regcheck.go` uses host knowledge search and model-proposed URLs; `../Agent-System-RDM/internal/rdmapp/regfetch.go` fetches, compares excerpts, and stores content-addressed network snapshots; `../Agent-System-RDM/internal/domain/regcheck.go` records dual-channel claims but currently compares clause identity more narrowly than this plan requires.
|
||||
- Current RDM integration boundary: `../Agent-System-RDM/AGENTS.md` requires extension Host use and prohibits importing backend internals; missing base capabilities require a base proposal and public extension.
|
||||
- Prior platform direction: `modules/documents/docs/proposals/2026-09-29-system-skeleton-design-and-plan.md` envisioned a future regulations plugin and a pluggable local/vector RAG pipeline. This plan narrows ownership: the new repository owns reusable corpus/retrieval; RDM retains its product plugin and audit/UI flows.
|
||||
- MinerU references: `https://mineru.net/apiManage/docs` and `https://mineru.net/apiManage/limit`. Provider quota and file limits are time-sensitive and must be rechecked before implementation.
|
||||
- Current regulations input candidate: `../Agent-System-Regulations/manifest.json` and `../Agent-System-Regulations/regulations_db.dump`. Presence and manifest counts do not verify rows, licensing, raw-source completeness, or legal effectivity.
|
||||
@@ -0,0 +1,74 @@
|
||||
# 法规结构化引用契约(U7)
|
||||
|
||||
状态:实施依据;owner:weichen;来源:`docs/superpowers/plans/2026-10-18-regulations-knowledge-base-plan.md` KTD11、U7。
|
||||
范围:Agent-System-RDM 命令与读模型(写方),Agent-System-Frontend 审计工作区与驾驶舱阅读器(读方)。
|
||||
RDM 证据批(U6,RDM PR #434,合入 703e41d)是唯一事实来源;引用只是批的派生视图,不另设写权威。
|
||||
|
||||
## 1. 引用对象 `CitationView`
|
||||
|
||||
引用 ID:`cit-` + sha256(batchId, corpusRevision, editionId, nodeId, kbExcerptStart, kbExcerptEnd, web captureId) 的前 12 位十六进制。
|
||||
同一证据批、同一配对得到同一 ID;批不可变,故引用不可变。
|
||||
|
||||
| 字段 | 类型 | 含义 |
|
||||
|---|---|---|
|
||||
| `id` | string | 引用 ID;未知或无效 ID 也返回对象,`state = "invalid"` |
|
||||
| `batchId` | string | 来源证据批 |
|
||||
| `claim` | string | 被支撑的主张文本 |
|
||||
| `state` | string | 批的 KTD12 状态:`verified` / `single_source` / `degraded` / `edition_unresolved` / `conflict` / `unverified` / `not_applicable`;另有 `invalid`(ID 无法解析) |
|
||||
| `stale` | bool | 后续语料修订改变了该条款文本或效力状态,待人工复核 |
|
||||
| `staleReason` | string | 如 `node_text_changed`、`legal_status_changed`、`edition_superseded` |
|
||||
| `regulationId` / `editionId` / `nodeId` | string | 稳定 ID |
|
||||
| `docNo` / `title` / `editionLabel` / `legalStatus` / `clauseNo` | string | 展示用元数据 |
|
||||
| `headingPath` | string[] | 章节路径 |
|
||||
| `corpusRevision` | string | 钉住的语料修订 |
|
||||
| `excerpt` | string | 原文片段;披露不允许或调用者无权查看原文时省略 |
|
||||
| `excerptStart` / `excerptEnd` | int | 片段在节点原文中的字节偏移 |
|
||||
| `nodeSha256` | string | 节点原文哈希 |
|
||||
| `disclosure` | string | `full` / `excerpt` / `metadata_only` / `withheld` |
|
||||
| `redactionReason` | string | 省略原文时的原因(如 `withheld_by_rights`、`metadata_only`、`no_source_text_permission`、`source_withdrawn`) |
|
||||
| `web` | object | `{url, finalUrl, captureId, contentSha256, official, fetchedAt, excerpt?, excerptStart?, excerptEnd?}`;摘录同样受披露与撤回约束 |
|
||||
| `manifestSha256` | string | 批封存清单哈希 |
|
||||
|
||||
`invalid` 与除 `verified` 以外的状态都不得渲染成有效法律依据(界面显示“未核验引用”或对应状态文案)。
|
||||
|
||||
## 2. 对话回答 `rdm.reg.answer`
|
||||
|
||||
请求:`{projectId, claims: [{claim, topic?, docNo?, clauseNo?, batchId?}]}`。有 `batchId` 时复用已有批(须属同一项目),否则按 U6 流程新建批。
|
||||
响应:
|
||||
|
||||
```json
|
||||
{
|
||||
"segments": [{"text": "主张一的文字", "citationId": "cit-…"}, {"text": ";"}, {"text": "主张二的文字", "citationId": "cit-…"}],
|
||||
"citations": [CitationView, …],
|
||||
"markdown": "主张一的文字[1];主张二的文字[2]\n\n[1] GB 9706.1-2020 §4.2(现行)——已核验\n[2] …"
|
||||
}
|
||||
```
|
||||
|
||||
`segments` 顺序拼接即完整回答;带 `citationId` 的片段即主张跨度。`markdown` 供纯文本通道(对话、工作台卡片)直接展示。
|
||||
|
||||
## 3. 文档与导出
|
||||
|
||||
- 章节正文可含行内标记 `[cit-xxxxxxxxxxxx]`(与 `[slc-x]` 同类)。写入章节版本时把引用钉住为
|
||||
`{id, batchId, corpusRevision, editionId, nodeId}` 存入版本(追加事件,重放可恢复);未知 ID 照样记录并在读取时报告 `invalid`。
|
||||
- `rdm.cockpit.node`(章节)新增 `citations: CitationView[]`,正文块保留原标记,由前端渲染。
|
||||
- 导出(docx 与导出报告)保留标记位置的编号,并附“引用”清单:文号、版本、条款、效力状态、核验状态、语料修订;原文片段遵守披露规则。
|
||||
|
||||
## 4. 过期标记 `rdm.reg.citation.check` / `rdm.reg.citation.review`
|
||||
|
||||
- `check {projectId, citationId? , sectionId?}`:经 `RegulationsHost` 查询当前语料修订中同一节点;若节点哈希或效力状态变化、版本被替代,
|
||||
追加“引用过期”事件,`stale = true`;不修改原证据批,也不修改已保存的文档版本。
|
||||
- `review {projectId, citationId, decision: keep|refresh, note}`:人工复核。`refresh` 需新建证据批并在新的章节版本中引用新 ID;原依据保留可查。
|
||||
|
||||
## 5. 审计读模型
|
||||
|
||||
- `rdm.inspect.tree kind=regs`:根层列出证据批 `{kind: "reg-batch", id, title: topic, state}`;`parent=<batchId>` 列出其引用
|
||||
`{kind: "reg-citation", id, title: "<docNo> <clauseNo>", state}`。
|
||||
- `rdm.inspect.object kind=reg-batch`:`{title, state, stateReasons, legStates, seal: {state, keyId, manifestSha256}, citations: CitationView[], resolutions}`;
|
||||
`kind=reg-citation`:`{title, citation: CitationView}`。
|
||||
- 项目授权沿用既有检查;跨项目读取拒绝。没有原文查看权限的调用者只得到元数据与 `redactionReason`。
|
||||
|
||||
## 6. 前端呈现(Agent-System-Frontend)
|
||||
|
||||
- 审计工作区新增“法规核验”树标签(`kind=regs`),批与引用详情展示状态、腿状态、封存、引用元数据与可展开原文片段(受披露约束)。
|
||||
- 驾驶舱阅读器把正文中的 `[cit-…]` 渲染为编号引用标记,点击展开元数据与原文片段;`invalid` 与非 `verified` 状态用明确的未核验样式;`stale` 显示“待复核”。
|
||||
- 遵守 Dev 根目录 `DESIGN.md`:令牌、`mk-*` 动效、`@ui` Collapsible,禁止 `<details>`。
|
||||
@@ -0,0 +1,106 @@
|
||||
# 法规语料来源、内容与发布权利盘点(U1)
|
||||
|
||||
- 计划:[法规知识库建设方案与实施计划](../plans/2026-10-18-regulations-knowledge-base-plan.md) U1
|
||||
- 盘点日期:2026-10-18;执行者:host(只读调查);来源等级:SELF(本地实测,可按“复核方法”重放)
|
||||
- 结论摘要:dump 完整且与 manifest 一致;2,878/2,907 份原件存在且哈希一致;**当前没有任何文档满足发布条件**——
|
||||
全部法律状态为自动判定、生效日期全部缺失、权利未经确认。按身份/原件/状态规则自动筛出的 233 份仅是“待人工审核候选”,
|
||||
其余 2,674 份进入隔离。U2 起的开发与评测只在本地一次性库中使用候选子集,不发布语料。
|
||||
|
||||
## 1. 输入对象
|
||||
|
||||
| 对象 | 值 |
|
||||
|---|---|
|
||||
| 目录 | `../Agent-System-Regulations`(非 Git 仓,只读) |
|
||||
| `manifest.json` | 2026-09-11 生成;声明 2,907 文档 / 312,919 chunk / 279,184 node;dump sha256 `27ac5cf5…a1141a64` |
|
||||
| `regulations_db.dump` | PostgreSQL 16.15 custom 格式(gzip),1,194,119,185 字节;实测 sha256 `27ac5cf538efe47232226a606ca0c1e70c33d5c3b488764c5d6be712a1141a64`,与 manifest 一致 |
|
||||
| `.regulations/` | 23G;`library/` 2,878 文件、`intake/` 仅 `.DS_Store`、`quarantine/` 179 文件、`work/` 2,912 个以 sha256 命名的 MinerU 输出目录(`full.md`、`content_list.json`、`parts/`) |
|
||||
|
||||
## 2. 方法
|
||||
|
||||
1. `pg_restore --list` 检查目录(245 条 TOC、23 张表、扩展 `vector` 与 `pg_trgm`)。
|
||||
2. 在一次性容器 `pgvector/pgvector:pg16`(仅绑定 `127.0.0.1`,dump 只读挂载)中 `pg_restore --no-owner -j 4`,无错误。
|
||||
3. 对库内 2,907 条 `reg_documents` 逐一读取原件计算 sha256 并比对;遍历 `library/intake/quarantine` 找出库外文件。
|
||||
4. 以 SQL 规则分类(第 5 节),每文档分类清单导出到仓外受控路径(见第 7 节)。
|
||||
5. 盘点结束后删除容器与临时数据(见第 8 节);原始目录未写入。
|
||||
|
||||
## 3. 结构映射与计数核对
|
||||
|
||||
| 源表 | 行数 | 含义 | 映射到新模型(U2) |
|
||||
|---|---:|---|---|
|
||||
| `reg_documents` | 2,907 | 一文件一行:`doc_id`、`sha256`(唯一)、`file_path`、`kind`、`doc_no`、`title`、`status`、`effective_date`… | `source_asset`(文件、哈希)+候选 `regulation_identity`/`regulation_edition`(须人工确认) |
|
||||
| `reg_nodes` | 279,184 | 树:`parent_id`、`level`、`node_kind`、`section_no`、`title`、`heading_path`、`content`、`page_start/end`、`sort_order` | `legal_node` 候选;文本须由解析输出重建并记哈希 |
|
||||
| `reg_chunks` | 312,919 | `grain`=clause 179,202 / section 133,717;`embedding vector(1024)`、`tsv`、`cite_key` | 仅作参考;新库重新生成 chunk 与向量(无模型来源记录) |
|
||||
| `reg_doc_relations` | 1,731 | `replaces` 1,730(解析到目标文档 91)、`replaced_by` 1 | 版本关系候选,须人工核对 |
|
||||
| `reg_ingest_jobs` / `_events` | 2,953 / 35,248 | `done` 2,911、`unprocessable` 42 | 解析历史线索,不迁移 |
|
||||
| 其余 16 张(`asset_*`、`*_legacy`、`reg_catalog_entries`、`reg_clause_links`、`reg_doc_aliases`、`reg_normative_refs`、`staff_*` 等) | 0 | 空表 | 不迁移 |
|
||||
|
||||
计数与 manifest 三项完全一致;manifest 的 14,655 文件数与目录实测不符(实测 library+quarantine 共 3,057 个文件,`work/` 下为解析产物),以实测为准。
|
||||
|
||||
## 4. 原件可用性与内容质量
|
||||
|
||||
| 检查 | 结果 |
|
||||
|---|---|
|
||||
| 原件存在且 sha256 一致 | 2,878(全部位于 `library/`) |
|
||||
| 原件缺失 | 29(库记录在 `intake/`,磁盘无文件;`work/` 中仍有其解析输出) |
|
||||
| 哈希不一致 | 0 |
|
||||
| 二进制重复 | 库内 0(`sha256` 唯一约束);`quarantine/` 179 个文件中 135 个与库内文件重复、44 个独有(含 31 个 mp4、rar/zip/cdr 等不可解析格式) |
|
||||
| 文件类型 | pdf 2,656、docx 165、doc 74、xlsx 9、md 2、xls 1 |
|
||||
| `jurisdiction`、`source_url`、`effective_date` | 全部为空 |
|
||||
| `kind_source`、`status_source` | 全部为 `auto`(无人工审核) |
|
||||
| `doc_no` | 656 份为空;169 个编号被 607 份文档共用,如 `GB/T1.1-2009` 被 70 份不同文档使用(实为前言引用的起草规则),且文件名由该错误编号生成 |
|
||||
| 标题 | 2,000+ 份为封面泛化标题(如“中华人民共和国医药行业标准”)、图片占位或 LaTeX 片段;168 份带 Markdown 标记 |
|
||||
| 节点 | 70,254 无页码;102,696 无条款号;56,435 内容为空(标题节点为主);`table` 仅 3 个(表格结构基本丢失) |
|
||||
| 向量 | 1024 维,未记录模型、版本或分块策略 |
|
||||
|
||||
结论:现有库可作为**解析线索与开发样本**,不能直接作为权威语料导入。U2/U3 以原件 + 新解析重建节点,现有节点/向量仅用于对照。
|
||||
|
||||
## 5. 准入分类规则
|
||||
|
||||
隔离标记(任一命中即隔离,不计入候选):
|
||||
|
||||
| 标记 | 规则 | 命中 |
|
||||
|---|---|---:|
|
||||
| `Q-SRC-MISSING` | 原件缺失 | 29 |
|
||||
| `Q-KIND-UNKNOWN` | `kind = unknown` | 452 |
|
||||
| `Q-DOCNO-COLLISION` | 同一 `doc_no` 对应多个文件 | 607 |
|
||||
| `Q-GENERIC-TITLE` | 去除 `**` 后标题为封面泛称、图片/公式占位或少于 6 字 | 2,222 |
|
||||
| `Q-STATUS-UNKNOWN` | `status = unknown` | 446 |
|
||||
|
||||
权利类别(候选判断,**均待语料维护者确认**,确认前一律不发布):
|
||||
|
||||
| 类别 | 判定 | 依据与拟定展示策略 | 总数 | 候选 |
|
||||
|---|---|---|---:|---:|
|
||||
| `R-OFFICIAL` | `kind` ∈ law/rule/notice/catalog/guidance | 国家机关法律法规、规章、规范性文件;《著作权法》第五条不适用保护的候选依据。拟:全文可内部检索与引用展示,需注明发布机关 | 336 | 193 |
|
||||
| `R-STD-MANDATORY` | 编号 `GB`/`YY`(非 /T) | 强制性标准官方平台可公开阅读,但再分发受限。拟:内部检索,引用展示短摘录,导出受限 | 31 | 3 |
|
||||
| `R-STD-LICENSED` | 编号 `GB/T`/`YY/T` | 推荐性标准,版权归标准出版方。拟:仅元数据 + 定位 + 短摘录,取得许可前不展示全文 | 2,079 | 31 |
|
||||
| `R-STD-FOREIGN` | 标题含 ISO/IEC/ASTM/EN/ANSI/AAMI 等 | 境外标准组织版权。拟:仅元数据,许可确认前不入检索正文 | 230 | 6 |
|
||||
| `R-UNKNOWN` | 以上皆非 | 身份不明,隔离 | 231 | 0 |
|
||||
|
||||
合计:候选 233,隔离 2,674。所有候选仍需人工完成法律身份、版本、生效状态与权利确认后才可进入 U4 发布。
|
||||
|
||||
## 6. U1 测试场景对应
|
||||
|
||||
| 计划场景 | 结果 |
|
||||
|---|---|
|
||||
| 有效样本映射到唯一源哈希与明确的来源/权利记录 | 样本 `doc-fb5793f2a564-fb5793f2`《医疗器械使用质量监督管理办法》→ `library/law/doc-fb5793f2a564__…__fb5793f2.docx`,sha256 `fb5793f2…f67f6d9f` 实测一致;类别 `R-OFFICIAL`、无隔离标记;树为 chapter → article,正文与原文一致,页码缺失(docx 来源) |
|
||||
| 重复二进制去重但不合并不同法律身份/版本 | 库内无重复二进制;隔离区 135 个重复文件按哈希识别为副本,不新建身份。反向问题:同一 `doc_no` 被多份不同文件共用,已以 `Q-DOCNO-COLLISION` 隔离,不按编号合并 |
|
||||
| 原件缺失、无效行、版本不明、权利未知时隔离且不计入可发布数 | 第 5 节规则;可发布数为 0,候选 233 仅表示可进入人工审核 |
|
||||
|
||||
## 7. 仓外产物
|
||||
|
||||
| 产物 | 位置 | sha256 |
|
||||
|---|---|---|
|
||||
| 每文档分类清单(元数据:`doc_id`、`sha256`、路径、kind、status、doc_no、权利类别、隔离标记;无正文) | `~/.cache/agent-system-dev/regkb/u1-classification-20261018.tsv`(0600) | `3c801f74006b7919e45247f91ede704d35d9110a1eb5f3f50abdc701574360ee` |
|
||||
|
||||
清单不入 Git;U2 的导入工具从原件与该清单重新生成新仓的语料发布清单(manifest),并重新计算哈希。
|
||||
|
||||
## 8. 复核方法与限制
|
||||
|
||||
复核:在任意一次性 `pgvector/pgvector:pg16` 容器中只读挂载 dump 恢复,执行第 3–5 节的计数与分类 SQL,并对 `reg_documents.file_path` 重新计算 sha256。
|
||||
|
||||
未验证/待决:
|
||||
|
||||
- 法律状态、生效日期、版本替代关系与权利类别全部未经人工确认;第 5 节规则只用于筛选审核候选。
|
||||
- 推荐性标准与境外标准的许可、可展示摘录长度与导出限制,需语料维护者(计划 A3)或用户裁定,属于发布阻塞项。
|
||||
- 29 份缺失原件是否可从其他来源补齐未调查。
|
||||
- 生产导入路径、备份拓扑、语料 owner 与更新审批角色未定(计划“Dependencies and Open Questions”)。
|
||||
+1
-1
Submodule modules/backend updated: 276dd73824...56a7f9f440
+1
-1
Submodule modules/documents updated: e2f5729e8f...5bb487795c
+1
-1
Submodule modules/frontend updated: 426d1044ac...50ec83657a
@@ -0,0 +1,54 @@
|
||||
# 法规知识库组合门禁(U8)
|
||||
|
||||
在固定组件修订上验证 RDM + 法规知识库(KB-Regulations)的本地组合:数据与索引可恢复、
|
||||
双源与引用流程可用、凭据不进入客户端制品。对应
|
||||
[法规知识库计划](../../../docs/superpowers/plans/2026-10-18-regulations-knowledge-base-plan.md) 的 U8
|
||||
与 Verification Contract 的 Composition/recovery 行;引用对象见
|
||||
[法规引用合同](../../../docs/superpowers/specs/2026-10-18-regulations-citation-contract.md)。
|
||||
|
||||
## 固定组件
|
||||
|
||||
`components.pin` 只有两个键,均为 40 位 hex,`run.sh` 逐行解析、从不执行:
|
||||
|
||||
- `rdm_sha`:Agent-System-RDM main(含 U6、U7 与 kbreg 组合)。
|
||||
- `kb_sha`:Agent-System-KB-Regulations main(含 provider 与 U8 恢复测试)。
|
||||
|
||||
`run.sh` 先核对两个检出的 HEAD 等于 pin,再核对 RDM 检出中
|
||||
`pins/agent-system-kb-regulations` gitlink 是 KB 检出里 `kb_sha` 的祖先(RDM 编译所用 KB 代码包含在被测修订中)。
|
||||
Dev 侧 Backend/Documents/Frontend/UI 的 gitlink 由本仓 `modules/` 固定,见 PROJECT.md「法规知识库组合」。
|
||||
|
||||
## 前置条件
|
||||
|
||||
- 一次性 PostgreSQL(带 pgvector),连接串放在 `KBREG_TEST_DATABASE_URL`;PATH 上有 `pg_dump`、`pg_restore`。
|
||||
可用 KB 仓 `scripts/test-pg-local.sh` 起临时库。门禁会写入该库,不要指向任何真实数据。
|
||||
- `SVC_RDM_SRC_DIR`:RDM 检出,位于 `rdm_sha`,submodule 已递归物化。
|
||||
- `KB_SRC_DIR`:KB-Regulations 检出,位于 `kb_sha`,submodule 已物化。
|
||||
- Go 与 Node(RDM 测试及客户端制品构建所需)。
|
||||
- 客户端制品扫描需要已构建的 RDM 产品前端制品(RDM 检出的 `.build/product/frontend/dist`),
|
||||
或用 `REGKB_SCAN_DIRS` 指定待扫目录(空格分隔)。服务端二进制 `bin/` 不是客户端制品,
|
||||
且携带 `KBREG_*` 变量名,因此不扫描。
|
||||
|
||||
## 用法
|
||||
|
||||
```bash
|
||||
KBREG_TEST_DATABASE_URL=... SVC_RDM_SRC_DIR=/path/to/rdm KB_SRC_DIR=/path/to/kb \
|
||||
make test-regulations-kb
|
||||
```
|
||||
|
||||
缺任一变量时直接以非零退出并指出变量名,不运行任何阶段。每个阶段打印 `PASS <阶段>` 或
|
||||
`FAIL <阶段>`,任一失败则整体非零退出。脚本不回显 `KBREG_TEST_DATABASE_URL` 或任何凭据值。
|
||||
|
||||
## 各阶段证明什么
|
||||
|
||||
| 阶段 | 命令 | 对应 U8 场景 |
|
||||
|---|---|---|
|
||||
| `kb-test-pg` | `make -C "$KB_SRC_DIR" test-pg` | provider 组合链;dump/restore 后重建索引仍保持语料修订哈希与历史引用解析;provider/解析器不可用;凭据注入、轮换与撤销 |
|
||||
| `rdm-kbreg` | `GOWORK=off go test -count=1 ./plugins/kbreg/...`,以及 `-run 'Composed\|RegCite\|Citation\|RegCheck\|RegBatch\|RegAudit'` 覆盖 `./internal/rdmapp/...`、`./plugins/rdm/...` | 完整法规问答的双通道记录、条款引用与审计批次重放;缺一通道时报告降级而非双源通过;保密词留在本地;凭据不进入输出;审计封印校验 |
|
||||
| `client-asset-secret-scan` | 扫描 `REGKB_SCAN_DIRS`(缺省仅为 RDM 产品前端制品 `.build/product/frontend/dist`;服务端二进制 `bin/` 不是客户端制品,携带 `KBREG_*` 变量名,不扫描) | 凭据不出现在客户端制品:任何文件含字符串 `KBREG_`,或含环境中非空 `KBREG_*KEY*`、`KBREG_*TOKEN*`、`KBREG_DATABASE_URL` 的值即失败;只打印文件路径与变量名。没有可扫目录时失败 |
|
||||
|
||||
跨项目与受限来源的拒绝/脱敏场景归入 `rdm-kbreg` 阶段所选的 RDM 命令总线测试;具体用例以固定 RDM 修订中的测试为准。
|
||||
|
||||
## 不在本门禁范围
|
||||
|
||||
- 真实网络搜索、嵌入与 MinerU 调用:NOT_RUN,待 owner 批准外部调用后另行执行。
|
||||
- 部署、版本发布与业务/法务验收:均为后续独立门禁,本门禁通过不代表其中任何一项完成。
|
||||
@@ -0,0 +1,6 @@
|
||||
# 法规知识库组合门禁的固定组件(U8)。只接受 rdm_sha、kb_sha 两个键,值为 40 位 hex。
|
||||
# run.sh 逐行解析本文件,不执行、不 source。升级走 PR。
|
||||
# rdm_sha:RDM main,含 U6、U7 与 kbreg 组合。
|
||||
# kb_sha:KB-Regulations main,含 provider 与 U8 恢复测试;须包含 RDM pins/agent-system-kb-regulations。
|
||||
rdm_sha=ece91dab9f23628be54a91e846389cb3753b88dd
|
||||
kb_sha=5dddad2ae58e7d0d7fffc95464e80fa0040d5e08
|
||||
Executable
+140
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env bash
|
||||
# 法规知识库组合门禁(U8)。缺环境直接失败,不静默跳过。
|
||||
# 不回显任何 KBREG_* 值;扫描结果只打印文件路径与变量名。
|
||||
set -euo pipefail
|
||||
|
||||
here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
pin="${REGKB_PIN:-$here/components.pin}"
|
||||
|
||||
# 与 scripts/fetch-rdm-pin.sh 同规则:只认已知键、40 位 hex,不执行 pin 文件。
|
||||
[ -f "$pin" ] || { echo "components.pin 不存在:$pin" >&2; exit 1; }
|
||||
declare -A got=()
|
||||
while IFS= read -r line || [ -n "$line" ]; do
|
||||
case "$line" in
|
||||
''|\#*) continue ;;
|
||||
esac
|
||||
case "$line" in
|
||||
*=*) ;;
|
||||
*) echo "components.pin 行格式错误(须为 key=sha)" >&2; exit 1 ;;
|
||||
esac
|
||||
key="${line%%=*}"
|
||||
val="${line#*=}"
|
||||
case "$key" in
|
||||
rdm_sha|kb_sha) ;;
|
||||
*) echo "components.pin 未知键:$key" >&2; exit 1 ;;
|
||||
esac
|
||||
[[ "$val" =~ ^[0-9a-f]{40}$ ]] || { echo "components.pin 的 $key 不是 40 位 hex" >&2; exit 1; }
|
||||
[ -z "${got[$key]:-}" ] || { echo "components.pin 重复键:$key" >&2; exit 1; }
|
||||
got["$key"]="$val"
|
||||
done < "$pin"
|
||||
[ "${#got[@]}" -eq 2 ] || { echo "components.pin 必须同时有 rdm_sha、kb_sha" >&2; exit 1; }
|
||||
rdm_sha="${got[rdm_sha]}"
|
||||
kb_sha="${got[kb_sha]}"
|
||||
|
||||
missing=0
|
||||
for v in KBREG_TEST_DATABASE_URL SVC_RDM_SRC_DIR KB_SRC_DIR; do
|
||||
if [ -z "${!v:-}" ]; then
|
||||
echo "regulations-kb: $v 未设置(组合门禁必需,不静默跳过)" >&2
|
||||
missing=1
|
||||
fi
|
||||
done
|
||||
[ "$missing" -eq 0 ] || exit 2
|
||||
|
||||
rdm_dir="$SVC_RDM_SRC_DIR"
|
||||
kb_dir="$KB_SRC_DIR"
|
||||
|
||||
head_of() { git -C "$1" rev-parse --verify -q HEAD 2>/dev/null || true; }
|
||||
rdm_head="$(head_of "$rdm_dir")"
|
||||
[ "$rdm_head" = "$rdm_sha" ] || { echo "regulations-kb: SVC_RDM_SRC_DIR HEAD=${rdm_head:-<无>},须为 rdm_sha=$rdm_sha" >&2; exit 1; }
|
||||
kb_head="$(head_of "$kb_dir")"
|
||||
[ "$kb_head" = "$kb_sha" ] || { echo "regulations-kb: KB_SRC_DIR HEAD=${kb_head:-<无>},须为 kb_sha=$kb_sha" >&2; exit 1; }
|
||||
|
||||
kb_link="$(git -C "$rdm_dir" rev-parse --verify -q "HEAD:pins/agent-system-kb-regulations" 2>/dev/null || true)"
|
||||
[ -n "$kb_link" ] || { echo "regulations-kb: RDM 检出缺少 pins/agent-system-kb-regulations gitlink" >&2; exit 1; }
|
||||
if ! git -C "$kb_dir" merge-base --is-ancestor "$kb_link" "$kb_sha" 2>/dev/null; then
|
||||
echo "regulations-kb: RDM 的 KB gitlink $kb_link 不是 kb_sha=$kb_sha 的祖先(或 KB 检出缺该对象)" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "regulations-kb: rdm=$rdm_sha kb=$kb_sha(RDM KB gitlink $kb_link 为其祖先)"
|
||||
|
||||
failed=0
|
||||
# 在 if 条件中 set -e 不生效:阶段函数内多条命令须显式 && 串联。
|
||||
stage() {
|
||||
local name="$1"; shift
|
||||
echo "=== stage $name ==="
|
||||
if ( "$@" ); then
|
||||
echo "PASS $name"
|
||||
else
|
||||
echo "FAIL $name"
|
||||
failed=1
|
||||
fi
|
||||
}
|
||||
|
||||
stage_kb() {
|
||||
make -C "$kb_dir" test-pg
|
||||
}
|
||||
|
||||
stage_rdm() {
|
||||
cd "$rdm_dir" &&
|
||||
GOWORK=off go test -count=1 ./plugins/kbreg/... &&
|
||||
GOWORK=off go test -count=1 -run 'Composed|RegCite|Citation|RegCheck|RegBatch|RegAudit' ./internal/rdmapp/... ./plugins/rdm/...
|
||||
}
|
||||
|
||||
stage_scan() {
|
||||
local dirs=() d
|
||||
if [ -n "${REGKB_SCAN_DIRS:-}" ]; then
|
||||
read -r -a dirs <<< "$REGKB_SCAN_DIRS"
|
||||
else
|
||||
for d in "$rdm_dir/.build/product/frontend/dist"; do
|
||||
[ -d "$d" ] && dirs+=("$d")
|
||||
done
|
||||
fi
|
||||
if [ "${#dirs[@]}" -eq 0 ]; then
|
||||
echo "scan: 没有可扫描的客户端制品目录(先构建 RDM 产品以生成 .build/product/frontend/dist,或设置 REGKB_SCAN_DIRS)" >&2
|
||||
return 1
|
||||
fi
|
||||
local secret_vars=() name
|
||||
while IFS= read -r name; do
|
||||
case "$name" in
|
||||
KBREG_*KEY*|KBREG_*TOKEN*|KBREG_DATABASE_URL)
|
||||
[ -n "${!name:-}" ] && secret_vars+=("$name") ;;
|
||||
esac
|
||||
done < <(compgen -e)
|
||||
local tmp rc=0 hits f
|
||||
tmp="$(mktemp)" || return 1
|
||||
for d in "${dirs[@]}"; do
|
||||
if [ ! -d "$d" ]; then
|
||||
echo "scan: 目录不存在:$d" >&2
|
||||
rc=1
|
||||
continue
|
||||
fi
|
||||
echo "scan: $d"
|
||||
hits="$(grep -rlF -e 'KBREG_' -- "$d" || true)"
|
||||
if [ -n "$hits" ]; then
|
||||
while IFS= read -r f; do echo "scan: $f 含字符串 KBREG_" >&2; done <<< "$hits"
|
||||
rc=1
|
||||
fi
|
||||
for name in "${secret_vars[@]}"; do
|
||||
printf '%s\n' "${!name}" | grep -v '^$' > "$tmp" || true
|
||||
[ -s "$tmp" ] || continue
|
||||
hits="$(grep -rlF -f "$tmp" -- "$d" || true)"
|
||||
if [ -n "$hits" ]; then
|
||||
while IFS= read -r f; do echo "scan: $f 含 $name 的值" >&2; done <<< "$hits"
|
||||
rc=1
|
||||
fi
|
||||
done
|
||||
done
|
||||
rm -f "$tmp"
|
||||
echo "scan: 已核对 ${#secret_vars[@]} 个凭据变量:${secret_vars[*]:-<无>}"
|
||||
return "$rc"
|
||||
}
|
||||
|
||||
stage kb-test-pg stage_kb
|
||||
stage rdm-kbreg stage_rdm
|
||||
stage client-asset-secret-scan stage_scan
|
||||
|
||||
if [ "$failed" -ne 0 ]; then
|
||||
echo "regulations-kb: FAIL"
|
||||
exit 1
|
||||
fi
|
||||
echo "regulations-kb: PASS"
|
||||
@@ -0,0 +1,120 @@
|
||||
"""法规知识库组合门禁:components.pin 只接受固定 SHA;run.sh 缺环境直接失败。"""
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
GATE = ROOT / "tests" / "integration" / "regulations-kb"
|
||||
PIN = GATE / "components.pin"
|
||||
RUN = GATE / "run.sh"
|
||||
HEX40 = re.compile(r"^[0-9a-f]{40}$")
|
||||
KEYS = {"rdm_sha", "kb_sha"}
|
||||
REQUIRED = ("KBREG_TEST_DATABASE_URL", "SVC_RDM_SRC_DIR", "KB_SRC_DIR")
|
||||
|
||||
|
||||
def load_pin(text):
|
||||
out = {}
|
||||
for line in text.splitlines():
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
if "=" not in line:
|
||||
raise ValueError("bad pin line")
|
||||
key, value = line.split("=", 1)
|
||||
if key not in KEYS:
|
||||
raise ValueError("unknown pin key")
|
||||
if not HEX40.match(value):
|
||||
raise ValueError("sha must be 40 hex")
|
||||
if key in out:
|
||||
raise ValueError("duplicate pin key")
|
||||
out[key] = value
|
||||
if set(out) != KEYS:
|
||||
raise ValueError("pin keys incomplete")
|
||||
return out
|
||||
|
||||
|
||||
def run_gate(env, timeout=20):
|
||||
base = {"PATH": os.environ.get("PATH", "/usr/bin:/bin")}
|
||||
base.update(env)
|
||||
return subprocess.run(
|
||||
["bash", str(RUN)], cwd=ROOT, env=base, capture_output=True, text=True, timeout=timeout
|
||||
)
|
||||
|
||||
|
||||
class RegulationsKbPinTests(unittest.TestCase):
|
||||
def test_pin_is_two_fixed_shas(self):
|
||||
doc = load_pin(PIN.read_text())
|
||||
self.assertEqual(set(doc), KEYS)
|
||||
for value in doc.values():
|
||||
self.assertRegex(value, HEX40)
|
||||
|
||||
def test_parser_rejects_url_short_sha_and_unknown_key(self):
|
||||
kb = "kb_sha=" + "b" * 40 + "\n"
|
||||
bad = [
|
||||
"rdm_sha=https://example.invalid/repo.git\n" + kb,
|
||||
"rdm_sha=abc\n" + kb,
|
||||
"rdm_sha=" + "a" * 40 + "\n" + kb + "url=" + "c" * 40 + "\n",
|
||||
]
|
||||
for text in bad:
|
||||
with self.assertRaises(ValueError):
|
||||
load_pin(text)
|
||||
|
||||
def test_run_sh_parser_rejects_bad_pins_before_env_check(self):
|
||||
kb = "kb_sha=" + "b" * 40 + "\n"
|
||||
cases = {
|
||||
"rdm_sha=https://example.invalid/repo.git\n" + kb: "不是 40 位 hex",
|
||||
"rdm_sha=abc\n" + kb: "不是 40 位 hex",
|
||||
"rdm_sha=" + "a" * 40 + "\n" + kb + "url=" + "c" * 40 + "\n": "未知键",
|
||||
"rdm_sha=$(touch /tmp/regkb-pwned)\n" + kb: "不是 40 位 hex",
|
||||
kb: "必须同时有",
|
||||
}
|
||||
for text, expect in cases.items():
|
||||
with tempfile.NamedTemporaryFile("w", suffix=".pin", delete=False) as f:
|
||||
f.write(text)
|
||||
path = f.name
|
||||
try:
|
||||
proc = run_gate({"REGKB_PIN": path})
|
||||
finally:
|
||||
os.unlink(path)
|
||||
self.assertNotEqual(proc.returncode, 0, text)
|
||||
self.assertIn(expect, proc.stderr, text)
|
||||
self.assertNotIn("=== stage", proc.stdout)
|
||||
|
||||
def test_run_sh_names_each_missing_variable_without_running_stages(self):
|
||||
proc = run_gate({})
|
||||
self.assertNotEqual(proc.returncode, 0)
|
||||
for name in REQUIRED:
|
||||
self.assertIn(name, proc.stderr)
|
||||
self.assertNotIn("=== stage", proc.stdout)
|
||||
|
||||
for missing in REQUIRED:
|
||||
env = {n: "/nonexistent-fake" for n in REQUIRED if n != missing}
|
||||
proc = run_gate(env)
|
||||
self.assertNotEqual(proc.returncode, 0, missing)
|
||||
self.assertIn(missing + " 未设置", proc.stderr)
|
||||
self.assertNotIn("=== stage", proc.stdout)
|
||||
self.assertNotIn("/nonexistent-fake", proc.stdout + proc.stderr)
|
||||
|
||||
def test_scan_default_excludes_server_bin(self):
|
||||
text = RUN.read_text()
|
||||
loops = [ln.strip() for ln in text.splitlines() if ln.strip().startswith('for d in "$rdm_dir/')]
|
||||
self.assertEqual(len(loops), 1)
|
||||
self.assertIn('"$rdm_dir/.build/product/frontend/dist"', loops[0])
|
||||
self.assertNotIn('"$rdm_dir/bin"', text)
|
||||
|
||||
with tempfile.TemporaryDirectory() as rdm_dir:
|
||||
Path(rdm_dir, "bin").mkdir()
|
||||
Path(rdm_dir, "bin", "rdm").write_text("KBREG_DATABASE_URL\n")
|
||||
script = 'dirs=(); ' + loops[0] + ' [ -d "$d" ] && dirs+=("$d"); done; printf "%s\\n" "${dirs[@]}"'
|
||||
proc = subprocess.run(
|
||||
["bash", "-c", script], env={"PATH": os.environ.get("PATH", "/usr/bin:/bin"), "rdm_dir": rdm_dir},
|
||||
capture_output=True, text=True, timeout=10,
|
||||
)
|
||||
self.assertEqual(proc.returncode, 0, proc.stderr)
|
||||
self.assertEqual(proc.stdout.strip(), "")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user