mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
120 lines
6.7 KiB
Markdown
120 lines
6.7 KiB
Markdown
# ADR-0165:Trusted Tool 失败与超时终态完成协议
|
||
|
||
- 状态:Accepted
|
||
- 日期:2026-07-26
|
||
- 关联:ADR-0156、ADR-0158、ADR-0162 至 ADR-0164;RFC D-152 至 D-154
|
||
|
||
## 背景
|
||
|
||
ADR-0163/0164 已关闭 Trusted Tool 的成功持久化与 Profile-neutral 成功协调,
|
||
但 adapter 明确失败和 deadline 到期仍会让 StepRun 停留在 `running`。如果每个
|
||
Profile 自行解释异常,低配路由设备和集群节点会产生不同的终态、重试和敏感信息
|
||
持久化语义;若把异常对象、stack 或未知 output 写进 RunEvent,又会扩大泄露面。
|
||
|
||
失败终态还必须与成功 completion 竞争收敛。仅在应用层先查一次成功记录不能证明
|
||
互斥:并发调用、事务提交响应丢失和 PostgreSQL 主库切换都可能让调用者观察到未知
|
||
结果。
|
||
|
||
## 决策
|
||
|
||
### 1. 失败完成只保存固定低敏事实
|
||
|
||
runtime-core 新增显式 subpath
|
||
`@qinglong/runtime-core/tool-execution-failure-completion`。v1 只接受:
|
||
|
||
- `failed`:`tool_adapter_failed` / `Trusted Tool execution failed`;
|
||
- `timed_out`:`tool_deadline_exceeded` /
|
||
`Trusted Tool execution deadline exceeded`。
|
||
|
||
completion 必须绑定 exact start、Project、Run、StepRun、Tool、adapter、Run version、
|
||
event sequence、mutation 和 event identity。它不保存 raw error、stack、adapter output,
|
||
也不创建 Result Artifact 或取得 result key authority。
|
||
|
||
### 2. 成功与失败 completion 必须原子互斥
|
||
|
||
SQLite 与 PostgreSQL 各增加 append-only failure completion 表和 repository。失败提交
|
||
必须在一个事务内完成:
|
||
|
||
1. 复验 start barrier、当前 `running` Tool StepRun、非 terminal Run;
|
||
2. 拒绝同一 start 已存在的成功 completion;
|
||
3. 将 StepRun 原子迁移到 `failed` 或 `timed_out`,保持 `outputRef=null`;
|
||
4. 推进 Run version/event sequence;
|
||
5. 写入固定低敏 RunEvent、StepRunMutation 与 failure completion。
|
||
|
||
成功 repository 同样必须在事务内拒绝同一 start 的失败 completion。SQLite 使用
|
||
`BEGIN IMMEDIATE` 串行化双方竞争;PostgreSQL 使用 serializable transaction,并锁定
|
||
exact StepRun/Run。两侧都只允许完整命令 exact replay,任何部分身份复用、跨表镜像
|
||
漂移或同时存在成功/失败记录都失败关闭。
|
||
|
||
SQLite capability 推进到 v32,共 55 张受管表;PostgreSQL `control-core` capability
|
||
推进到 v33。PostgreSQL runtime role 对 failure completion 只取得 `SELECT, INSERT`,
|
||
admin、Package manager、Package executor、Worker ingress 与 PUBLIC 默认拒绝。
|
||
|
||
### 3. 一个协调器裁决所有 Tool 终态
|
||
|
||
runtime-core 新增显式 subpath
|
||
`@qinglong/runtime-core/trusted-tool-completion`,由
|
||
`executeAndCompleteTrustedTool` 固定编排:
|
||
|
||
1. 执行 adapter 前同时读取 durable success/failure winner;
|
||
2. 只有两者均不存在才调用既有 Trusted Tool execution;
|
||
3. adapter 抛错后再次读取 durable winner,先收敛并发或未知提交结果;
|
||
4. 只把明确的 `TrustedToolExecutionFailedError` 归类为 `failed`;
|
||
5. 只把明确的 `TrustedToolExecutionDeadlineExceededError` 归类为 `timed_out`;
|
||
6. Artifact、key、binding、snapshot、storage 等缺失或损坏继续保持非终态并失败关闭;
|
||
7. failure commit 响应丢失后只读取 durable winner,同一次调用不得重新执行 adapter。
|
||
|
||
返回值是 `succeeded | failed | timed_out` 的判别联合。固定 system actor、start-derived
|
||
dedupe、mutation 和 event identity 均由协调器生成,不接受 transport 注入。
|
||
|
||
### 4. 保持双 Profile 的资源边界
|
||
|
||
现有 `LocalSqliteTrustedToolStorage` 与 `ClusterTrustedToolStorage` 增加
|
||
`failureCompletions` port,不新增 workspace package或第三方依赖:
|
||
|
||
- edge/standalone 仍使用首次请求才动态加载的 SQLite 单例 bundle,不新增连接、
|
||
timer、watcher 或 socket;
|
||
- cluster-control 仍只通过受审 `@qinglong/cluster-postgres/runtime` 组合入口,
|
||
在现有单一 Pool 上装配同构 bundle;
|
||
- runtime-core root、PostgreSQL root/admin/ingress 和生产 transport 不获得执行
|
||
authority;生产 allowlist 仍只有 `run.get` 与 `run.cancel`。
|
||
|
||
## 被否决方案
|
||
|
||
1. **把异常序列化进 Artifact 或 RunEvent**:扩大敏感信息面,且失败终态不需要解封。
|
||
2. **只有失败 repository 检查成功记录**:晚到的成功事务仍可穿透,无法证明互斥。
|
||
3. **用任意异常自动终态化**:会把 key 丢失、binding 漂移或数据库不可用误报为业务失败。
|
||
4. **协调器捕获后重跑全部流程**:会重复 adapter 副作用。
|
||
5. **为两个 repository 各拆一个 package**:没有独立部署或依赖边界,只会加重
|
||
路由设备安装、构建与审计成本。
|
||
6. **因终态闭环而开放生产 route**:result key 生命周期、人工恢复和专属故障注入
|
||
尚未完成。
|
||
|
||
## 验证
|
||
|
||
- runtime-core:331/331,覆盖成功、失败、超时、固定事实、并发 winner、响应丢失、
|
||
adapter-call-count=1、前置条件缺失保持非终态和显式 subpath;
|
||
- local-sqlite:119/119,真实 SQLite 覆盖原子失败提交、exact replay、成功/失败双向
|
||
排斥、固定事实与 lazy storage bundle;
|
||
- cluster-postgres:181 pass / 1 条件 skip,覆盖事务 SQL、双向排斥、typed schema、
|
||
migration checksum、readiness、六角色权限和 composition entrypoint;
|
||
- cluster-control:139 pass / 2 条件 skip,覆盖单 Pool storage 装配与依赖边界;
|
||
- 21 个 QL3 workspace package 全量 build/test 为 0 fail,package 数量和第三方依赖
|
||
均未增加;edge import、cluster dependency、cluster deployment 审计无 finding;
|
||
- 全新 PostgreSQL 18 六角色真库 integration:42 pass / 1 条件 skip / 0 fail,直接
|
||
覆盖 `timed_out` 原子提交、exact replay、晚到成功拒绝、固定低敏事实与无 output
|
||
明文;
|
||
- PostgreSQL 18.4 arm64 物理 HA 总门 `passed=true`:`remote_apply`、timeline 1→2、
|
||
旧主 fencing、双 control replica 重新 activation、`pg_rewind` 只读同步重加入及
|
||
既有领域 COMMIT-response-loss 门全部通过。该 HA fixture 尚未注入 Trusted Tool
|
||
failure completion 专属 COMMIT-response-loss,不能用通用事务门替代该证据。
|
||
|
||
## 后续门禁
|
||
|
||
1. 在真实 PostgreSQL 上执行新增 terminal completion integration,并给 Tool completion
|
||
注入 COMMIT-response-loss、主库晋升后 durable winner 和 adapter-call-count=1;
|
||
2. 给 SQLite 增加 adapter 返回后、failure/success 事务提交前后的进程 crash 矩阵;
|
||
3. 建立 result key catalog、rotation、retention/rekey 与 key-lost 人工恢复;
|
||
4. 按 Project current snapshot 构造短生命周期 adapter registry,再评审产品
|
||
use-case/transport 入口。
|