9.6 KiB
ADR-0152:Generation 绑定的原子 Plugin Package Task Reconciliation
- 状态:Accepted(双方言原子仓库、ownership、receipt、最小权限入口与真实 PostgreSQL 门已实现;生产 materialization coordinator、故障注入级 HA receipt 证明和引用感知 retention 尚未实现)
- 日期:2026-07-26
- 关联:ADR-0089、ADR-0091 至 ADR-0093、ADR-0149 至 ADR-0151、 QL-RFC-0001 D-144/D-145/D-146
背景
ADR-0151 已能按 generationDigest 持久化一份完整、不可变的 Package semantic
revision,但 TaskDefinition consumer 仍有三个未关闭的错误窗口:
- 一代包含多个 Task 时,逐条调用通用 Task repository 会暴露部分 generation;
- upgrade 删除一个 Task 时,直接删除历史会破坏 Run、execution revision 和审计引用, 不处理又会让旧任务继续可调度;
- Package publisher 与人工/其他 publisher 竞争同一个
taskId时,只有 revision CAS 不足以表达长期 ownership。
此外,active pointer、materialized revision、Task head 和 execution revision 位于不同 耐久边界。publisher 必须在同一提交内证明“正在提交的仍是当前 active generation”, 并保存可精确重放、可恢复、可审计的 generation receipt。
决策
1. 不新增 workspace package
纯规划与共享 repository contract 放入既有
@qinglong/runtime-core/plugin-package-task-reconciliation。SQLite adapter 放入
@qinglong/local-sqlite/plugin-package-task-reconciliation 显式 subpath;
PostgreSQL adapter 只从 @qinglong/cluster-postgres/package-executor 导出。
该切片没有独立部署、依赖、版本或供应链生命周期,因此不创建只有一两个文件的新
workspace importer。它不新增第三方依赖、timer、watcher、socket、连接池或常驻缓存;
packages/ 仍保持 21 个 importer。
2. generation 是唯一批次,receipt 是提交事实
新增 qinglong/plugin-package-task-reconciliation@v1 receipt。每份 receipt 精确绑定:
- Project、Package、generation、lock digest 和 previous lock digest;
- active
generationDigest与 materialized revision digest; - 该 generation 的完整 Task item 集合;
- 每项最终
taskId、revision、content digest 与 disposition; - domain-separated receipt digest 和数据库提交时间。
任务 identity 固定为 pkg:<packageName>:<resourceId>。单次 reconciliation 最多处理
512 项;输入 facts 必须与“当前 materialized Task 集合 ∪ 上一代 receipt item 集合”
完全相等,少项、多项、重复项或外来项均失败关闭。
disposition 只有:
created;retained;updated;disabled;already_disabled。
upgrade 中消失的 Task 不删除,而是以新不可变 revision 设置 enabled=false;已禁用
任务不重复写 revision。语义未变的 Task 保留原 revision,不因 generation 变化制造
写放大。
3. 规划是纯函数,提交重新复验全部 fence
runtime-core planner 只接受规范化 materialized revision、上一代 receipt 和数据库 观察到的 Task/ownership facts,产生确定性 mutation ID、TaskDefinition writes、 execution plans 与 receipt。它不取得数据库、文件、网络或 active pointer authority。
adapter 在提交前和事务内都要复验:
- materialized revision identity;
- active install 的 installation、generation、lock 与 previous lock;
- 上一代 receipt chain;
- Task head revision/content digest;
- Package ownership;
- 完整 item/write/execution-plan coverage。
任何 fence 漂移都必须整体回滚。相同 generation、相同 receipt 是 exact replay;同一 generation 绑定不同 receipt 是 conflict。
4. Task ownership 是长期数据库事实
双方言新增 plugin_package_task_ownerships,以
Project + taskId 为主键并保存 packageName、首次 claim generation digest 与时间。
ownership 不随 disable、upgrade 或安装历史回收而删除。
首次 create 必须在创建 Task head 的同一事务 claim ownership;后续只有相同 Package 可以更新。其他 Package、人工 publisher 或通用 Task repository 不得接管。SQLite 和 PostgreSQL 的通用 TaskDefinition append 入口都在事务内拒绝已被 Package claim 的 Task,避免绕过专用 publisher。
5. SQLite 使用一个 BEGIN IMMEDIATE
SQLite 新增:
QingLong3PluginPackageTaskOwnerships;QingLong3PluginPackageTaskReconciliations;QingLong3PluginPackageTaskReconciliationItems。
0047-plugin-package-task-reconciliations 安装三表、索引、CHECK、FK 和 owned trigger;
0048-capability-v24 把 local capability 推进至 v24。catalog 当前为 43 张 owned
table。
repository 复用既有单 operation authority,在一个 BEGIN IMMEDIATE 中完成:
- active generation 与上一代 receipt 复验;
- Task head/revision CAS;
- command Task 的 local execution revision;
- ownership claim;
- receipt 和 item 明细。
事务中任一步失败都不得留下 Task、execution plan、ownership 或 receipt 的部分状态。
6. PostgreSQL 只允许 Package executor 调用受审函数
PostgreSQL pg-0026-plugin-package-task-reconciliations 增加同义三表,并把
control-core capability 推进至 v25;migration stream 为 26 条,catalog 为 41 张表。
ql3_package_executor 没有对 Task head/revision、execution revision、ownership 或
receipt 表的原始 INSERT/UPDATE/DELETE authority。唯一写入口是:
ql3.commit_plugin_package_task_reconciliation(
char(64), char(64), jsonb, jsonb, jsonb
)
该 SECURITY DEFINER 函数固定 search_path、复验 session_user 属于
ql3_package_executor、锁定 active install/Task heads,并在一个数据库事务内执行与
SQLite 同义的 fence、CAS、ownership、execution revision 和 receipt 提交。
runtime、admin、package-manager、worker-ingress、PUBLIC 均无函数执行权和新表写权; manager 不能把公开管理请求提升为 execution authority,常驻 runtime 也不能直接发布 Package Task。
7. 当前只关闭 TaskDefinition 发布缺口
本 ADR 不注册 Tool handler,不激活 Workflow/Prompt,不绑定 Secret,也不把 materialized revision 自动接入生产启动。生产 coordinator 仍须按以下顺序显式装配:
- 读取 active generation;
- 精确读取 immutable materialized revision;
- 调用专用 reconciliation repository;
- 再次观察 active generation;
- 只有 receipt 与当前 generation 一致时才允许后续 consumer admission。
在 coordinator、startup recovery 与用户可见状态完成前,该能力保持显式 subpath、 默认不可达。
Profile 影响
- edge/standalone:没有后台 reconciliation;每次显式安装/恢复只使用一个 SQLite writer transaction。未变化 Task 不新增 revision,适合低性能路由设备。
- cluster:多个 executor 可竞争,但数据库锁、CAS、ownership 和 generation receipt 使同一代只产生一个结果。executor 无原始表写权限。
- worker:不导入 planner/repository,不读取 receipt,不取得 Package 发布 authority。
被否决方案
- 为 planner、receipt 或双方言 adapter 分别新建 package:没有独立生命周期,
会继续把
packages/拆成单文件包;现有 package 的显式 subpath 已满足隔离。 - 逐 Task 调用通用 repository:一代中途失败会产生部分可见状态,也无法原子保存 generation receipt。
- 删除 upgrade 中移除的 Task:会破坏历史 Run/execution/audit 引用;禁用新 revision 保留审计连续性。
- 以 namespace 字符串代替 ownership 表:字符串约定不能阻止通用 publisher 或 并发 Package 抢占。
- 给 executor 原始表写权限:应用层校验可被绕过,无法证明 item/write/receipt 同成同败。
- 把 Task revision 直接嵌入 materialized revision 当作已发布:语义事实不等于 当前 Task head,也不能给 scheduler/executor 提供既有 CAS 和 execution revision。
验证
- runtime-core:两代 create/retain/update/disable 规划、receipt digest、完整 coverage、 ownership collision、head drift 和确定性 mutation identity;
- SQLite:真实
DatabaseSync共享 contract、exact replay、第二代 retain/disable/create、 active generation 漂移整体回滚、通用 Task publisher 旁路拒绝; - PostgreSQL 18.4 arm64 真库:26 条 migration 后两代 reconciliation 与 exact replay 通过,完整集成测试 34 pass、0 fail、1 个环境能力相关 skip;
- PostgreSQL package:146 pass、0 fail、1 个真库条件 skip;
- PostgreSQL physical HA:timeline 1→2、
remote_apply、旧主先 fencing、standby promotion、旧主pg_rewind只读重入以及 promotion 前后 package-executor v25 readiness/ACL 均通过,最终gates.passed=true。
上述 HA 结果证明 schema、函数 identity 和最小权限契约可随 WAL/promotion 保持 ready, 但本轮没有在分区或 COMMIT-response-loss 窗口中提交 reconciliation receipt,因此不能 宣称已经取得 Task reconciliation 事务级故障注入证明。
后续
- 实现唯一 production materialization coordinator 与 bounded startup recovery;
- 把 reconciliation receipt 纳入 PostgreSQL HA 的 COMMIT-response-loss 与 promotion durable inspection matrix;
- 建立 immutable Tool registry generation snapshot;
- 建立 Workflow/Prompt 版本仓库和 activation contract;
- 在 Run/execution 引用图完整后设计 Package Task 与 materialized revision 的 retention/GC;此前禁止删除 ownership、receipt 或历史 revision。