Files
qinglong/docs/adr/ADR-0160-sqlite-postgresql-immutable-tool-invocation-artifact-repository.md

99 lines
4.8 KiB
Markdown
Raw Permalink 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-0160SQLite/PostgreSQL 不可变 Tool Invocation Artifact 仓库
- 状态:Accepted
- 日期:2026-07-26
- 关联:ADR-0043、ADR-0063、ADR-0125、ADR-0158、ADR-0159
RFC D-29/D-30/D-123/D-149/D-150
## 背景
ADR-0159 已把 Tool input 与审批 preview 从 plan 移到两个不可变 Artifact,但只有领域
envelope 和 Repository port 仍不足以支持重启、集群派发或主库晋升。双方言必须用同一
身份和重放语义持久化,同时保持低配设备不引入新进程或依赖,并避免 Cluster 的
admin、Package 与 Worker authority 取得敏感调用材料。
## 决策
### 1. 使用现有 Profile adapter package
- SQLite adapter 位于 `@qinglong/local-sqlite/tool-invocation-artifact`
- PostgreSQL adapter 位于
`@qinglong/cluster-postgres/tool-invocation-artifact`
- 不增加 workspace package、第三方依赖、常驻进程、timer、watcher 或缓存。
每个方言各有 input/preview 两张表。表保存受审 mirror column 和完整有界 Artifact
JSONinput JSON 只有 AES-256-GCM envelope,数据库永不保存 key material 或明文。
### 2. 双 Artifact 必须原子提交并精确重放
Repository 一次只接受具有相同 Project、action 和 sealing time 的 input/preview
pair。SQLite 使用共享 `BEGIN IMMEDIATE` operation authorityPostgreSQL 使用短
`SERIALIZABLE` transaction。任一行失败必须回滚两行。
相同 Artifact ID 只有完整规范化内容一致才能返回 `existing`。部分 pair、mirror
column 漂移、非法 JSON、digest 漂移或相同身份不同内容均失败关闭。PostgreSQL 并发
唯一键竞争在事务回滚后重读:赢家内容完全一致时收敛为 exact replay,否则为
conflict。
### 3. PostgreSQL 不以行锁换取扩大权限
Artifact 行不可变,因此 replay 读取不得使用 `FOR SHARE`。PostgreSQL 对行锁读取会
要求更新类权限,这与 append-only authority 冲突。runtime 只取得两张表的
`SELECT, INSERT``UPDATE, DELETE` 必须由数据库拒绝。admin、Package manager、
Package executor 和 Worker ingress 对两表均无 `SELECT/INSERT/UPDATE/DELETE`
迁移 authority 继续独占 DDL。
### 4. Capability 与 schema 必须锁步
- SQLite`0057-tool-invocation-artifacts` 建表,
`0058-capability-v29` 发布 `tool_invocation_artifact:1`;当前 58 条 migration、
capability v29、51 张 typed owned table
- PostgreSQL`pg-0031-tool-invocation-artifacts` 原子建表、安装 ACL 并发布
capability v30;当前 31 条 migration、capability v30、50 张表。
双方言 readiness、Drizzle schema、migration manifest/checksum、table/column/index/
CHECK/FK contract 必须一起前进,不能只修改 migration SQL。
## 低配与集群影响
- Edge 仍是单 SQLite 文件和现有共享写 authority;每次调用只增加两个有界行和一次
短事务,不增加后台工作;
- input 明文上限 64 KiB,完整 envelope 上限 96 KiBpreview 内容上限 8 KiB,完整
envelope 上限 16 KiB
- Cluster 的两个 Artifact 随 PostgreSQL WAL 复制,不在应用层再造复制协议;
- retention/rekey 不进入 runtime 热路径,后续必须由短生命周期 maintenance
authority 实现。
## 被否决方案
1. **给 runtime 授予 UPDATE 以继续使用 `FOR SHARE`**:为不可变表扩大权限,且不能
提供额外正确性。
2. **分别 autocommit 两个 Artifact**:崩溃会留下无法判定的半 pair。
3. **把 Artifact 写入 start barrier JSON**:扩大热表和恢复读取面,并复制
ciphertext。
4. **让 admin/Package executor 代写**:混淆执行 authority 与管理/发布 authority。
5. **新增 Artifact workspace package**:没有独立部署、依赖或权限生命周期。
## 验证
- SQLite database/schema/Artifact repository 定向测试 16/16
- PostgreSQL migration/schema/readiness/Artifact repository 定向测试 33/33
- Artifact repository 额外覆盖 concurrent unique winner exact replay、半 pair
rollback、损坏 mirror fail-closed 与禁止 `FOR SHARE`
- PostgreSQL 18.4 arm64 双节点物理 HA
- runtime 原子写入并 exact replay
- input JSON 不含测试明文;
- admin、Package manager、Package executor、Worker ingress 均被数据库拒绝;
- `remote_apply` standby 已观察两行;
- timeline 1→2 promotion 后 runtime 可读取并重放;
- 旧主经 `pg_rewind` 只读同步重入,总 gate `passed=true`
## 后续门禁
1. retention、key rotation/rekey、遗失 key 和损坏 row 的 inspect/manual recovery
2. 首个 trusted built-in adapter 在 durable start 后解封并再次验证 Registry
3. adapter response-loss/进程崩溃的无重复副作用恢复证据。
Artifact reference 与最终 start barrier 的双方言原子绑定已由 ADR-0161
完成,不再属于开放项。