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

102 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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. 使用独立的一对一绑定表
- SQLite`ToolExecutionStartArtifactBindings`
- PostgreSQL`ql3.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 与权限锁步
- SQLite`0059-tool-execution-artifact-bindings` 建表,
`0060-capability-v30` 发布 `tool_execution_artifact_binding:1`;当前 60 条
migration、capability v30、52 张 typed owned table
- PostgreSQL`pg-0032-tool-execution-artifact-bindings` 建表、安装 ACL 并发布
capability v31;当前 32 条 migration、capability v31、51 张表。
PostgreSQL runtime 对绑定表只有 `SELECT, INSERT``UPDATE, 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、进程崩溃与副作用幂等恢复证据。