mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
148 lines
7.9 KiB
Markdown
148 lines
7.9 KiB
Markdown
# ADR-0154:Project-scoped 不可变 Tool Definition Snapshot
|
||
|
||
- 状态:Accepted(架构边界、纯 planner、canonical digest、轻量 contribution、
|
||
8 MiB snapshot 上限、双方言 append-only repository、current-vector proof、
|
||
分页双观察 production coordinator、本机 application gate、Cluster
|
||
package-executor Job、executor-only PostgreSQL ACL 与 physical HA snapshot
|
||
durability 已实现;Tool consumer admission 与 trusted handler binding 尚未实现)
|
||
- 日期:2026-07-26
|
||
- 关联:ADR-0133、ADR-0149 至 ADR-0153、QL-RFC-0001 D-131/D-144/D-148
|
||
|
||
## 背景
|
||
|
||
ADR-0150 允许 active Plugin Package 提供经 Package name 和已审批 permission 围栏的
|
||
`ToolDefinition`,ADR-0133 提供 immutable `ToolDefinitionRegistry` 与 Policy-fenced
|
||
invocation plan。但目前仍不能把多个 active Package 的 Definition 组成可供产品读取的
|
||
一致 registry。
|
||
|
||
这里必须避免两个看似直接但错误的推论:
|
||
|
||
- Package 提供 Definition 不等于 Package 可以注入 handler;
|
||
- 一个进程级全局 registry 不能代表所有 Project,因为不同 Project 可以安装不同
|
||
Package generation。
|
||
|
||
如果 registry 没有绑定完整 active Package 集合,移除 Package、升级 generation 或
|
||
无 Tool 的 Package 发生变化时,旧 registry 可能继续被误认为当前。
|
||
|
||
## 决策
|
||
|
||
### 1. Snapshot 必须以 Project 为边界
|
||
|
||
`qinglong/project-tool-definition-snapshot@v1` 至少绑定:
|
||
|
||
- `projectId`;
|
||
- 完整、唯一排序的 active Package vector;
|
||
- 每个 Package 的 name、installation、generation、generation digest、lock digest 和
|
||
materialized revision digest;
|
||
- 完整、唯一排序的 Tool Definition 与来源 Package/generation;
|
||
- active vector digest、definition digest 和 snapshot digest;
|
||
- 数据库提交时间。
|
||
|
||
active vector 必须包含没有 Tool 的 active Package。否则“Package 从无 Tool 升级为有
|
||
Tool”或“有 Tool 降级为无 Tool”不能可靠改变 snapshot identity。
|
||
|
||
一个 Project 最多 128 个 active Package、128 个 Tool Definition;任何重复
|
||
`name + version`、跨 Package namespace、来源 revision 漂移或超限都失败关闭。
|
||
完整 canonical snapshot JSON 另受 8 MiB 硬上限。
|
||
|
||
### 2. Builder 使用双观察,不建立第二个 Package pointer
|
||
|
||
caller-driven builder 固定执行:
|
||
|
||
1. 从耐久 install heads 分页读取一个 Project 的完整 active vector;
|
||
2. 对每个 Package 读取 active generation,必须与 install vector 精确一致;
|
||
3. 按 generation digest 逐项读取 immutable materialized revision,立即提取只含
|
||
generation、revision digest 和 Tool Definition 的轻量 contribution,然后释放完整
|
||
revision;
|
||
4. 从 contributions 构造确定性 snapshot;
|
||
5. 再次读取完整 install vector 和每个 active generation;
|
||
6. 全部未变才允许提交 snapshot。
|
||
|
||
planner 不得要求同时持有全部 24 MiB materialized revision;否则 128 个 active
|
||
Package 会在低配设备上制造不可接受的理论峰值。snapshot 不是第二个 active pointer。
|
||
source of truth 仍是 durable active install 与
|
||
ADR-0149 generation;snapshot 只是这一完整集合的不可变、可审计投影。
|
||
|
||
### 3. 双方言使用 append-only snapshot + source item
|
||
|
||
SQLite/PostgreSQL 使用既有 storage package 的显式 subpath,不新增 workspace package:
|
||
|
||
- snapshot 主表按 `Project + activeVectorDigest` 唯一;
|
||
- source item 表保存该 snapshot 的完整 Package vector;
|
||
- Definition 保存在规范化 snapshot JSON 中,并由索引列/CHECK 绑定 identity;
|
||
- create 只允许首次插入或完整 exact replay;
|
||
- update/delete 禁止。
|
||
|
||
`findCurrent(Project)` 必须在一次数据库观察中证明 snapshot source item 与当前 active
|
||
install heads 双向完全相等。安装刚提交而 snapshot 尚未发布、Package 被移除或任一
|
||
generation 改变时返回 unavailable/absent,禁止回退到旧 snapshot。这样不需要 timer、
|
||
watcher、LISTEN 或可变内存 head。
|
||
|
||
PostgreSQL 只允许 `ql3_package_executor` 创建 snapshot;未来 Tool invocation consumer
|
||
只取得经过 current-vector 复验的 SELECT,不取得 Package install、materialization 或
|
||
snapshot 写权。
|
||
|
||
### 4. Definition snapshot 不包含 handler
|
||
|
||
snapshot 和现有 `ToolDefinitionRegistry` 均不得包含函数、module path、dynamic import、
|
||
command、URL、MCP credential、数据库 service 或网络 client。Package 安装不能创建或
|
||
替换 handler binding。
|
||
|
||
后续受信 handler binding 必须由产品 composition 独立提供,并精确绑定:
|
||
|
||
- Project Tool snapshot digest;
|
||
- Tool name、version 和 definition digest;
|
||
- reviewed handler adapter identity/version;
|
||
- execution class、timeout/redaction/audit contract;
|
||
- 可用 Profile 与所需外部 authority。
|
||
|
||
没有 exact binding 的 Definition 必须保持不可调用。built-in、MCP、HTTP 和未来隔离
|
||
Package runtime 可以使用不同 binding ceremony,但均不能由 Package resource JSON
|
||
自行声明为已信任代码。
|
||
|
||
### 5. Profile 保持请求驱动
|
||
|
||
- edge/standalone:Task publication gate 后按 Project 构造 snapshot;空 Package 集合
|
||
产生合法空 snapshot。读取与提交使用单 SQLite authority,无常驻 cache/timer。
|
||
- cluster:既有 package-executor Job 在 Task publication 后构造并提交 snapshot;
|
||
多 Job 通过 active vector exact replay 收敛。
|
||
- worker:不构造 snapshot;只接受未来 execution plan 中已绑定的 handler identity。
|
||
|
||
## 被否决方案
|
||
|
||
1. **一个进程级全局 registry**:会混淆不同 Project 的安装集合和 Policy authority。
|
||
2. **只收集有 Tool 的 Package**:无 Tool→有 Tool 的升级不能被完整 source vector
|
||
围栏。
|
||
3. **把 handler/module/URL 写进 Package Tool JSON**:把 Definition 安装升级为控制面
|
||
代码或网络 authority 注入。
|
||
4. **以 registry cache 作为 current head**:进程重启、多副本和 Package 更新会产生
|
||
stale truth;current 必须由数据库 active vector 复验。
|
||
5. **每次 Tool call 重读 staging/OCI**:绕过 immutable revision,并把调用可用性绑定
|
||
到 Registry。
|
||
6. **为 snapshot 新建 package**:没有独立部署或版本生命周期,显式 subpath 足够。
|
||
|
||
## 实现门
|
||
|
||
1. runtime-core pure planner、canonical digest、轻量 contribution、8 MiB、
|
||
128/128 bounds,以及 active-source/pending-Project keyset、双观察 publication、
|
||
有界 recovery/final probe 和 drift tests(已完成,runtime-core 275/275);
|
||
2. 双方言 append-only snapshot/source-item schema、exact replay、active-vector
|
||
current proof 与显式 storage subpath(已完成:SQLite capability v25;
|
||
PostgreSQL `pg-0027` / capability v26);
|
||
3. install vector 在 queued/staged/activating 窗口保持旧 active generation、active
|
||
commit 后旧 snapshot 立即失效,以及 stale publish conflict 的双方言共享契约
|
||
(已完成;source page 精确绑定 active install 与 immutable revision,publication
|
||
在提交前完成第二次完整观察);
|
||
4. local application 在未来 Tool consumer admission 前按 Project 请求驱动发布
|
||
current snapshot(已完成;位于 Task publication 后、Secret/Run/lifecycle/admission
|
||
前;只分页处理缺 current snapshot 的 active Project,空 Project 生成合法空
|
||
snapshot,无 timer/watcher/全历史扫描);
|
||
5. PostgreSQL `ql3_package_executor` 的 snapshot `SELECT/INSERT`、其余常驻角色
|
||
default deny、真实六角色 PostgreSQL 18 integration 与 physical HA readiness
|
||
(已完成;package-executor recovery Job 在 Task publication 后运行同一有界
|
||
coordinator。PG18.4 arm64 六角色真库 38 pass/1 条件 skip;25 个 physical HA
|
||
具体 gate 与总 `passed` 全绿,snapshot 在旧主由 executor 发布、晋升前完成
|
||
`remote_apply` 复制并在 timeline 2 以相同三层 digest 读取);
|
||
6. 独立 ADR 冻结 trusted handler binding、preview/approval、StepRun/Trace/Audit 后,
|
||
才能开放 Tool execution(待实现)。
|