Files
qinglong/docs/adr/ADR-0307-bounded-durable-local-deployment-status.md
T

5.4 KiB
Raw Blame History

ADR-0307:有界且诚实的本机部署持久状态

  • 状态:Accepted
  • 日期:2026-08-09
  • 关联 RFCQL-RFC-0001 D-05、D-06、D-17、D-87、D-184、D-199、D-201、D-202、D-258
  • 关联 ADRADR-0086、ADR-0194、ADR-0197、ADR-0199、ADR-0201、ADR-0202、ADR-0257

背景

QingLong 3.0 的本机部署工具已经能以私有 command file 准备 systemd/OpenRC/Compose bundle,并为 Compose revision、preflight、apply、失败回滚、SQLite restore 与证据收集提供可重放事务。但每个命令 只返回本次操作结果。CLI 响应丢失、operator shell 退出或设备重启后,部署用户没有一个低成本入口确认 当前 Profile、service kind、Compose generation 和是否残留事务锁,只能直接查看私有文件或冒险调用 Docker。

实时服务健康与持久部署状态不是同一事实。路由设备不应为状态查询加载 Docker client、扫描全部历史 receipt 或增加守护进程;集群节点也不应让这个本机工具获得 Kubernetes/Cluster Control authority。

决策

  1. 既有 @qinglong/local-owner-cli/local-deploymentql3-local-deploy 增加 local.deployment.status/status,不新增 workspace package、生产依赖、binary 或部署单元。
  2. 输入继续是 canonical 当前 UID 0600 私有 command file;命令只含 deploymentRoot 与匹配当前 POSIX identity 的 allowRootService。不接受 caller 注入 Profile、service kind、generation 或健康结论。
  3. 查询验证 deployment root/service/revision 私有目录,读取 application v2 Profile 和唯一 service descriptor。Compose 使用既有 canonical selection/revision reader,返回 generation、可选 rollback target 及 revision/rollout/restore/evidence-collection 四个固定围栏状态。
  4. 任一围栏存在时只报告 transition=recovery_required,表示需要寻找并重放原命令;不把锁解释成服务 故障,也不自动删除、恢复或继续事务。没有围栏只报告 stable,不推导容器正在运行。
  5. 顶层固定 observation=durable,运行态固定 runtime.health=unobserved。实时健康必须继续由 init/Docker 与 application active event 证明;状态命令不打开 SQLite、socket、网络或子进程。
  6. 输出只含 Profile、service kind、generation、rollback target 与枚举状态,不返回路径、instance/image/ digest/mutation/operation ID、socket 或 secret。实现读取固定数量且有 64 KiB 上限的小文件,不按历史规模 扫描,Edge 与 Standalone 使用同一常数工作量。

被否决的方案

  • 直接执行 docker compose ps/systemctl status:会把只读磁盘观察扩大为平台命令执行、socket 权限和 实时环境耦合,OpenRC/rootless/低配设备行为也不一致。
  • 把持久状态命名为 healthy/activeselection 和 descriptor 只能证明期望配置,不能证明当前进程、boot 或 application admission;这会产生危险的假阳性。
  • 扫描并汇总所有 receipt/snapshot:成本随升级历史增长,还会把恢复证据细节暴露到普通状态面。
  • 新增 deployment-status package/daemon:状态能力与部署文件共享同一 POSIX authority,且只有一个生产 消费者;拆包或常驻进程只增加 Edge 制品与生命周期成本。
  • 状态命令自动清理残留锁:锁是 response-loss 与恢复事务的唯一围栏,删除会破坏 exact replay 和恢复证据。

验收证据

  • 编辑前 GitNexus:唯一修改的既有函数 localDeploymentCli.main 为 LOW1 direct/1 total/0 process deploymentPathsinspectActiveComposeImageSelection 只被复用,没有修改。
  • 新增 process、Compose stable/rollback/recovery fence、私有低敏 CLI 与静态 authority 隔离门;本机部署 27/27、完整 Local Owner CLI 108/108 通过。
  • 状态实现没有 SQLite/Docker/init import,不建立 connection、socket、timer、watcher、listener、queue、cache 或子进程;workspace 仍为 19 package。Owner CLI 为 49 source/1 root/50 root lines/48 nested,新增实现位于 既有 deployment/ domain,没有新增根平铺文件或提高 hard capworkspace 为 770 source/32 root/738 nested。
  • 从空 dist 重建并测试 19 package 通过;backend 1,113 项为 1,111 pass/2 条件 skip/0 fail。package boundary、dependency、Edge import、Local image、Cluster deployment 与 image release 六项审计全绿。
  • 十档 Profile artifact/RSS 全部 compatible,且相对 ADR-0306 字节、文件和 loaded module 完全不变:基础 Edge 为 3,635,156 bytes/333 files/49 modules,最大 Standalone Application AI 为 6,123,870 bytes/ 492 files/105 modules。Owner CLI 状态能力不进入任何常驻 Application 制品。
  • 最终 GitNexus 为 43,402 nodes/98,605 edges/1,703 clusters/271 flowsstatus inspector 为 LOW 1 direct/ 1 total/0 processnormalizer 为 LOW 1 direct/2 total/0 processCLI main 保持 LOW 1/1/0。 detect_changes all/compare develop 为 12/31、14/34,均 low/0 affected process。

后续边界

该入口只关闭“部署持久状态不可见”,不关闭真实服务健康、签名 release digest、systemd/OpenRC 安装启用、 固定 Edge/多架构物理压力与完整升级回滚演练。若后续提供 live status,必须作为独立显式 operation 接受并 验证对应 supervisor authority,且不能改变本契约的 durable/unobserved 语义。