Files
qinglong/docs/adr/ADR-0493-target-native-reconciliation-domain-preservation.md
T

74 lines
5.3 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-0493:目标原生 Reconciliation 域分类与身份保留
- 状态:Accepted
- 日期:2026-08-24
- 决策:D-398
- 关联:ADR-0483、ADR-0484、ADR-0485、ADR-0488、ADR-0492
## 背景
Reconciliation 必须同时处理两类不同事实:从 2.x 迁入的数据,以及已经属于 QingLong 3.0 目标库的原生数据。此前实现把 `identity_policy_audit` 整域无条件标为 `manual_required/identity_custody_required`,因此即使 Legacy 完全没有 `Auths/Users`fresh v52 目标库自带的 Project、RoleBinding、Credential、Pepper、SecurityAudit 与 LocalOwner 表也会阻止全局 completion。
同一盘点还发现 fresh v52 的六张已知表没有进入稳定领域,被误归为 `unknown`
- Automation`QingLong3LegacyAdoptions``QingLong3LegacyAdoptionTasks``QingLong3LocalExecutionContextRecipes``QingLong3LocalTaskExecutionRevisions`
- Run History`QingLong3RunAttemptLogArtifactTombstones``QingLong3RunAttemptLogRetentionState`
这不是缺少新 adapter,而是现有 planner 对目标原生 schema 的知识不完整。为绕过门禁而伪造 completion receipt 或把整个 `QingLong3*` 前缀视为可信都会破坏 fail-closed 边界。
## 决策
### 1. 已知目标表使用精确领域目录
上述六张表按精确表名分别归入 Automation 与 Run History。Schema object 继续按其 `tableName` 继承同一领域,因此相关 index/trigger 不需要单独的宽泛名称规则。
不引入 `QingLong3*``LegacyAdoption*``Local*` 的整体通配。未来新增但尚未登记的目标表仍进入 `unknown`,不读取行数,并要求人工外部处理。
### 2. 目标原生身份是保留事实,不是迁移事实
`identity_policy_audit` 的 disposition 改为按来源判定:
- Legacy 存在 `Auths/Users` 时继续 `manual_required`
- Legacy 没有身份事实、Target 有已知身份事实时为 `target_only`
- 两端都没有时为 `aligned`
Target 身份诊断是 `required/reviewable_fact`,必须在 signed review 中逐事实选择 `retain_target` 才能形成 `no_effect` application action。它不能选择 `adopt_legacy``exclude_legacy`。Legacy 身份诊断仍是 `blocked/identity_custody_required`,只允许 `defer|manual_external`,本 ADR 不声明 2.x credential、session、password hash、token、Policy 或 Audit 已迁移。
### 3. Completion 只消费既有闭合证据
本 ADR 不增加 completion schema、adapter、instance state 或绕过规则。目标原生身份经过 canonical diagnostics、signed decision 和 application summary 后,以既有 `no_effect/application_summary` 进入 completion;真正未知表和任何 Legacy 身份事实仍阻止 completion。
完整 v52 + Legacy Secret/Config fixture 必须通过真实 v3 completion,而不是测试直接构造 receipt、推进 head 或调用 storage collector。只有 completed head durable 后,Secret/Config backup 才能由既有流程回收。
### 4. 部署与资源边界不变
实现只修改既有 Local Owner 一次性 reconciliation planner/reviewer,没有新增 workspace package、production dependency、SQL migration、daemon、listener、timer、Pool、容器或 Kubernetes workload。Edge/Standalone 常驻闭包、SQLite cache 上限和 artifact 预算不变;Cluster 仍使用自己的 PostgreSQL、Secret provider 与 HA authority。
## 被拒绝的替代方案
### 为目标原生身份增加 migration adapter
拒绝。没有 Legacy 身份输入时不存在要迁移的数据;额外 adapter 只会复制已经由目标数据库拥有的事实并扩大权限面。
### 信任全部 QingLong3 前缀
拒绝。名称前缀不是 schema ownership 证明,会让未来未知表自动越过人工审查。
### 自动跳过目标身份评审
拒绝。`target_only` 仍必须形成逐事实 signed `retain_target` 决策,不能仅凭分类器直接授权 completion。
### 放行 Legacy Auths/Users
拒绝。旧身份材料的 custody、hash/token 兼容、撤销、Policy 与 Audit 语义尚未建立独立 adapter;本 ADR 只消除目标原生数据被误当成迁移输入的问题。
## 验证
- 定向回归 `4/4`fresh v52 `unknown=0`、目标身份 `retain_target`、Legacy 身份继续 blocked、真正未知表继续 row-free/manual
- Secret/Config completion v3 使用真实 `complete → replay → verify` 链路,首调 `completed`、重放 `existing`receipt 为 v3 且 Identity/Unknown 均为 `no_effect`
- completed head durable 后 Secret/Config backup 被回收,加密 material 与 receipt 保持只读;
- Local Owner 受限沙箱为 `301 total / 291 pass / 7 conditional skip / 3 loopback EPERM`,两个 loopback 文件在沙箱外 `15/15`,有效结果 `301/294/7/0`
- 完整 backend 为 `1567 total / 1565 pass / 2 conditional skip / 0 fail`18-package clean build 与逐包顺序测试除 Worker 三条 sandbox loopback 外全部通过,对应 Worker 文件在沙箱外 `8/8`
- package boundary、精确 Cluster dependency、122-module Edge import、service-manager bridge import、本地镜像与 `14/14` Local artifact audit 全部 compatibleworkspace 保持 18 packages`singleSourcePackages=[]``shallowSourcePackages=[]`
- 基础 Edge/Standalone 保持 `2,635,529 / 2,635,607 bytes`、323 files、58 loaded modules,没有 Cluster/PostgreSQL 闭包。