feat(ql3): commit service manager legacy rollback

This commit is contained in:
whyour
2026-08-20 17:40:29 +08:00
parent ad291e514d
commit 2cd6ea1d55
16 changed files with 3382 additions and 62 deletions
+20
View File
@@ -11,6 +11,26 @@
最新增量证据(2026-08-20):
- D-380/ADR-0473(已接受;OpenRC live actor 待镜像基础设施恢复后补跑):完成 systemd/OpenRC service-manager rollback 的
安全 commit 协议。`rollback_prepared` 不再被误当作 root 授权;Owner 重新绑定当前 head、preparation、Application 与
legacy-silence commitment 原始摘要、descriptor 摘要后,才 no-replace 发布 `legacy_restart_requested`。短生命周期 root bridge
只允许固定 `qinglong`/`qinglong3`、固定 descriptor 与固定 systemd/OpenRC argv,启动前证明双服务 inactive,并在任何 start 前写
durable barrierbarrier 后所有重放只能 inspect,响应丢失可按 legacy active/target inactive 与进程身份收敛,无法证明则由 Owner
消费为 `manual_required`,永不盲目二次 start。Owner 是 instance head 的唯一终态写者,成功 CAS 到 `legacy_running` 并支持
exact replay;该状态只证明 init/process running 与 target stopped,不宣称 2.x 业务健康。实现仍在现有 Local Owner package,且将
回滚四模块内聚到 `service-manager/legacy-rollback/`,没有新 package、production dependency、binary、daemon、watcher、timer、
socket、数据库连接或部署对象。聚焦门 `16/16`Local Owner 全量
`181 total / 176 pass / 5 conditional skip / 0 fail`backend 全量
`1,523 total / 1,521 pass / 2 conditional skip / 0 fail`18-package clean build/逐包测试单次退出 0。package boundary、
Service Bridge import、Edge import、Cluster dependency、Cluster/Worker deployment、Console 与 Console distribution 八项审计
全部 compatible/passedworkspace 仍为 18 packages、`singleSourcePackages=[]``shallowSourcePackages=[]`Local Owner 为
`111 source / 110 nested / 1 root binary entry`。14 档 Local artifact audit 全部 compatible;基础 Edge/Standalone 保持
`2,598,669 / 2,598,747` bytes、316 files、57 loaded modulesAdopted 为 `2,817,964 / 2,818,087` bytes、58 loaded modules
Application+AI 为 `4,501,822 / 4,501,954` bytesMCP 为 `7,324,601 / 7,324,709` bytes。systemd live actor 已覆盖
root/non-root success、真实 manager start、response-loss inspect convergence、Owner consume/replayroot barrier-crash 证明没有
第二次 start,双服务均 inactive 并收敛为 manual。OpenRC 因本机缺少基础镜像且 `node:24-alpine` credential helper 挂起未执行,
不能宣称全组合门已闭合;临时容器/镜像/tag 已清理。本切片不改变 PostgreSQL schema、ACL、repository、role、Pool、连接或
failover 语义,因此不重跑且不重新占有 HA 证明。D-381 应补 OpenRC 证据与 `legacy_running` 后的有界 2.x readiness/health proof。
- D-379/ADR-0472(已接受;OpenRC live actor 待镜像基础设施恢复后补跑):为 systemd/OpenRC adopted cutover 增加 Owner-side
`service-legacy-rollback-prepare`。命令绑定 exact `target_stopped` record 与 instance head,重读 stop intent、Application v3、
activation 和 legacy-silence commitment,并复用 Docker 路径相同的 stable-fd SHA-256/inode/sidecar reconciliation。
@@ -0,0 +1,115 @@
# ADR-0473Service Manager Legacy Rollback Commit
- 状态:Accepted
- 日期:2026-08-20
- 关联 RFCQL-RFC-0001 D-64、D-274、D-275、D-379、D-380
- 关联 ADRADR-0314、ADR-0315、ADR-0362、ADR-0363、ADR-0472
## 背景
ADR-0472 已使 systemd/OpenRC adopted cutover 能在 Owner authority 内把安全候选推进到
`rollback_prepared`,但它刻意不授予 root mutation,也不能证明旧服务已经重新运行。若 root 直接把
`rollback_prepared` 当作启动授权,Owner 的数据判断、init mutation 与最终实例状态会混成一个不可审计步骤;若在响应丢失后
再次执行 `start`,又可能越过崩溃窗口重复副作用。
本阶段还必须同时适配低配路由设备和集群节点:回滚不能引入新 daemon、watcher、连接池或部署对象,也不能为了源码目录变密就
制造单文件 workspace package。编辑前 GitNexus 对 preparation、service bridge、deployment CLI、live actor 与 Docker gate
涉及的既有符号完成 upstream impact;均为 LOW,最多 3 个直接/累计上游、0 条已识别 execution flow。
## 决策
### 1. Owner 授权与 root mutation 分离
Owner 只能通过私有命令文件执行:
```text
ql3-local-deploy service-legacy-rollback-authorize --command-file <private.json>
```
授权必须重新验证当前 instance head、`rollback_prepared` record、Application 原始字节摘要、legacy-silence commitment 原始字节
摘要、目标 descriptor 摘要和 manager kind,并 no-replace 发布 `legacy_restart_requested`。preparation 不是 root 授权,root bridge
只接受这一种当前 head 和 exact authorization digest。
### 2. root bridge 只允许固定服务和固定 argv
root bridge 的唯一新操作是 `local.deployment.service-manager.legacy-rollback.execute`。它只允许:
- legacy 服务名 `qinglong` 与 target 服务名 `qinglong3`
- systemd descriptor `/etc/systemd/system/qinglong.service` 或 OpenRC descriptor `/etc/init.d/qinglong`
- 受审的固定 `systemctl``rc-service` argv,不接受 shell、任意 executable、服务名或路径;
- 启动前同时证明 legacy inactive、target inactive,并复验 Owner application/commitment/authorization 与 descriptor 原始摘要。
bridge 在任何 start 前先 no-replace 写 durable root barrier。barrier 之后的所有重放都只能 inspect,永不再次 start。
### 3. 响应丢失按双服务观察收敛
若 manager 实际完成 start 但响应丢失,重放读取 barrier 并检查两个固定服务:只有 legacy active、target inactive,且进程身份与
manager 观察一致时,root outcome 才是 proved running。若 barrier 已存在但无法证明上述事实,结果固定为 unproved,交给 Owner
终结为 `manual_required`;不得猜测、删除 barrier、替换 descriptor 或自动启动 target。
root outcome 先于 Owner outcome 持久化,因此 root 成功后 Owner 进程崩溃仍可用相同输入恢复,不重复 init mutation。
### 4. Owner 是实例终态唯一写者
Owner 通过:
```text
ql3-local-deploy service-legacy-rollback-consume --command-file <private.json>
```
消费 exact root outcome。只有 root 证明 legacy running、target stopped,且 authorization/head/digest 全部一致时,才 CAS 到
`legacy_running`;任一不确定、漂移或双服务冲突都进入 `manual_required`。exact replay 返回同一 completion,不覆盖已存在的不同
Owner outcome。
`legacy_running` 只证明 init/process running 与 target stopped,不代表 QingLong 2.x HTTP、任务调度、数据库或业务健康。
### 5. 保持部署与 package 边界
实现留在现有 `@qinglong/local-owner-cli`。为避免 `service-manager/` 继续平铺超过直接源码文件阈值,回滚子域内聚为:
```text
service-manager/legacy-rollback/
preparation.ts
contract.ts
consumer.ts
bridge.ts
```
不新增 workspace package、production dependency、binary、daemon、timer、watcher、socket、数据库连接、systemd/OpenRC unit 或
Kubernetes workload。root bridge 仍是显式短生命周期命令。
## 被否决方案
1. **把 `rollback_prepared` 直接交给 root**:准备事实不是启动授权,拒绝。
2. **barrier 重放再次调用 start**:响应丢失会重复副作用,拒绝。
3. **root 直接写 instance head**:会混淆 OS mutation 与 Owner 状态 authority,拒绝。
4. **只检查 legacy active**:target 同时运行时会制造双主,拒绝。
5. **把 `legacy_running` 宣称为业务健康**init/process 观察不足以证明 2.x readiness,拒绝。
6. **新建 rollback package 或 daemon**:没有独立交付/依赖/生命周期依据,并放大路由设备闭包,拒绝。
## 验收证据
- 聚焦 Owner/contract 门 `16/16`Local Owner 全量 `181 total / 176 pass / 5 conditional skip / 0 fail`
- 18-package clean build/逐包测试单次退出 0backend 全量
`1,523 total / 1,521 pass / 2 conditional skip / 0 fail`
- package boundary、Service Bridge import、Edge import、Cluster dependency、Cluster/Worker deployment、Console 与 Console
distribution 八项审计全部 compatible/passed。workspace 仍为 18 packages、`singleSourcePackages=[]`
`shallowSourcePackages=[]`Local Owner 为 `111 source / 110 nested / 1 root binary entry`
- 14 档 Local artifact audit 全部 compatible。基础 Edge/Standalone 为 `2,598,669 / 2,598,747` bytes、316 files、
57 loaded modulesAdopted 为 `2,817,964 / 2,818,087` bytes、58 loaded modulesApplication+AI 为
`4,501,822 / 4,501,954` bytesMCP 为 `7,324,601 / 7,324,709` bytes。回滚 authority 未进入基础运行闭包。
- systemd live actor 已覆盖 root/non-root 成功、真实 manager start、响应丢失后的 inspect-only 收敛、Owner
`legacy_running` 消费与 exact replayroot barrier-crash 场景证明没有第二次 startlegacy/target 均保持 inactiveOwner 收敛为
`manual_required`
- OpenRC actor 因本机缺少 Alpine/OpenRC 基础镜像,拉取 `node:24-alpine` 时 credential helper 挂起而未执行;因此本 ADR
不宣称 systemd/OpenRC 全组合门闭合。临时 systemd 容器、测试镜像和临时 tag 均已清理。
- 本阶段不修改 SQL、migration、PostgreSQL repository/role/Pool 或 HA 语义,因此不重新生成 PostgreSQL HA 证据。
## 未完成
- OpenRC root/non-root success 与 root barrier-crash live actor
- `legacy_running` 后有界、可重放的 2.x readiness/health proof
- 固定物理 Edge 的完整 prepare/authorize/execute/consume 回滚证据;
- `reconciliation_required` 的 export、冲突裁决与受审回灌。
本 ADR 关闭 service-manager 回滚的安全 commit 与进程级收敛,不代表 QingLong 3.0 升级/回退 Gate 已全部完成。
+1
View File
@@ -476,6 +476,7 @@
| [ADR-0470](./ADR-0470-session-scoped-console-capability-discovery.md) | Console 会话级能力发现与服务端操作围栏 | Accepted |
| [ADR-0471](./ADR-0471-legacy-core-api-compatibility-baseline.md) | Legacy 核心执行 API 兼容基线 | Accepted |
| [ADR-0472](./ADR-0472-service-manager-legacy-rollback-preparation.md) | Service Manager Legacy Rollback Preparation | Accepted |
| [ADR-0473](./ADR-0473-service-manager-legacy-rollback-commit.md) | Service Manager Legacy Rollback Commit | AcceptedOpenRC live actor 待补) |
## 规则