Files
qinglong/docs/adr/ADR-0454-target-instance-manual-primary-canary-ceremony.md
T

91 lines
9.0 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-0454:目标实例 Manual Primary Canary 与显式回滚仪式
- 状态:Accepted(仪式实现完成;首次真实用户目标实例执行仍待运维)
- 日期:2026-08-19
- 关联 RFCQL-RFC-0001 D-361、PR-4、PR-5
- 关联 ADRADR-0002、ADR-0449、ADR-0450、ADR-0451、ADR-0453
- AmendsADR-0453 的首次目标实例 canary 操作缺口
- Amended byADR-0455 的 Profile-bounded durable runtime activation receipt
## 上下文
ADR-0453 已提供 process-epoch capture authority、clean-shutdown evidence、closed terminal audit、compiled-backend rollback/resource report、Primary gate bundle 与
rollout manifest v2 loader,但维护者仍需手工拼接多个命令、文件名、时间窗口和摘要。只提供底层 gate 会留下四类运维缺口:
1. canary 开始前没有不可变计划绑定 Profile、精确样本数和当时的 live rollout 基线;
2. terminal/resource/gate 输出容易经 shell 重定向得到宽权限、部分写入或互相不属于同一 session 的文件;
3. qualification 与写入 live manifest 之间没有显式人工边界,配置选择又容易被误报成“当前进程已经激活”;
4. rollback 没有绑定被替换 manifest 的摘要,也没有 crash-replay intent/completion 链。
Edge 可能是 128 MiB 路由设备,不能为 canary 新增 daemon、watcher、遥测栈或第二数据库;Standalone 可能运行在集群节点上,但本仪式仍只裁决本机
`edge|standalone` Profile,不得借宿主机形态伪装成 `cluster-control|worker` Primary 证据。
## 决策
1. 新增 `qinglong/manual-primary-canary-plan@v1``prepare` 只接受受控 session ID、`edge|standalone`、Edge 精确 8 条或 Standalone 32128 条中由
operator 选定的精确 admission 数;它记录当前 `qinglong3-rollout.json` 为 absent 或 disabled+SHA-256。已有 enabled manifest 时拒绝准备。
2. plan 固定派生全部 basename,不接受调用方提供输出路径。config root 必须是当前 UID 拥有、非 symlink、group/world 不可写的真实目录;所有 artifact 均以
`0600`、同目录临时 inode、file fsync、hard-link no-replace 与 directory fsync 发布。重复调用只接受逐字节相同文件。
3. `prepare` 只输出三项部署环境:实际 Profile、`QL3_SHADOW_ORIGINS=manual` 与唯一 capture basename;它不写 enabled manifest、不启动任务、不重启服务。
operator 必须在隔离窗口中通过既有 Legacy 产品入口精确执行计划数量的 manual admission,并干净关闭同一 worker;任何额外 manual execution 都使样本不相等。
4. `observe` 只有在 capture qualified、单一 manual origin、计数精确且窗口结束至少五分钟后,才以固定参数启动 Node 24 terminal auditor。数据库必须为非 symlink、
group/world 不可写的普通文件;auditor 只读打开 SQLite。调用方不能注入 origin、window、settling、child script 或 shell。
5. `resource` 用固定 `full + require-compiled + 8 samples` 启动 ADR-0451 runner。它使用自身临时 SQLite,不接触生产数据库;低配设备必须在应用停止后运行,不能把
与常驻 workload 争用内存后的失败解释为产品回归。
6. `qualify` 复用 ADR-0453 gate,但额外绑定 plan 文件摘要、三份 source 的原始文件摘要、三份 canonical JSON 摘要、精确 admission target 与 gate 文件摘要。
现有 gate、partial qualification 或 response loss 只能通过原文件重放;source 在 qualification 后被替换时,mutating CLI 与独立 auditor 都失败关闭。
7. `approve` 是唯一写 live manifest 的操作。它要求显式 `approvedBy`,审批最短一分钟、最长 24 小时;先复核 plan 时的 absent/disabled 基线,disabled 基线先
no-replace 归档,再以同目录 fsync 临时文件和最终摘要复核发布 schema v2 manifest。结果状态固定为 `activation_approved`/`primary_selected`,并明确
`requiresRestart=true``runtimeActivationObserved=false`;配置选择不得冒充 HTTP worker 已完成 startup reconciliation 和 router activation。
8. 应用重启后,实际运行态由 bootstrap 的 `selected → reconciled → durable active receipt → activated` 证明。ADR-0455 已让独立 auditor 复核 receipt 与 Linux
boot/PID/start-time 联合身份,并新增 `active` 要求;`off|rolled-back` 同时要求不存在仍 current 的 runtime。非 Linux portable receipt 不能获得 current 结论。
9. `rollback` 只接受四个固定 reason 与有界 operator。它先 no-replace 发布 intent,绑定当前 enabled manifest SHA-256 和目标 disabled SHA-256,再复核当前摘要并原子替换
live manifest,最后发布 completionintent 或 completion response loss 可用相同参数重放。disabled 已有效但不同于本 session 的目标时拒绝覆盖。
10. 审批过期后,loader 对下一次 bootstrap 必须 fail-closed 为 off;状态/auditor 报 `approvalExpired=true``rolloutMode=off`。无 watcher 的既有进程不会仅因磁盘
审批过期而自动卸载 router,故 `off` 审计会在 current receipt 仍存活时失败。operator 必须显式 rollback 并停止/重启应用;过期不能被当作自动续期、自动删除或已停止证明。
## 被拒绝的替代方案
### 常驻 watcher 自动检测 capture 并启用 Primary
拒绝。它把一次性证据变成后台控制面,增加路由设备 timer/文件监控成本,并绕过独立人工审批。
### Canary CLI 自动触发八个用户任务
拒绝。工具没有用户会话、Task Policy、脚本内容或副作用 authoritysynthetic spawn 不能证明真实 Legacy 产品入口的 admission capture。
### 用 enabled manifest 存在表示 Primary 已运行
拒绝。manifest 只在下次 bootstrap 被读取;进程可能尚未重启、startup reconciliation 可能失败或审批已经过期。selection 与 runtime activation 必须分开陈述。
### 原地覆盖证据和 rollout 文件以方便重试
拒绝。覆盖会丢失冲突和 crash window。证据采用 no-replacelive rollout 只在摘要复核后原子替换,并由 previous/intent/completion 文件保留恢复链。
## 资源、安全与部署影响
- 正常 QingLong runtime 不新增 import、timer、watcher、listener、数据库连接、schema、migration、package 或生产依赖。全部动作由 operator 一次性调用。
- plan/qualification/selection/rollback 报告不包含数据库路径、命令、Task、Run、Cron、PID、日志、用户输出、错误正文或 Secretstdout 只返回 stage、Profile、样本数和布尔状态。
- `observe` 只读生产 SQLite`resource` 只使用 runner 的临时 SQLite。Edge 应在应用停止后运行 resourceStandalone 也不得与同机生产 canary 并发争用。
- POSIX owner 是本机信任根。摘要复核能防止误覆盖和非协作漂移,但不能防御同一 UID 在最后复核与 rename 之间的恶意并发;共享 config root 或远程 delegation 需要
另行引入签名/锁服务,不得把本仪式描述成多写者共识。
- 本仪式不适用于 `cluster-control|worker`,也不证明物理路由、flash wear、断电、跨主机签名或真实生产任务安全。
## 验证
- domain/CLI 聚焦矩阵覆盖 Edge/Standalone 样本预算、exact shape、短期审批、prepare 重放、unsafe root、disabled baseline drift、source replacement、partial
qualification、selection receipt response loss、审批过期、rollback intent/completion response loss及独立审计。
- 真实 compiled backend 已通过 D361 `prepare → resource`Edge plan 保持 automatic activation falseresource 阶段产生 qualified full rollback evidence
enabled/off 进程 peak RSS 分别为 `109,953,024 / 102,383,616` bytes,真实 Legacy child 均 exit 0Shadow Run delta 从 1 收敛为 0。
- 阶段门已重跑:聚焦 `24/24``build:back`、完整 backend `1,481 pass / 0 fail / 2 conditional skip`、18-package clean build/test、四项架构审计与
`14/14` artifact audit 全部通过;产物字节与 D-360 一致。隔离 frozen-lockfile Linux arm64 Docker 的 128 MiB router/256 MiB Edge release peak 分别为
`81,887,232 / 148,840,448` bytes`memory.events max/oom/oom_kill` 增量均为 0。
- D361 不修改 PostgreSQL schema/migration、依赖树或 Kubernetes 拓扑,因此不重跑 PostgreSQL HA;任何仓库 synthetic fixture、compiled resource child 或 Docker
arm64 结果都不沿用、也不冒充尚未执行的真实目标实例 manual capture/activation。
## 后续
维护者仍需在一台真实目标 Edge 或 Standalone 实例执行 [Manual Primary Canary 操作手册](../operations/ql3-manual-primary-canary.md),并保留 capture、terminal、resource、
gate、qualification、selection、bootstrap activated audit 与 rollback completion。其他 origin 必须建立自己的 admission authority 与 gate;固定物理路由/flash/断电、
多写者 config authority 仍是独立后续工作;运行态 durable activation receipt 已由 ADR-0455 补齐,但首次真实目标实例执行仍待运维。