6.9 KiB
ADR-0163:原子加密 Tool 成功完成协议
- 状态:Accepted
- 日期:2026-07-26
- 关联:ADR-0156 至 ADR-0162;RFC D-149 至 D-152
背景
ADR-0162 已能在 durable start barrier 后执行首个受信只读 Tool,并返回经过当前 Definition Registry 规范化的内存结果,但该结果还不是可恢复的 durable fact:
- 进程在 adapter 成功后、StepRun 完成前崩溃时,无法证明 exact output 是否已经完成;
- 只更新 StepRun 会让 result、RunEvent 和 mutation ledger 出现部分提交;
- 把明文 output 存入 StepRun、RunEvent 或普通 JSON 会扩大数据库泄露面;
- 只读
retry_safe只能说明重试不会重复副作用,不能重放同一次 exact result。
该缺口必须同时适配单 SQLite 的低配路由设备和 PostgreSQL 多副本节点,且不能为一个 协议继续增加只有单文件的 workspace package。
决策
1. Result Artifact 是密文,不是 StepRun payload
@qinglong/runtime-core/tool-execution-completion 定义三个 exact-shape v1 contract:
qinglong/tool-execution-result-artifact@v1;qinglong/tool-execution-completion@v1;qinglong/tool-execution-completion-command@v1。
成功 output 必须先通过同一 current Tool Definition Registry 规范化,再以 AES-256-GCM 密封。AAD、Artifact digest 和 completion digest 绑定:
- Project、Run、StepRun 与 start barrier;
- Tool、adapter、output digest 与 execution result digest;
- key ID、算法、密文长度和完成时间。
数据库只保存密文 Artifact,不保存 output 明文。output 上限为 256 KiB,Result Artifact JSON 上限为 384 KiB,Completion JSON 上限为 24 KiB。key provider 仍只 返回 owned 32-byte key;加解密持有的 byte buffer 在成功和失败路径都覆零。
2. 成功完成与 StepRun/Run 事实同事务提交
双方言 repository 的 commit(command) 必须在一个事务中完成:
- 读取并复验 exact durable start barrier;
- 复验 start mutation 对应的 Run version/event sequence;
- 锁定并复验当前
runningTool StepRun 与非 terminal Run; - 把 StepRun 原子迁移为
succeeded,且outputRef必须等于 Result Artifact ID; - CAS 递增 Run version/event sequence;
- 插入 RunEvent、StepRunMutation;
- 插入不可变 Result Artifact 与 Completion record。
任一身份、digest、version、event sequence、时间或 output reference 漂移均失败关闭。
同一个 start、Artifact、mutation、event 或 (Run, StepRun, completed version) 不能
绑定到第二组事实。完整命令重放返回 existing;部分相同或内容漂移返回 conflict。
SQLite 使用 BEGIN IMMEDIATE。PostgreSQL 使用既有 SERIALIZABLE 有界重试事务,
并对 StepRun/Run 使用行锁;读取 jsonb barrier 后必须先通过领域 normalizer
规范化,不能依赖 PostgreSQL 保留 JSON 对象键顺序。
3. 表与权限保持追加式
SQLite migration 0061 新增 ToolExecutionCompletions,0062 将 local capability
推进至 v31。PostgreSQL migration pg-0033-tool-execution-completions 新增
ql3.tool_execution_completions,将 control-core 推进至 v32。
单表同时保存 Artifact JSON、Completion JSON、关键 mirror 列、复合唯一约束和到 start barrier、StepRun mutation、RunEvent 的外键。这样避免再为 Result Artifact 创建一个单用途表和一套不完整提交协议。
PostgreSQL ql3_runtime 对该表只有 SELECT, INSERT;admin、Package manager、
Package executor、Worker ingress 与 PUBLIC 均无权限。repository 不提供 update 或
delete。
4. 不新增 package,按部署边界使用显式 subpath
共享协议留在现有 runtime-core,SQLite/PostgreSQL adapter 分别留在现有
local-sqlite 与 cluster-postgres。三个入口均为显式 subpath,不从 package root
聚合导出。
workspace 继续保持 21 个 QL3 package,没有新增第三方依赖、进程、连接池、timer、 watcher、socket 或后台队列。Edge/Standalone 每次成功调用只增加一次有界 AES/JSON 工作和一个现有 SQLite 事务;Cluster 复用现有 PostgreSQL Pool。
当前边界
本 ADR 只关闭 running → succeeded:
failed、timed_out和 cancellation 的 Tool-specific result/error envelope 尚未 建立;- trusted adapter 的产品 composition 尚未把 execute→seal→commit 串成公开路径;
- Result Artifact key 的持久 catalog、rotation、retention/rekey 仍由后续决策完成;
- key lost、Artifact/关系损坏和 result ambiguity 仍需 inspect/manual recovery;
- HA 门已验证 schema/ACL/复制与既有领域提交响应丢失,但尚未对新的 Tool completion transaction 注入 COMMIT-response-loss。
因此 Tool execution production admission 继续关闭。
被否决方案
- 把明文 output 写入 StepRun 或 RunEvent:扩大敏感结果的持久化与读取面。
- 先保存 Artifact、再更新 StepRun:崩溃窗口会产生无完成事实的孤立结果。
- 只保存 output digest:无法在重启或响应丢失后重放 exact output。
- 复用 invocation Artifact 表:输入与结果具有不同身份、生命周期和授权方向。
- 拆成新的 result package:没有独立部署、依赖或权限生命周期,只会继续增加 单文件 package。
- 赋予 runtime UPDATE/DELETE:破坏 append-only 证据边界。
- 直接比较 PostgreSQL
jsonb字符串:对象键顺序不是语义,可能误报 conflict。 - 把成功协议宣传为全 terminal completion:会掩盖 failed/timed_out 的恢复缺口。
验证
- runtime-core:320/320;
- local-sqlite:117/117,真实内存 SQLite 覆盖原子提交与 exact replay;
- cluster-postgres unit:178 pass / 1 条件 skip;
- 全新 PostgreSQL 18 六角色真库 integration:41 pass / 1 条件 skip,直接覆盖加密
Result Artifact、
running → succeeded、Run version/event sequence、exact replay 和无明文持久化; - PostgreSQL 18.4 arm64 双节点物理 HA:streaming、
remote_apply、旧主隔离、晋升、pg_rewind回归只读、双控制副本恢复及全部报告 gate 通过; - 21 个 QL3 workspace package 全量 build/test 通过;
- edge import、cluster dependency、edge artifact 审计通过;edge artifact 3,554,497 bytes、40 个加载模块、RSS 增量 10,731,520 bytes;
- 临时 PostgreSQL 容器已删除,无测试资源残留。
后续门禁
- 在 edge/standalone 与 cluster-control composition 中装配 start→execute→seal→commit,并保持公开入口默认关闭;
- 定义 failed/timed_out 的低敏、可恢复、不可伪造完成 envelope;
- 增加 SQLite crash、PostgreSQL COMMIT-response-loss 与 Tool completion 的物理 HA 故障注入;
- 建立 result key catalog/rotation/retention/rekey 与人工恢复流程;
- 完成物理 Edge idle/fault/scale 证据后再评审 production admission。