Files
qinglong/docs/adr/ADR-0161-tool-execution-start-artifact-binding.md

5.2 KiB
Raw Permalink Blame History

ADR-0161Tool Execution Start 与 Artifact 的不可变绑定

  • 状态:Accepted
  • 日期:2026-07-26
  • 关联:ADR-0158、ADR-0159、ADR-0160RFC D-123/D-149/D-150

背景

Tool invocation input 与 redacted preview 已成为独立不可变 Artifactplan、 admission 和 start barrier 只携带 reference。若数据库只保存 start barrier JSON 数据库无法证明该 start 实际引用哪一对已持久化 Artifact;历史缺行、镜像列漂移或 相同 ID 的错误内容可能在重启、重放或 PostgreSQL promotion 后被误接受。

同时,直接扩展既有 start-barrier 表会要求 SQLite 重建热表,并把 Artifact identity 复制到所有 start 查询路径。低配设备需要保持单次短事务和零后台进程,集群则需要让 复合身份随 PostgreSQL WAL 原生复制并维持最小权限。

决策

1. 使用独立的一对一绑定表

  • SQLiteToolExecutionStartArtifactBindings
  • PostgreSQLql3.tool_execution_start_artifact_bindings

每个 start_id 只能有一行。该行保存 Project、action、input/preview Artifact ID 与 Artifact digest,以及 input/action/preview/redaction digest。bound_at_ms 必须与 barrier 的 started_at_ms 一致。

input 与 preview 父表增加受审复合唯一索引。绑定表通过两个复合外键精确引用完整 Artifact 镜像身份,并通过第三个外键引用 start barrier。Artifact digest 已覆盖 key ID、algorithm、大小等完整 envelope,因此绑定表不再复制这些可由 digest 证明的 字段。

2. 同一事务先写 barrier,再写绑定

SQLite 继续复用共享 BEGIN IMMEDIATE authorityPostgreSQL 继续复用现有短 SERIALIZABLE start transaction。Trace、Audit、StepRun/Run CAS、RunEvent、 mutation、barrier 和 Artifact binding 任一失败,整个 start 都必须回滚。

Artifact pair 必须在 start 前已经持久化。缺少 Artifact、Project/action 不一致或 任一 digest 漂移均由复合外键失败关闭,不能在 start 事务里补造 Artifact。

3. 读取时以关系事实反证 JSON

Repository 查询使用 LEFT JOIN 读取绑定镜像,并把每个字段与规范化 barrier reference 对比。使用 LEFT JOIN 是刻意的:升级前已存在但没有绑定行的 barrier 仍能被发现,随后明确返回 unavailable;若使用 inner join,它会被误判为“不存在”, 重试写入后才以唯一键冲突结束,无法区分历史不完整事实。

不对旧 barrier 进行推测性 backfill。缺少绑定就是不可恢复的执行证据缺口,必须由 后续 inspect/manual recovery 处理。

4. Capability、readiness 与权限锁步

  • SQLite0059-tool-execution-artifact-bindings 建表, 0060-capability-v30 发布 tool_execution_artifact_binding:1;当前 60 条 migration、capability v30、52 张 typed owned table
  • PostgreSQLpg-0032-tool-execution-artifact-bindings 建表、安装 ACL 并发布 capability v31;当前 32 条 migration、capability v31、51 张表。

PostgreSQL runtime 对绑定表只有 SELECT, INSERTUPDATE, DELETE 必须由数据库 拒绝。admin、Package manager、Package executor 和 Worker ingress 均无表权限。 双方言 migration manifest/checksum、Drizzle schema、readiness table/index/CHECK/FK contract 必须同时前进。

低配与集群影响

  • Edge/Standalone 每次 Tool start 只增加一个 12 列有界关系行,无新 package、 进程、连接、timer、watcher 或缓存;
  • 查询只增加一次主键 LEFT JOIN,不会扫描 Artifact JSON 或解密 input
  • Cluster 绑定行与三组外键随 PostgreSQL WAL 复制,不实现应用层复制协议;
  • start 热路径不解析明文,Artifact key material 仍不进入数据库。

被否决方案

  1. 把完整 Artifact JSON 写进 barrier:复制 ciphertext、扩大热行和恢复读取面。
  2. 只把 Artifact ID 写进 barrier JSON:数据库无法证明 ID 对应的 digest、 Project 和 action。
  3. 迁移时从 barrier JSON 回填绑定:把未经关系外键证明的历史 JSON 升格为可信 数据库事实。
  4. 用 inner join 隐藏缺失绑定:把损坏历史伪装成不存在,降低故障可诊断性。
  5. 给 runtime UPDATE 权限:不可变绑定无需更新,扩大 authority 没有正确性收益。

验证

  • runtime-core 全量 313/313
  • SQLite 全量 116/116,其中 migration/schema/readiness/start repository 定向 18/18
  • PostgreSQL package 175 pass/1 条件 skip,其中 migration/schema/readiness/start repository 定向 35/35
  • Cluster Control 最小权限与应用组合测试 139 pass、2 条条件 skip
  • PostgreSQL 真实集成覆盖 Artifact 先持久化、start 与 binding 原子提交、exact replay 和 durable row 计数;
  • PostgreSQL 18 物理 HA 门覆盖 capability v31/51 表、runtime append-only、四个隔离 角色拒绝、promotion/readiness 与旧主 rejoin。

后续门禁

  1. 遗失 key、损坏 Artifact/绑定行的 inspect/manual recovery
  2. 首个 trusted built-in adapter 在 durable start 后解封并重新通过 Registry
  3. adapter response-loss、进程崩溃与副作用幂等恢复证据。