Files
qinglong/docs/adr/ADR-0492-compatible-secret-config-completion-v3.md
T

91 lines
6.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR-0492:兼容 Secret/Config 的 Reconciliation Completion v3
- 状态:Accepted
- 日期:2026-08-24
- 决策:D-397
- 关联:ADR-0487、ADR-0488、ADR-0490、ADR-0491
## 背景
ADR-0488 的 completion v1 只识别 Application 与 AutomationADR-0490 的 v2 再加入 Run History。ADR-0491 已经让 Secret/Config 形成 signed decision、原子 application receipt、写后 target snapshot、applied head 与可恢复 backup,但旧 completion 无法消费这些证明,也不能在全局完成后回收 Secret/Config 的数据库等量 rollback material。
Application plan 中 `secret_and_config` 的历史 action 是 `manual_external`。这是专用 adapter 获得授权前的正确失败关闭状态,不能改写 sealed plan 为 `adapter_required`。Completion 必须验证后续 plan、signed decision 和 apply 全链路,再在自己的 receipt 中把该域收敛为已证明的 adapter;它仍不能替其他 `manual_external` 域背书。
## 决策
### 1. 保持 v1/v2 精确兼容,新增 v3
`local.deployment.reconciliation.complete|complete.verify` 新增 schema v3。v1/v2 的输入 shape、receipt 语义和验证路径保持不变;只有 receipt 包含 `secret_config_application` 时版本才为 v3。v3 可同时携带 Automation、Secret/Config 与 Run History authority`adapterCount` 由八域证据实际推导并扩大为 `0|1|2|3`,调用方不能自报。
Secret/Config completion binding 只包含 `secretConfigId``decisionId``expectedApplyDigest`。options 只携带 plan/decision/apply authority roots 和 target SQLite 路径,不重新携带 keyring、credential 或明文 material。所有 authority roots 必须互不重叠;Automation 与 Secret/Config 同时存在时必须指向同一个 target SQLite。
### 2. 证明链必须闭合
Completion 重新验证:
1. sealed Application plan 的 `secret_and_config=manual_external`
2. 同一 Application 上 ready、无 skip 的 signed Secret/Config decision
3. exact apply intent、receipt、decision/SecretConfig identity、preparation digest 与 apply digest
4. 当前 target snapshot 等于 Secret/Config `targetAfter`
5. apply storage 是合法的 `applied` 或 completion 后 `completed` layout,且不存在 rollback receipt
6. source head 是 `reconciliation_secret_config_applied` 且绑定 apply digest。
若 Automation 也先写入同一数据库,当前 target 不再等于 Automation 的旧 `targetAfter`。此时链式证明固定为 `Secret/Config backup.sha256 == Automation targetAfter.sha256`,然后再验证当前 target 等于 Secret/Config `targetAfter`;不得把合法的后续写入误判为 Automation drift,也不得跳过两阶段之间的 digest 连续性。
Rolled-back state、target drift、decision/apply 脱离、提前丢失 backup、unknown `Configs`、Identity/Policy/Audit、Unknown 或任意其他未终态域都继续拒绝全局 completion。Secret/Config 已 applied 不代表整个 reconciliation 已完成。
### 3. durable head 先于 rollback material 回收
Instance lineage 新增唯一合法边:
```text
reconciliation_secret_config_applied → reconciliation_completed
```
既有边、generation、source digest 和 CAS 规则不变。Receipt 必须先 no-replace 发布并封存,随后 completed head durable,最后才可删除 Automation 与 Secret/Config backup。两类 storage 都接受 `applied|completed` 重放:head 尚未 completed 时 backup 缺失立即失败;head 已 completed 后允许任一 backup 已回收,并幂等收敛剩余 backup。
Secret/Config completed layout 删除的只有 `backup/before.sqlite`。加密 `materials.ndjson`、intent 与 apply receipt 保留为 `0400` audit evidenceroot、backup root 与空 rollback work root 封为 `0500`。该操作不扫描数据库、不创建数据库等量副本、不引入 timer/GC,适合低容量 Edge;真正销毁 ciphertext 或 sealed Legacy source 仍是后续独立 retention ceremony。
### 4. 部署边界不变
实现全部位于既有 `@qinglong/local-owner-cli` 的 cutover、completion 与 Secret/Config application 子域,没有新增 workspace package、production dependency、SQL migration、daemon、listener、watcher、timer、Pool、容器或 Kubernetes workload。Edge/Standalone 常驻闭包不加载该一次性 Owner authority。
Cluster 不复用本机 receipt、POSIX storage 或 instance head。Cluster completion 仍需要 PostgreSQL SERIALIZABLE ledger、外部 Secret provider/KMS、HA timeline 与 promotion 后验证。
## 影响
- completion receipt 的消费者必须按 `schemaVersion` 解析,未知版本继续失败关闭。
- `advanceLocalCutoverInstanceHead` 是 CRITICAL 共享状态机;本 ADR 只增加一条 source-state 边,不改任何旧 transition。
- 本 ADR 验收时完整迁移库仍会因目标原生 `identity_policy_audit` 和六张未登记 v52 表落入 `unknown` 而保持 manualADR-0493 已通过精确分类与 signed `retain_target` 修正这两个本地 planner 缺口。Legacy `Auths/Users` 和真正未知表仍保持全局围栏。
- v3 verify 要求 completed storage,不能在 head durable 之前充当修复命令。
## 被拒绝的替代方案
### 改写 sealed Application plan
拒绝。历史 `manual_external` 是 adapter 授权前的事实;事后把它改成 `adapter_required` 会破坏签名、digest 与审计语义。
### 只检查 Secret/Config apply receipt
拒绝。孤立 receipt 不能证明 signed decision、当前 target、source head、Automation 前序写入或 rollback 状态。
### completion 前删除 backup
拒绝。receipt/head crash window 仍可能需要显式 rollback;提前删除会让响应丢失不可恢复。
### 为 Edge 增加后台 GC
拒绝。一次性 completion 已能固定内存、幂等回收;常驻 timer 会扩大路由设备资源与生命周期表面。
## 验证
- completion v3 定向:`3/3`,覆盖 exact Secret/Config evidence、其他 manual 域失败关闭、rolled-back、target drift、v3 receipt、lineage 边和 completed-storage 幂等回收;
- completion v1/v2 兼容:no-effect v1、Automation rollback retention 与 Run History v2 均通过;
- Local Owner:受限沙箱 `300 total / 290 pass / 7 skip / 3 loopback EPERM`,对应两个 loopback 文件在沙箱外 `15/15`,有效结果 `300/293/7/0`
- TypeScript package closure8 个 Local 依赖包与 Local Owner 全部通过;
- 完整 backend`1567 total / 1565 pass / 2 conditional skip / 0 fail`
- 18-package clean build 与逐包顺序测试单次退出 0package boundary、Cluster dependency、122-module Edge import、service-manager bridge import、本地镜像与 `14/14` Local artifact audit 全部 compatible
- workspace 保持 18 packages`singleSourcePackages=[]``shallowSourcePackages=[]`;基础 Edge/Standalone 为 `2,635,529 / 2,635,607 bytes`、323 files、58 loaded modules。
阶段提交后的远程 CI 仍需重新验证;D-397 的真实 Edge 空间证据和 Cluster Secret provider live gate 仍属于 ADR-0491 后续工作。