mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-21 00:17:47 +08:00
146 lines
7.2 KiB
Markdown
146 lines
7.2 KiB
Markdown
# ADR-0223:按 generation 绑定的 Plugin Package Workflow 执行计划
|
||
|
||
- 状态:Proposed
|
||
- 日期:2026-07-30
|
||
- 关联 RFC:QL-RFC-0001 D-12、D-144、D-211、D-212
|
||
- 关联 ADR:ADR-0001、ADR-0150、ADR-0156、ADR-0222、ADR-0224
|
||
|
||
## 背景
|
||
|
||
ADR-0222 已经让 Workflow 定义以 immutable、generation-bound publication 发布,并让
|
||
quarantine、publisher revocation 和正常 lifecycle withdrawal 立即阻止新启动。但定义
|
||
可见不等于 Workflow 可执行。现有系统仍缺少一个不可变输入,把以下事实绑定为同一次
|
||
运行意图:
|
||
|
||
- exact active automation publication;
|
||
- exact materialized revision 与 Workflow 定义;
|
||
- Workflow 中每个 Task 的 immutable source digest;
|
||
- DAG 依赖、初始 ready frontier、Run ID 与每个 StepRun ID。
|
||
|
||
如果执行器临时读取多个 current head,再逐项创建 StepRun,会留下三个问题:
|
||
|
||
1. Package upgrade、disable 或安全撤销可在读取之间切换 generation;
|
||
2. 进程崩溃可能只展开部分 DAG;
|
||
3. 响应丢失后无法区分 exact replay 与使用新定义重新执行。
|
||
|
||
这些问题不能靠进程内缓存、定时扫描或“再次读取最新定义”修复。
|
||
|
||
## 决策
|
||
|
||
### 1. 先冻结纯执行计划,不提前开放执行副作用
|
||
|
||
`@qinglong/runtime-core/plugin-package-workflow-execution-plan` 提供 profile-neutral
|
||
纯契约,不新增 workspace package、第三方依赖或进程:
|
||
|
||
- schema 固定为 `qinglong/plugin-package-workflow-execution-plan@v1`;
|
||
- 最多 128 个 Step,编码后最多 256 KiB;
|
||
- plan 绑定 Project、Package、installation、lock、generation、materialized
|
||
revision、publication、Workflow definition、Run 与所有 StepRun identity;
|
||
- 每个 Step 绑定 Task ID、generation-bound reference、原始 source digest、依赖和
|
||
`pending|ready` 初态;
|
||
- root Step 才能为 `ready`,有依赖的 Step 必须为 `pending`;
|
||
- plan 使用 domain-separated canonical SHA-256,可严格 normalize 与复算。
|
||
|
||
本 ADR 的切片只创建不可变 plan。后续 ADR-0224 已在 SQLite 中原子创建
|
||
Run/StepRun/receipt,但仍不调用 Executor、不解析 Secret、不读取输入 Artifact,
|
||
也不把 durable admission 解释为产品 Workflow 已开放。
|
||
|
||
### 2. v1 执行面严格等于现有 Package Workflow 语义
|
||
|
||
Plugin Package Workflow v1 只包含有界、无环的 Task DAG:
|
||
|
||
- Step 只引用同一 materialized revision 中的 Package Task;
|
||
- disabled Workflow 或 disabled Task 拒绝规划;
|
||
- publication 与 revision 的 Project、Package、installation、lock、generation 和
|
||
digest 必须完全一致;
|
||
- publication 中的 Workflow semantic digest 必须与 revision 中的同名 Workflow
|
||
一致;
|
||
- 调用者必须一次提供与 Step key 精确相等、无重复的 StepRun ID 集合。
|
||
|
||
RFC 15.1 中的 Model、Tool、Approval、条件、表达式、Subworkflow、动态重试和模板输入
|
||
不是这个 v1 plan 的隐式能力。它们必须在各自的 Policy、Secret、Artifact、Trace 和
|
||
start barrier 契约完成后按版本扩展,不能通过任意 JSON 字段提前进入执行面。
|
||
|
||
### 3. durable admission 必须是双方言单事务
|
||
|
||
存储切片必须新增专用 Workflow admission authority,而不是让应用串联通用
|
||
RunRepository 与 StepRunRepository。一次 admission transaction 必须:
|
||
|
||
1. 取得与 publisher revocation 相同的安全序列化边界;
|
||
2. 在事务内验证 exact publication start guard;
|
||
3. exact replay 优先检查 immutable plan/receipt;
|
||
4. 原子创建 Workflow Run、全部 StepRun、顺序 RunEvent/StepRun mutation 与
|
||
admission receipt;
|
||
5. 任一 collision、generation 漂移、非 current publication、quarantine、
|
||
lifecycle withdrawal 或权限失败全部回滚;
|
||
6. COMMIT response loss 只能 inspect durable receipt,不得重新生成 ID 或重新规划。
|
||
|
||
SQLite 复用单 `LocalSqliteOperationAuthority` 与 `BEGIN IMMEDIATE`。PostgreSQL 使用
|
||
受审 `SECURITY DEFINER` admission function 或等价的单一 runtime transaction,使
|
||
start guard 和 Run/StepRun 写入共享同一 transaction-level signer lock。runtime
|
||
不取得 Package provenance、quarantine 或 publisher receipt 表的直接读取权。
|
||
|
||
### 4. executor 使用 durable frontier,不使用常驻全量扫描
|
||
|
||
后续 executor 只能从已 admission 的 plan 与 StepRun 状态计算 frontier:
|
||
|
||
- 只有全部 `needs` succeeded 的 pending Step 才能原子推进为 ready;
|
||
- 任一 required dependency failed/cancelled/timed_out 时,下游收敛为 skipped,
|
||
Workflow Run 按固定聚合规则终结;
|
||
- 已 durable running 的 Step 在 Package 后续 withdrawn/quarantined 时按原 revision
|
||
完成或恢复;安全事实只禁止新的 Workflow/Step start;
|
||
- Edge/Standalone 使用既有 application lifecycle 的有界单页调用,默认分别限制为
|
||
8/32 个候选,不新增 daemon、watcher 或 per-Workflow timer;
|
||
- Cluster 使用 caller-driven worker/executor cycle 与数据库 keyset claim,不创建
|
||
每 Workflow 常驻 Job 或内存队列。
|
||
|
||
具体 Task Attempt 启动仍必须复用现有 Run/Attempt/Executor fence,不能由 Workflow
|
||
planner 直接 spawn。
|
||
|
||
## 不采用方案
|
||
|
||
### 每次执行重新读取 current Workflow 和 Task head
|
||
|
||
拒绝。会让一次 Run 混合多个 generation,也无法 exact replay。
|
||
|
||
### 先建 Run,再逐项创建 StepRun
|
||
|
||
拒绝。崩溃会留下半展开 DAG,恢复只能猜测未创建步骤。
|
||
|
||
### 把 Workflow executor 放进新的 workspace package
|
||
|
||
拒绝。纯领域契约没有独立部署、权限域、重依赖或 Profile 替换价值;它属于
|
||
runtime-core subpath。双方言 authority 分别留在既有 local-sqlite 与
|
||
cluster-postgres。
|
||
|
||
### Edge 为每个 Workflow 启动 timer 或 watcher
|
||
|
||
拒绝。低配路由设备不能为 dormant Workflow 支付常驻内存、唤醒和闪存写放大。
|
||
|
||
### publication withdrawn 后终止所有 running Step
|
||
|
||
拒绝。正常退役和安全隔离都不等于已启动副作用可以安全热杀;running execution 继续由
|
||
Attempt cancellation/recovery authority 裁决。
|
||
|
||
## 当前验证
|
||
|
||
1. runtime-core 定向 6/6:active publication + exact revision 生成两步 DAG,
|
||
root 为 ready、dependent 为 pending,并绑定两个 Task source digest;
|
||
2. 完整 plan、JSON round-trip 与无摘要字段输入得到相同 canonical digest;
|
||
3. withdrawn publication、跨 revision 漂移、缺失或重复 StepRun ID、plan digest 和
|
||
generation-bound Task reference 漂移均失败关闭;
|
||
4. planner 只经显式 runtime-core subpath 发布,root 不暴露 authority;
|
||
5. runtime-core 完整测试 394/394 通过;
|
||
6. ADR-0224 已完成 SQLite v41 单事务 admission、Run/StepRun/event/mutation/receipt
|
||
exact replay 与 readiness;workspace 仍为 20 个 package;
|
||
7. 未新增生产依赖、timer、watcher、listener 或常驻进程。
|
||
|
||
## 尚未关闭
|
||
|
||
1. PostgreSQL durable admission repository、migration、readiness、权限与 HA;
|
||
2. SQLite 真实断电和固定 Edge 资源预算;
|
||
3. 有界 ready-frontier coordinator 与 Task Attempt 启动;
|
||
4. Workflow terminal aggregation、取消、超时和恢复;
|
||
5. 产品级强认证/Policy/API/CLI/UI 入口;
|
||
6. Prompt、Secret binding 以及 Model/Tool/Approval/Subworkflow 扩展。
|