mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
feat(ql3): atomically apply cluster legacy env migration
This commit is contained in:
@@ -148,6 +148,32 @@
|
||||
arm64 physical HA 通过 146 gates、timeline `1→2`,报告 SHA-256 为
|
||||
`0ee2199d0a52a02025bff017a07477d707353d12aefc3811f474e3775f2bb86b`。
|
||||
|
||||
- D-402/ADR-0497(已验收):Cluster Legacy Env plan 现在可以在一个 Project-serialized
|
||||
`SERIALIZABLE` transaction 中真正提交。profile-neutral contract 使用可重放、按 ID 排序的
|
||||
Task/Trigger mutation stream,并分别冻结 source revision-set 与 mutation-set digest;repository
|
||||
每批只保留 128 项,先迁移 Task,再迁移 Trigger,支持 100,000/500,000 上限而不在管理节点
|
||||
JS 堆保存全集。
|
||||
|
||||
Task current head、Plugin ownership、`command@v1` semantic、旧 digest 与数据库时间均在写前复验;
|
||||
新 Task revision 保留原字段,只追加固定 `environmentBundleRef`,enabled Task 同时生成 Cluster
|
||||
execution revision。Trigger 复验自己的 current revision、旧 Task pin 和 schedule fence,随后固定
|
||||
到同 application 的新 Task revision;合法的历史 pin 不要求等于迁移前 Task current head。
|
||||
Trigger revision、head CAS、schedule claim/due reset 和 fence 递增与 Task DML 原子提交。
|
||||
|
||||
`pg-0071-cluster-legacy-env-migration-applications` 将 PostgreSQL contract 推进到 v70,增加 application、
|
||||
Task item、Trigger item 三张 content-free append-only receipt 表。只有 Automation Manager 拥有
|
||||
`SELECT, INSERT`;runtime/admin 和其余角色无权限。exact replay 重新验证 durable heads、execution
|
||||
revisions 和 schedules,但不会再次消费输入流。实现仍复用 runtime-core/cluster-postgres,没有新增
|
||||
package、生产依赖、daemon 或 Edge import。
|
||||
|
||||
Runtime Core `591/591`、Cluster PostgreSQL `361 total / 358 pass / 3 conditional skip / 0 fail`、
|
||||
v70 定向门 `74/74` 均为零失败。PostgreSQL 18.6 arm64 HA 再次通过 146 gates、timeline `1→2`,
|
||||
最终报告 SHA-256 为 `42ca97de43cfebd4611282b1fd5c0b09030eda89e88144967497902b01d18b3a`;
|
||||
真实用例覆盖 Trigger 固定 Task r1、Task current r2、原子生成 Task r3/Trigger r2 并重定向 pin,
|
||||
同时证明 bundle ref-only execution、schedule reset、无流消费 replay 与数据库角色隔离。D-402
|
||||
关闭 mutation/receipt 边界;direct external custody、promotion 后 receipt replay 和固定低性能 Edge
|
||||
物理证据仍是 ADR-0491 转 Accepted 前的门禁。
|
||||
|
||||
- D-396/ADR-0490(已验收):Run History 不再只有永久 `manual_external`,但也没有被错误实现为 Legacy 日志到 3.0 Run ledger 的回灌。
|
||||
新的 Local adapter 以 ADR-0482 sealed capture bundle 作为 append-only 保全资产:Legacy history 必须逐事实选择 `retain_both`,Target history
|
||||
必须选择 `retain_target`;receipt 只绑定 signed review、application、bundle fingerprint、领域 inventory 与有界 fact counts,不保存表名、Run ID、
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# ADR-0491:有界 Secret/Config Reconciliation 与任务环境绑定
|
||||
|
||||
- 状态:Proposed(D-397 已实现 Legacy Env inspection、私有有界 row plan、durable plan publication、独立 signed decision、逐项 Automation adoption provenance、Local SQLite 原子 application publisher、Owner prepared/apply/rollback 编排、ADR-0492 completion v3;ADR-0494 完成 Cluster mounted-files provider live 子门,ADR-0495 完成 content-free Cluster plan ledger baseline,ADR-0496 完成 opaque environment bundle 的 Worker 内存展开与 HA-validated 数据面;真实 Edge 空间证据、Cluster Task/Trigger mutation/receipt、promotion 后 receipt replay 与直接外部 custody gate 尚未完成)
|
||||
- 状态:Proposed(D-397 已实现 Legacy Env inspection、私有有界 row plan、durable plan publication、独立 signed decision、逐项 Automation adoption provenance、Local SQLite 原子 application publisher、Owner prepared/apply/rollback 编排、ADR-0492 completion v3;ADR-0494 完成 Cluster mounted-files provider live 子门,ADR-0495 完成 content-free Cluster plan ledger,ADR-0496 完成 opaque environment bundle 数据面,ADR-0497 完成 Cluster Task/Trigger 原子 mutation 与 receipt;真实 Edge 空间证据、promotion 后 receipt replay 与直接外部 custody gate 尚未完成)
|
||||
- 日期:2026-08-23
|
||||
- 决策:D-397
|
||||
- 关联:ADR-0073、ADR-0074、ADR-0092、ADR-0094、ADR-0480、ADR-0482、ADR-0483、ADR-0484、ADR-0485、ADR-0486、ADR-0487、ADR-0488、ADR-0490
|
||||
@@ -147,4 +147,4 @@ D-397 当前八切片已经实现:absent、unsupported、Edge over-budget、2.
|
||||
|
||||
ADR-0494 已完成 Cluster `mounted-files` provider live 子门:真实三节点 K3s 中两个 management replica、direct exact-key executor 和两个跨节点 provider observer 完成 PostgreSQL durable approval/binding、Kubernetes atomic projection rotation、无 Secret API 权限/ServiceAccount token、只读 `0440`、内容脱敏及删除后 fail-closed;v2 私有报告 24/24 gates 为 true,并保持 v1 verifier 兼容。该门不增加 Edge 闭包,也不等于直接 Vault/KMS/HSM custody。
|
||||
|
||||
转为 Accepted 前仍必须完成:固定低性能 Edge 设备的真实空间/写放大/断电恢复证据,以及 Cluster Legacy Env migration 的逐项 Task/Trigger current-head revalidation、revision mutation/receipt、外部 custody adapter 和 HA promotion 后 receipt replay。ADR-0495 已完成专用 PostgreSQL SERIALIZABLE plan ledger baseline,但它只保存摘要、计数和 pinned SecretRef,不执行 Task/Trigger DML,也不接触 Secret material。ADR-0496 已验收只保存 pinned bundle ref、通过 fenced remote delivery 取回 typed carrier、在 Worker 内存展开的安全数据面,并通过 146-gate PostgreSQL HA;它仍不执行 migration DML 或生成 migration receipt。ADR-0492 已完成本机 completion schema 演进和 completed-head 后 rollback material 回收,ADR-0493 又让没有 Legacy 身份输入的 fresh v52 目标身份经 signed `retain_target` 正确形成 no-effect,并精确消除六张已知目标表的 `unknown` 误判。Legacy `Auths/Users` 或真正未知表仍保持 manual;本切片的 Local Owner 编排、ADR-0494 的 mounted-files gate、ADR-0495 的 plan ledger、ADR-0496 的数据面或 PostgreSQL HA 证据都不得冒充完整 Cluster migration 与外部密钥托管。
|
||||
转为 Accepted 前仍必须完成:固定低性能 Edge 设备的真实空间/写放大/断电恢复证据、直接外部 custody adapter,以及 HA promotion 后对既有 application receipt 的 exact replay。ADR-0495 已完成专用 PostgreSQL plan ledger,ADR-0496 已完成只保存 pinned bundle ref、通过 fenced remote delivery 取回 typed carrier 并在 Worker 内存展开的数据面;ADR-0497 又在一个 Project-serialized SERIALIZABLE transaction 中完成逐项 Task/Trigger current-head revalidation、revision/execution mutation、schedule reset 和 content-free append-only receipt,并支持合法历史 Task pin。它仍不写入 Secret material、不等于 direct Vault/KMS/HSM custody,也尚未在 promotion 后重放同一 application receipt。ADR-0492 已完成本机 completion schema 演进和 completed-head 后 rollback material 回收,ADR-0493 又让没有 Legacy 身份输入的 fresh v52 目标身份经 signed `retain_target` 正确形成 no-effect,并精确消除六张已知目标表的 `unknown` 误判。Legacy `Auths/Users` 或真正未知表仍保持 manual;Local Owner 编排、mounted-files gate、plan/application ledger 或通用 PostgreSQL HA 证据都不得冒充完整外部密钥托管。
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
- 决策:D-400
|
||||
- 关联:ADR-0104、ADR-0233、ADR-0259、ADR-0491、ADR-0494
|
||||
|
||||
> 2026-08-24:ADR-0497/D-402 已完成本 ADR 所列的下一切片:在同一 Automation Manager
|
||||
> SERIALIZABLE transaction 中复验并迁移 Task/Trigger,重置 schedule fence,并写入逐项
|
||||
> content-free receipt。本 ADR 的 plan ledger 决策保持不变。
|
||||
|
||||
## 背景
|
||||
|
||||
ADR-0491 已完成 Local SQLite 上的 Legacy Env 检查、人工裁决、Secret application、
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
- 决策:D-401 前置切片
|
||||
- 关联:ADR-0091、ADR-0092、ADR-0104、ADR-0113、ADR-0114、ADR-0491、ADR-0494、ADR-0495
|
||||
|
||||
> 2026-08-24:ADR-0497/D-402 已完成本 ADR 所要求的 Task/Trigger mutation 与 migration
|
||||
> receipt;本 ADR 继续定义 opaque bundle 的安全数据面,direct external custody 与 promotion
|
||||
> 后 receipt replay 仍是后续门禁。
|
||||
|
||||
## 背景
|
||||
|
||||
ADR-0495 的 Cluster plan 只保存一个同 Project、固定 version 的 SecretRef,并明确禁止把
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
# ADR-0497:Cluster Legacy Env 的原子 Task/Trigger 迁移与只追加回执
|
||||
|
||||
- 状态:Accepted
|
||||
- 日期:2026-08-24
|
||||
- 决策:D-402
|
||||
- 关联:ADR-0104、ADR-0233、ADR-0259、ADR-0491、ADR-0495、ADR-0496
|
||||
|
||||
## 背景
|
||||
|
||||
ADR-0495 冻结了无敏感内容的 Cluster migration plan,ADR-0496 又让 Task 与执行修订只需保存
|
||||
一个固定版本的 `environmentBundleRef`。此前仍缺少真正提交计划的 authority:如果分别调用现有
|
||||
Task 与 Trigger repository,会开启两个独立事务,出现 Task 已改而 Trigger、schedule 或 receipt
|
||||
尚未提交的裂脑窗口;如果一次把 100,000 个 Task 和 500,000 个 Trigger 全部装入 JS 数组,又会
|
||||
让 Automation Manager 在低内存节点上不可用。
|
||||
|
||||
迁移还必须处理合法的历史 pin:Trigger 可能仍固定 Task r1,而 Task 当前 head 已推进到 r2。
|
||||
新 Trigger 应固定本次迁移产生的 Task r3,不能错误假设旧 Trigger pin 等于 Task current head。
|
||||
|
||||
## 决策
|
||||
|
||||
### 1. 使用可重放流与双摘要冻结输入
|
||||
|
||||
新增 profile-neutral application contract 与
|
||||
`qinglong/cluster-legacy-env-migration-application-receipt@v1`。调用方提供可重放的 Task/Trigger
|
||||
mutation stream;每项包含 ordinal、实体身份、旧 revision/content digest 和独立 UUID mutation。
|
||||
Task 与 Trigger 分别计算 source revision-set digest 和 mutation-set digest:前者必须匹配已发布
|
||||
plan,后者必须匹配 application intent。
|
||||
|
||||
流必须从 ordinal 0 连续、按 Task/Trigger ID 严格递增,不允许重复、未知字段、非规范 UUID 或
|
||||
超过 100,000/500,000 项。Task/Trigger ID 延续现有定义契约的 128-byte、无控制字符边界,不用
|
||||
更窄的 ASCII 正则误伤合法历史数据。Trigger 可以为空,但 Task 至少一个。
|
||||
|
||||
### 2. 一个 Project-serialized SERIALIZABLE 事务完成全部写入
|
||||
|
||||
Automation Manager repository 先开启 `SERIALIZABLE`,取得 domain-separated Project advisory
|
||||
transaction lock,再验证 active Project、plan ID/digest 和 exact mutation replay。每批最多只保留
|
||||
128 项,先完整处理 Task,再处理 Trigger;任何流摘要、head、ownership、spec 或 CAS 不一致都会
|
||||
回滚 receipt 和全部 revision DML。
|
||||
|
||||
Task 阶段对每个 current head 执行 `FOR UPDATE`,拒绝 Plugin-owned、非 `command@v1`、已有
|
||||
`environmentBundleRef`、revision/digest 漂移和数据库时间倒退;新 revision 保留 name、description、
|
||||
command config、labels、enabled 与 created time,只追加 plan 中的固定 bundle ref。enabled Task 同时
|
||||
生成新的 `remote_worker` Cluster execution revision,数据库只保存 ref,不保存 Env 名称或值。
|
||||
|
||||
Trigger 阶段复验 current Trigger revision、旧 Task pin 和 schedule revision,保留 spec 与 enabled,
|
||||
但绑定同 application 中该 Task 的新 revision/content digest。新 Trigger revision、head CAS 与
|
||||
schedule reset 同事务提交;schedule 清空 due/claim 字段并递增 state/claim fence。旧 Trigger pin
|
||||
可以是历史 revision,不要求等于 Task 迁移前 current head。
|
||||
|
||||
### 3. v70 提供三张只追加、无敏感内容的回执表
|
||||
|
||||
`pg-0071-cluster-legacy-env-migration-applications` 将 control contract 推进到 v70,新增:
|
||||
|
||||
- `cluster_legacy_env_migration_application_receipts`:application/plan/mutation、四个 set digest、
|
||||
固定 bundle ref、计数、数据库提交时间和精确 canonical receipt JSON;
|
||||
- `cluster_legacy_env_migration_application_tasks`:每个 Task 的 before/after revision digest、mutation、
|
||||
可选 execution digest 和 item digest;
|
||||
- `cluster_legacy_env_migration_application_triggers`:每个 Trigger 的 before/after revision、旧 Task pin、
|
||||
新 Task pin 和 item digest。
|
||||
|
||||
表中没有 Env name/value、bundle carrier、plaintext/ciphertext、key ID、Task/Trigger spec、命令或
|
||||
provider path。application/plan/mutation/receipt 唯一,ordinal 与 revision 关系有 named constraints;
|
||||
子表通过 `(application_id, project_id)` 复合外键隔离 Project,Trigger item 又通过复合外键固定到
|
||||
同 application 的 Task item。三表均从 PUBLIC 撤销,只向 `ql3_automation_manager` 授予
|
||||
`SELECT, INSERT`,不授予 UPDATE/DELETE/TRUNCATE。
|
||||
|
||||
### 4. Exact replay 不重新消费输入流
|
||||
|
||||
相同 application mutation 先读取 durable receipt,精确比较 intent,然后聚合验证 Task heads、
|
||||
Task/execution revision、Trigger heads/revision 和 schedule 仍与逐项 receipt 一致。验证成功直接返回
|
||||
`existing`,不调用 Task/Trigger stream factory;intent drift、receipt 缺项、ordinal gap 或 current
|
||||
head 已继续推进均失败关闭。序列化、死锁和 lock timeout 使用新 stream factory 最多重试三次。
|
||||
|
||||
### 5. 不为该能力新增微包或 Edge 常驻成本
|
||||
|
||||
纯契约位于既有 `runtime-core` 的显式 subpath,PostgreSQL authority 位于既有
|
||||
`cluster-postgres` 显式 subpath;不进入 runtime/admin/root entrypoint,不新增 workspace package、
|
||||
生产依赖、daemon、controller、timer、watcher 或全集缓存。低内存 Cluster 节点只承担固定 128 项
|
||||
batch;Edge/Standalone 默认 import graph 不加载 PostgreSQL authority。
|
||||
|
||||
## 被拒绝的替代方案
|
||||
|
||||
### 分别调用 Task 与 Trigger repository
|
||||
|
||||
拒绝。两个事务无法保证 Task、Trigger、schedule 和 receipt 原子,response loss 也无法证明哪一半
|
||||
已经提交。
|
||||
|
||||
### 先收集全部候选再写数据库
|
||||
|
||||
拒绝。100,000/500,000 上限会把路由级设备或小型管理节点变成内存压力点;可重放有序流和固定 batch
|
||||
已经能在事务回滚后重新计算摘要。
|
||||
|
||||
### 要求 Trigger 旧 Task pin 等于 Task current head
|
||||
|
||||
拒绝。不可变 Trigger 合法固定历史 Task revision;只需复验该旧 pin,并把新 Trigger 显式重定向到
|
||||
本次 application 产生的新 Task revision。
|
||||
|
||||
### 把 Task/Trigger spec 或 Env 名称写进 receipt
|
||||
|
||||
拒绝。revision 本身已经保存规范 spec;receipt 只需要 identity、digest、count 和 fence,复制内容会
|
||||
扩大 PostgreSQL backup、HA replica 和审计泄漏面。
|
||||
|
||||
## 当前验证与后续门禁
|
||||
|
||||
runtime-core 完整测试 `591/591`;cluster-postgres package 测试 `361 total / 358 pass / 3
|
||||
conditional skip / 0 fail`;v70 migration/schema/readiness 定向门 `74/74`。真实 PostgreSQL 18.6
|
||||
arm64 HA 多次通过 146 gates,timeline `1→2`;最终报告 SHA-256 为
|
||||
`42ca97de43cfebd4611282b1fd5c0b09030eda89e88144967497902b01d18b3a`。
|
||||
|
||||
真实数据库用例证明:带空格的合法 Task/Trigger ID 可迁移;Trigger 固定 Task r1、Task current r2
|
||||
时会原子生成 Task r3 与 Trigger r2 并让新 Trigger 固定 r3;execution plan 只出现 bundle ref;
|
||||
schedule fence 递增且 claim/due 清空;exact replay 不消费 stream;Automation Manager UPDATE 以及
|
||||
runtime/admin SELECT 均以 `42501` 被拒绝。
|
||||
|
||||
本 ADR 关闭 D-402 的 Cluster Task/Trigger application/receipt 边界,但 ADR-0491 仍保持 Proposed。
|
||||
后续仍必须完成 direct Vault/KMS/HSM custody、migration Job 的短期身份与装配、在 PostgreSQL
|
||||
promotion **之后**对既有 application receipt 执行 exact replay,以及固定低性能 Edge 设备的真实
|
||||
空间、写放大、断电与恢复证据。
|
||||
@@ -499,6 +499,8 @@
|
||||
| [ADR-0493](./ADR-0493-target-native-reconciliation-domain-preservation.md) | 目标原生 Reconciliation 域分类与身份保留 | Accepted |
|
||||
| [ADR-0494](./ADR-0494-postgresql-secret-binding-and-mounted-provider-live-rotation.md) | PostgreSQL Secret Binding 与 Mounted Provider 在线轮换门 | Accepted |
|
||||
| [ADR-0495](./ADR-0495-content-free-cluster-legacy-env-migration-plan-ledger.md) | 无敏感内容的 Cluster Legacy Env 迁移计划账本 | Accepted |
|
||||
| [ADR-0496](./ADR-0496-opaque-cluster-environment-bundle-delivery.md) | Cluster 不透明环境 Bundle 的有界交付与 Worker 内存展开 | Accepted |
|
||||
| [ADR-0497](./ADR-0497-atomic-cluster-legacy-env-migration-application.md) | Cluster Legacy Env 的原子 Task/Trigger 迁移与只追加回执 | Accepted |
|
||||
|
||||
## 规则
|
||||
|
||||
|
||||
Reference in New Issue
Block a user