Files
qinglong/docs/adr/ADR-0355-human-approval-decision-product-gate.md
T

5.3 KiB
Raw Blame History

ADR-0355:强人类认证、摘要绑定的 Approval 决策产品门

  • 状态:Accepted
  • 日期:2026-08-10
  • 关联 RFCQL-RFC-0001 D-05、D-06、D-08、D-13、D-17、D-28、D-75、D-85、D-87、D-157、D-257、D-259、D-260、D-263、D-265、D-266、D-267
  • 关联 ADRADR-0031、ADR-0138、ADR-0353、ADR-0354

背景

MCP 已能列出 Approval 并读取一个经过 redaction contract 的 preview,但仍故意没有写 authority。若把 approve/reject 直接加入同一 MCP 进程,Agent、API credential、Artifact read 和人类决定会混在一个 authority 中;若本机 Owner CLI 只接受 request ID,则人类无法证明决定针对自己实际检查过的 action/preview。Edge 路由器还不能为一次人工决定常驻新的 Web 服务,而 Cluster 也不能为每个决定建立新 Pool 或绕过既有 mTLS/OIDC 管理边界。

决策

  1. Profile-neutral ApprovalDecisionService 只接受强认证 User,允许的 assurance 固定为 multi_factorhardwarelocal_console,并重新执行当前 Project 的 approval.decide Policy。
  2. 决策命令除 request/project/version/decision/reason 外,必须携带完整 expectedActionpermission、action type、action reference、action digest 和 preview digest。服务从 durable Approval 重新读取 canonical binding,任何一项漂移均在写前拒绝。
  3. expectedVersion 固定为 1success 把 allowed Security Audit 与 Approval version 1→2 放在同一 storage transaction。 同一 decision ID、决定、reason 和 User 的重试返回 existing,不重复写 audit;不同语义复用 ID 失败关闭。
  4. 本机产品面是独立 ql3-approval 私有 command-file CLI,提供 approval.inspectapproval.decide。inspect 同时要求 approval.readartifact.read,返回 canonical expectedAction 和有界 redacted previewdecide 必须把该 binding 原样带回。
  5. 本机认证继续复用 POSIX private-path proof、Owner Pepper、active User credential 和 local_console principal。写前复验 command proof/credential fileSQLite Approval repository 又在 BEGIN IMMEDIATE 后、读取或写入任何 Approval 前复验同一 credential fence,从而关闭 revoke 与写事务之间的竞态。认证、Policy、binding、state/fence 失败使用独立 failure event 审计。
  6. MCP 保持纯只读,不 import decision service、不新增 Tool,也不取得 approval.decide。consume、dispatch 和 execute 仍由 各自的受信执行面完成,人工决定不能直接产生外部副作用。
  7. Cluster 复用同一 Profile-neutral service,由 @qinglong/cluster-admin/approval-decision-management 在调用方拥有的 PostgreSQL Pool 上组合现有 Approval repository 与 Project Policy repository。它不建立 listener、Pool、timer 或认证协议; 未来远程 route 必须接在既有强认证管理 transport 后,并在 transport 层重新确认认证。

资源与 Package 裁决

  • Edge/Standalone CLI 是短进程、单 SQLite connection、无后台 timer/listener/cache;未调用时资源为零。
  • Cluster factory 复用调用方 Pool,不创建 per-request Pool,也不改变 HA schema 或连接拓扑。
  • 公共协议归 Runtime Core 的 approved-action/ domainSQLite 短期 authority 归现有 adapter;本机命令归 Local Owner CLI Cluster 组合归 Cluster Admin。没有独立制品、依赖或生命周期理由,因此不新增 workspace package。

被否决方案

  1. qinglong.approval.get 增加 approve/reject:混合 Agent read authority 与 Human write authority。
  2. 决策只带 request ID/version:不能证明人类决定与已检查 preview/action binding 相同。
  3. 交互式 CLI 从 stdin 询问 yes/no:难以审计、重放和自动生成受保护的变更单,且容易被终端注入或默认值误导。
  4. 为 Approval CLI/decision service 新建 package:会制造用户已质疑的微包,没有新的部署或 authority 边界。
  5. 为本切片新建表或队列:现有 Approval/audit/preview schema 已满足 exact binding 与原子决定。
  6. 同时开放通用 consume/execute:会把人类审查与外部副作用重新耦合,越过独立 start/recovery 门禁。

发布边界

本 ADR 完成本机 Owner 的 inspect/decide 产品门和 Cluster 的可复用组合边界,但不声称已开放 Cluster 远程管理 API/UI。 Cluster route 仍须完成 transport principal、独立限流、失败审计、部署配置和端到端 PostgreSQL 测试后才能注册。MCP 永久保持 只读;任何通用消费或执行入口必须另立 ADR。

验证证据

  • Runtime Core 455/455、Local SQLite 209/209、Local Owner CLI 137/137、Cluster Admin 258 pass/2 条件 skip、 PostgreSQL 290 pass/1 条件 skip。
  • package boundary、cluster dependency、edge import 与十二档 artifact 门全部 compatible17 个 package、1004 个源码文件中 978 个位于领域子目录,root 仅 26 个,没有单文件或浅目录微包。
  • 默认 Edge/Standalone Application loaded module 仍为 120MCP 为 203;新增决策语义只有显式 Owner/Cluster composition import 时才加载。Standalone Application AI 为 6,275,925 bytes/639 files,距 6 MiB 上限余 15,531 bytesStandalone MCP 为 9,872,053 bytes/949 files/203 modulesRSS 38,404,096 bytes,均未放宽预算。