mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
docs(ql3): freeze legacy deployment lineage contract
This commit is contained in:
@@ -11,6 +11,15 @@
|
||||
|
||||
最新增量证据(2026-08-21):
|
||||
|
||||
- D-388/ADR-0481(契约已冻结,实施中):D-387 的 committed data receipt 只作为启动前置事实,不获得 activation 或
|
||||
rollback authority。新增 adopted-only Application v4,精确绑定 `commitPath/expectedCommitDigest/expectedReceiptDigest`,
|
||||
并要求 Application 在 signal、SQLite、Secret、Plugin、AI 之前以 no-follow、stable-stat 和 canonical digest 验证。
|
||||
既有 `ql3-local-deploy` 将增加独立 `local.deployment.adopted.prepare|verify`,不复用 fresh setup、不安装或启动服务;
|
||||
systemd/OpenRC 保持 Owner intent → 最小 root bridge → Owner consumer,root 不解析 receipt,最终 cutover journal 显式携带
|
||||
commit/receipt digest。adopted Compose 不再错误复用 fresh `/var/lib/qinglong3` path mapping,而使用宿主与容器路径字节相同的
|
||||
identity-preserving deployment/source bind,保证 SQLite activation path digest 在真实容器内仍成立;preflight/apply/restore/
|
||||
evidence lineage 必须继承同一 receipt。v2 fresh 与 v3 SQLite-only adoption 保持兼容,不新增 package、dependency 或常驻对象。
|
||||
本条只记录 Proposed contract,不能在实现、故障重放、完整测试、架构与 artifact 门完成前宣称 Accepted。
|
||||
- D-387/ADR-0480(已接受):把 D-386 prepared model 推进为受认证、Project-scoped、可审计且可恢复的原子 application。
|
||||
既有 `ql3-adoption` 增加 exact `local-data-directory.adoption.apply|apply.verify`;Owner credential 通过独立短生命周期 SQLite handle 建立
|
||||
`local_data_adoption` 强认证并要求目标 Project 的 `secret.manage`,publisher 在 `BEGIN IMMEDIATE` 内再次复验 credential、Project 与
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
# ADR-0481:Committed Legacy Data Receipt 的本机部署 Lineage
|
||||
|
||||
- 状态:Proposed(D-388 契约冻结)
|
||||
- 日期:2026-08-21
|
||||
- 关联 RFC:QL-RFC-0001 D-05、D-06、D-17、D-64、D-87、D-184、D-259、D-388
|
||||
- 关联 ADR:ADR-0194、ADR-0309、ADR-0310、ADR-0313、ADR-0314、ADR-0362、ADR-0476、ADR-0477、ADR-0478、ADR-0479、ADR-0480
|
||||
|
||||
## 背景
|
||||
|
||||
ADR-0480 已把 Legacy `config/db/ssh.d` prepared model 原子提交到 Local SQLite,并在 transformation root
|
||||
留下内容无关、可精确验证的 `commit.json`。但是现有部署链只绑定 SQLite activation、Legacy silence
|
||||
commitment、Application config、进程 identity 与 service/Compose outcome。D-387 的 `commitDigest` 和数据库
|
||||
`receiptDigest` 尚未进入 systemd、OpenRC 或 Compose 的启动事实。
|
||||
|
||||
这不是日志字段缺失,而是 authority 缺口:现有 adopted Application v3 不认识 data application receipt,部署者
|
||||
可以先完成 D-387,再继续用一个只绑定 SQLite activation 的 v3 config 启动目标;相反,若把 D-387 apply 与
|
||||
service start 合并,又会让数据迁移 credential 获得 activation 权限,并破坏 ADR-0480 已明确的职责分离。
|
||||
|
||||
Compose 还有一个更早的产品缺口。fresh v2 固定把 deployment root 映射到 `/var/lib/qinglong3`;SQLite activation
|
||||
却绑定宿主机 canonical source/target path digest。直接把 adopted config 的路径改成容器路径会让真实 Application
|
||||
校验失败,继续依赖测试中的合成 mount evidence 也不能称为受审 adopted Compose create/config。
|
||||
|
||||
本决策只处理本机 Edge/Standalone。Cluster 必须使用 PostgreSQL、separation-of-duty、控制面 rollout 与集群专用
|
||||
fencing;不能复用本机私有文件或 Owner credential ceremony。
|
||||
|
||||
## 决策
|
||||
|
||||
### 1. Receipt 是启动前置事实,不是启动授权
|
||||
|
||||
D-387 的 `commit.json` 证明一个 prepared transformation 已经完成数据库提交和明文逻辑回收。它不表示:
|
||||
|
||||
- 配置、SSH binding、Task 或 Trigger 已启用;
|
||||
- Legacy 已静默;
|
||||
- systemd/OpenRC unit 已安装、enable 或 start;
|
||||
- Compose target 可以 `up`;
|
||||
- target 可以回退,或 Legacy 可以重新启动。
|
||||
|
||||
因此 data apply、deployment bundle prepare、service/Compose activation 和 rollback 继续是四个独立命令与 durable
|
||||
事实。任何一步成功都不隐式调用下一步。
|
||||
|
||||
### 2. Application v4 精确绑定 committed application
|
||||
|
||||
新增只允许 `storage.mode=adopted` 的
|
||||
`qinglong/local-application-process@v4`。它保留 v3 的 `storage` 与 `cutover`,并增加 exact 字段:
|
||||
|
||||
```json
|
||||
{
|
||||
"legacyDataApplication": {
|
||||
"commitPath": "/absolute/private/transformation/commit.json",
|
||||
"expectedCommitDigest": "64-hex",
|
||||
"expectedReceiptDigest": "64-hex"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Application 在取得 signal、SQLite、Secret、Plugin Package、AI 或 lifecycle authority 前,按以下顺序失败关闭:
|
||||
|
||||
1. 解析 exact v4 config,要求所有 authority path 规范、非 root、互异且有界;
|
||||
2. 使用 no-follow descriptor 有界读取私有 `commit.json`,复核 owner、mode、link count、inode 与读前后 stat;
|
||||
3. 校验 D-387 exact schema、`state=committed`、reclamation 三项固定值与 payload-domain digest;
|
||||
4. 同时匹配 config 的 `expectedCommitDigest`、`expectedReceiptDigest`、Profile,以及 storage activation 所绑定的
|
||||
transformation/target 事实;
|
||||
5. 再验证既有 Legacy silence commitment,然后才进入 adopted storage startup。
|
||||
|
||||
v2 fresh 行为不变。v3 仍表示“只接管 SQLite、没有声明完整 data-directory application”的兼容模式;完成 D-387
|
||||
并要把其结果作为部署前置事实的路径必须使用 v4,部署 prepare 不得为该路径生成 v3。
|
||||
|
||||
### 3. Canonical commit codec 下沉到既有 SQLite adoption domain
|
||||
|
||||
`commit.json` 的 payload 本来由 SQLite adoption receipt 派生。canonical type、exact normalizer 与 digest 计算放在
|
||||
现有 `@qinglong/local-sqlite/data-directory-adoption` 子路径,由 D-387 cleanup、Application startup gate 和 Owner
|
||||
deployment consumer 共同复用。文件身份读取仍由各自 authority owner 负责。
|
||||
|
||||
这不是新 package,也不让 Local SQLite 读取 deployment journal、调用 init/Docker 或获得 service authority;它只
|
||||
共享内容无关的纯数据 contract,避免 Application 与 Owner 各自维护一份易漂移的 schema。
|
||||
|
||||
### 4. 新增 adopted bundle prepare/verify,但不激活服务
|
||||
|
||||
既有 `ql3-local-deploy` 增加 exact、私有 command-file 操作:
|
||||
|
||||
```text
|
||||
local.deployment.adopted.prepare
|
||||
local.deployment.adopted.verify
|
||||
```
|
||||
|
||||
命令精确绑定 Profile、instance/cutover、deployment root、SQLite source/target/recovery/manifest/activation、Legacy
|
||||
silence commitment、D-387 commit/receipt,以及 systemd、OpenRC、Compose 三选一 service contract。prepare 在发布
|
||||
任何文件前验证全部源证据,随后 no-replace 发布 Application v4 config、描述符和一个内容无关 bundle receipt;verify
|
||||
只验证终态,绝不修复、install、enable、start、stop、pull image 或连接 socket。
|
||||
|
||||
该操作不执行 `local.setup`,因为 target SQLite、Owner pepper、Secret keyring 和 D-387 receipt 已存在。fresh
|
||||
`local.deployment.prepare` 保持 v2/`local.setup` 语义,避免把两种 authority 混成大量 optional 字段。
|
||||
|
||||
### 5. systemd/OpenRC 保持 Owner → root bridge → Owner consumer
|
||||
|
||||
Application v4 config 的文件 SHA-256 继续进入 service-manager intent,因此短生命周期 root bridge 可传递绑定而无需
|
||||
解析 D-387 schema、打开 SQLite 或读取 transformation root。root bridge 仍只执行固定 manager/argv 并发布 outcome。
|
||||
|
||||
Owner consumer 必须重新读取 v4 config、commit 和既有 activation/commitment/data evidence。新的 cutover journal
|
||||
版本显式记录:
|
||||
|
||||
- `legacyDataApplicationCommitDigest`;
|
||||
- `legacyDataApplicationReceiptDigest`;
|
||||
- 既有 `applicationConfigDigest`、`activationDigest` 与 `commitmentDigest`。
|
||||
|
||||
restart/stop 必须保持同一 commit/receipt binding;发生漂移时不能调用 manager。Legacy rollback preparation 可以读取
|
||||
该 lineage,但 `commitDigest` 绝不替代既有 stopped evidence、双阶段授权、barrier 和 readiness proof。
|
||||
|
||||
### 6. adopted Compose 使用 identity-preserving bind
|
||||
|
||||
fresh v2 Compose 继续把 deployment root 映射到 `/var/lib/qinglong3`。adopted v4 不复用这一映射,而要求:
|
||||
|
||||
- target、recovery、manifest、activation、cutover commitment、D-387 commit 与运行时可写目录均位于私有
|
||||
deployment root;
|
||||
- deployment root 以 source 与 target 相同的 canonical absolute path 绑定进容器;
|
||||
- Legacy SQLite source 作为唯一额外 bind,同样映射到相同 canonical absolute path;
|
||||
- 描述符固定 read-only rootfs、无网络、cap-drop、no-new-privileges、UID:GID 和 Profile memory/PID 上限;
|
||||
- adopted target 不使用隐式 `unless-stopped` 绕过 generation/Legacy reproof。
|
||||
|
||||
这样 Application 看到的 path 字节与 activation 中的 path digest 相同,不需要重写已签定的证据,也不扩大为任意
|
||||
caller-supplied mount 表。Compose config inspection 必须精确验证两条 mount、config path、restart policy、image digest、
|
||||
generation 和 mutation labels。
|
||||
|
||||
Compose preflight 在任何 `compose up` 前验证 v4 commit/receipt,并把二者加入 rollout receipt。apply 的 exact replay、
|
||||
失败回收、restore 与 evidence collection 必须继承同一 binding;restore 仍只恢复目标 SQLite generation,不删除 D-387
|
||||
提交、不重新创建已回收明文,也不自动启动 Legacy。
|
||||
|
||||
### 7. 低配与大节点使用同一协议、不同预算
|
||||
|
||||
本能力不新增 workspace package、production dependency、daemon、timer、watcher、listener、数据库连接或后台 retry。
|
||||
Application 常驻路径只增加一次不超过 64 KiB 的私有 JSON 读取和 SHA-256;Owner/Compose 验证均为人工触发的一次性
|
||||
操作,不扫描历史。
|
||||
|
||||
Edge 保持 128 MiB/64 PID 描述符预算,Standalone 保持 256 MiB/256 PID。两档共享同一 receipt/lineage schema,避免
|
||||
低配设备成为弱协议;Cluster 节点不因此获得本机模式的规模或高可用声明。
|
||||
|
||||
## 故障与重放语义
|
||||
|
||||
- commit 在 prepare 前漂移:不发布 bundle;
|
||||
- prepare 在文件发布中崩溃:原命令只按 deterministic content/no-replace 收敛,未知额外文件失败关闭;
|
||||
- service/Compose activation 前漂移:不调用 manager/Docker;
|
||||
- manager/Docker side effect 后响应丢失:沿用既有 barrier 与 inspect-only recovery,不因 receipt 重新执行副作用;
|
||||
- Application 读取 commit 后、storage 前 commit 被替换:descriptor identity/stat 复核失败;
|
||||
- 已 active 后 commit 被删除或漂移:下一次 restart/stop consumer 失败关闭并进入既有人工诊断路径;当前进程不引入
|
||||
watcher,因此不冒充运行期间持续 attestation;
|
||||
- rollback:必须执行既有显式 prepare/authorize/consume 或 Compose restore ceremony,receipt 本身没有回退权限。
|
||||
|
||||
## 被拒绝的替代方案
|
||||
|
||||
### 只把 `commitDigest` 加进 stdout 或 service intent
|
||||
|
||||
拒绝。Application 仍可用 v3 直接启动,root/Compose side effect 也可能发生在 Owner 复核前。
|
||||
|
||||
### D-387 apply 成功后自动 start
|
||||
|
||||
拒绝。数据迁移 credential 会获得 deployment authority,且 COMMIT-response-loss 会让自动副作用无法安全重放。
|
||||
|
||||
### Application 导入 Owner CLI 或直接调用 systemd/Docker
|
||||
|
||||
拒绝。会把短生命周期部署 authority 带入低配常驻闭包,并破坏 root bridge 的最小解析面。
|
||||
|
||||
### adopted Compose 继续映射到 `/var/lib/qinglong3`
|
||||
|
||||
拒绝。会改变 activation 已绑定的 path identity;重新计算 digest 等于伪造一份没有原 ceremony 支持的新证据。
|
||||
|
||||
### 为 receipt 建立新 workspace package或常驻 watcher
|
||||
|
||||
拒绝。canonical codec 已有 SQLite adoption owner;watcher 既不能回滚外部 side effect,也会为路由设备增加常驻成本。
|
||||
|
||||
### 用 receipt 自动允许 Legacy rollback
|
||||
|
||||
拒绝。receipt 证明新数据已提交,反而意味着回退更需要数据 reconciliation;它不证明 target stopped 或 Legacy ready。
|
||||
|
||||
## 验收条件
|
||||
|
||||
1. v4 config、commit schema/digest/Profile/receipt/path 任一漂移,Application 在 signal/storage 前失败;v2/v3 既有语义不变。
|
||||
2. adopted prepare/verify 对 systemd、OpenRC、Compose 均可 exact replay,且不产生 install/start/socket/network 副作用。
|
||||
3. systemd/OpenRC root bridge 不解析 commit;Owner cutover journal 显式绑定 commit/receipt,restart/stop 漂移失败。
|
||||
4. adopted Compose 真实 config 使用 identity-preserving mount,preflight/apply/restore/evidence lineage 保留 commit/receipt。
|
||||
5. activation 与 rollback 仍需既有独立命令;D-387 apply 或 bundle prepare 单独成功不会改变服务状态。
|
||||
6. 覆盖成功、exact replay、commit/config/mount 漂移、发布崩溃、manager/Docker 响应丢失、ENOSPC 与低配资源边界。
|
||||
7. 完整 package/backend、架构、distribution、artifact 门通过;workspace package 数、浅包审计和常驻依赖闭包不退化。
|
||||
|
||||
## 未包含
|
||||
|
||||
- Cluster/PostgreSQL/Kubernetes 的 prepared-model application 与 rollout;
|
||||
- 运行期间持续文件 attestation 或 tamper remediation;
|
||||
- `scripts/upload` 的最终启用、Task/Trigger activation、SSH host-key 审核;
|
||||
- 数据产生后的自动 reconciliation 或 Legacy restart;
|
||||
- 固定物理 Edge/NAS 的断电、FTL 写放大和加密卷销毁证明。
|
||||
@@ -484,6 +484,7 @@
|
||||
| [ADR-0478](./ADR-0478-private-legacy-data-directory-staging.md) | 私有 Legacy Data Directory 暂存与稳定校验 | Accepted |
|
||||
| [ADR-0479](./ADR-0479-private-versioned-legacy-config-keyv-ssh-transformation.md) | 私有、版本化的 Legacy Config、Keyv 与 SSH 转换 | Accepted |
|
||||
| [ADR-0480](./ADR-0480-authenticated-atomic-legacy-data-application.md) | 受认证、原子且可恢复的 Legacy Data Application | Accepted |
|
||||
| [ADR-0481](./ADR-0481-committed-legacy-data-deployment-lineage.md) | Committed Legacy Data Receipt 的本机部署 Lineage | Proposed(D-388 契约冻结) |
|
||||
|
||||
## 规则
|
||||
|
||||
|
||||
Reference in New Issue
Block a user