6.9 KiB
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 与 Automation,ADR-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 重新验证:
- sealed Application plan 的
secret_and_config=manual_external; - 同一 Application 上 ready、无 skip 的 signed Secret/Config decision;
- exact apply intent、receipt、decision/SecretConfig identity、preparation digest 与 apply digest;
- 当前 target snapshot 等于 Secret/Config
targetAfter; - apply storage 是合法的
applied或 completion 后completedlayout,且不存在 rollback receipt; - 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 新增唯一合法边:
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 evidence,root、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而保持 manual;ADR-0493 已通过精确分类与 signedretain_target修正这两个本地 planner 缺口。LegacyAuths/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 closure:8 个 Local 依赖包与 Local Owner 全部通过;
- 完整 backend:
1567 total / 1565 pass / 2 conditional skip / 0 fail; - 18-package clean build 与逐包顺序测试单次退出 0;package boundary、Cluster dependency、122-module Edge import、service-manager bridge import、本地镜像与
14/14Local 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 后续工作。