--- doc-schema-version: 1 title: "团队不可变更新设计" summary: "不可变的更新设计:安装、准备、本机激活和保留恢复合同" read_when: - "为具有密封发布目录的安装设计本机更新" - "检查团队部署控制器切换" --- # Team 不可变更新设计 **实施设计;实施准备和显式启用的本机激活。无部署授权。** 完成`openclaw update` 中的不可变安装适配器。与现有所有者保持更新编排、激活恢复、Doctor 迁移和服务生命周期。不要将专用部署控制器移植到核心中。 原始库存主要于 2026 年 10 月 2 日在 `e4dc2512b87419b12f1d9cfbbe5f2860fd9b869e` 使用。下面的所有者库存现在包括本机不可变准备、激活、恢复和状态预测。事件时间和控制器库存是由活动证据提供的,而不是在此通道中执行的测量或私人控制器源验证。未访问生产。 “拟议合同”下的所有内容都描述了完整的设计;下面确定了已实现的子集。 ## 实施情况 第一个审查切片(#163799)实现了 **Detect 并采用不可变安装** 和 **做好一切可能的准备,而之前的网关服务于**。维护者接受了持久描述符扩展、保留当前代和前代以及期刊引用的代,以及 `openclaw update` 下的显式采用子命令。 Slice 1 记录采用情况和准备代数,打包稳定的启动器,并通过状态和试运行报告不可变的安装。它不会发布 `current`、更改服务定义、重新启动网关、迁移实时状态、收集代、导入专用控制器历史记录或停用该控制器。 Slice 2 添加了版本化、显式启用的采用记录和本机 activation/recovery 所有者。它重用了悬挂排水管、本机 systemd 生命周期、重新启动运行状况和配置审核所有者。激活日志在发布前指示意图,验证所选的物理生成和稳定的服务定义,并仅接受候选者编写的附加配置写入,并具有匹配的审核证据和未更改的策略。启动检查仍然是一个有限的待定结果。验证成功则注销记录;安全回滚会保留它。 `openclaw update recover --root ` 协调不确定的影响并验证已经健康的候选者或前任,而无需重新启动它。 仅启动金丝雀在耗尽之前运行,并在实时准备就绪后在新的私有状态副本上再次运行,同时选定的网关提供服务。接受的启动配置迁移保护在第二个金丝雀之前保留。最终检查必须观察相同的实时 PID 并在所有者退出操作之前启动。这些收据证明了现有的金丝雀合约,而不是本地模型标记转向。普通`update.status`通过现有的刷新所有者请求刷新已验证的不可变安装事实并绕过私人管理员状态,从而保持激活记录的权威性。 在耗尽之前,独立激活所有者在其安装同级控制目录下准备并密封调用运行时的完整副本作为 `recovery-`,重复使用同一源 SHA 的经过验证的副本。记录的外部 Node 运行 `.control/recovery.mjs`,它会分派给保留的产品所有者,而无需借用候选人或经理结账。切换期间不会发生运行时复制、依赖项安装或构建。挂起和回滚结果打印准确的独立恢复命令。新的 `openclaw update status` 观察者还公开该命令和安全待定故障代码,以及记录时经过历史验证的 SHA、时间戳、版本、构建、PID 和启动标识。准备好的候选人和待恢复的数据与已接受或恢复的历史记录分开;较旧的收据可能缺少网关验证详细信息。 在操作员使用 `--enable-activation` 重复采用之前,切片 1 采用的激活保持禁用状态。网关 `update.run` 仍将操作员引导至网关服务 cgroup 之外的根 CLI。服务网关必须支持承诺的暂停切换:现有部署所有者必须首先激活包含此功能的一个桥接版本。候选端 CLI 无法将其改装到较旧的正在运行的网关中。在该桥正常运行后,启用采用并证明在淘汰旧控制器之前可以本地切换到不同的经过审查的一代。不可变的 `--drain-timeout` 标志独立选择消耗预算,例如 30 秒,而 `--timeout` 保留 canary/readiness 阶段预算。健康恢复从不使用消耗预算。网关 RPC 权限切换不属于此切片的一部分。激活需要 cgroup v2 和匹配的架构合约;不兼容的模式要求在耗尽之前被拒绝。仅限启动的金丝雀预演在切换前使用私有副本,没有 Doctor 预修复,因此候选者必须处理自己的附加启动迁移。激活期间不会运行实时 Doctor 或可选的 NOCOW 重写。一般不兼容数据库 migration/rewind、生成收集、部署 adoption/proof 和私有控制器停用仍然是单独的工作。下面更广泛的拟议合同描述了那些剩余的边界,而不是完成的生产部署。 在最终本地停止准备时,暂停所有者验证原始租约和所有写入托管,然后活动主机在确认切换之前提交单向关闭。转学后,恢复和到期不能重新入场。旧的仅适用于手臂的合同仍然可供现有调用者使用,但不可变的更新程序永远不会退回到它。未知回复保留恢复;主机可能已经停止。如果主机关闭通过本机调度赢得了比赛,则只有没有待处理作业和空 cgroup 的非活动服务才算停止;保留替换过程以用于显式恢复。在主机承诺之前,现有控制记录永久进入其停止阶段。稳定的启动器无需重播日志即可读取该记录,并阻止主管替换在停止或指针发布期间输入网关代码。仅在所有者授权的阶段恢复启动;不需要临时覆盖 systemd 策略。 显式 v1 到 v2 启用可以协调现有部署所有者选择的网桥。采用保留了稳定的根、发布、运行时和服务绑定,验证密封的前身和服务桥,并保留前身而不发明激活成功收据。它还仅升级确切打包的 v1 启动器,在原子替换之前备份其字节。启用后自定义启动器和外部指针漂移仍然被拒绝。 ## 问题和性能边界 当前的部署构建了一个固定的官方主修订版本,发布了一个密封版本,耗尽了网关,更改了 `current` 符号链接,并重新启动了 systemd 服务。其私人控制器还协调Doctor、备份、验证、恢复和保留。这重复了现在具有大量本机实现的职责。 报告的事件将 2,400 秒的家长截止日期与 38-GB NOCOW 重写结合起来。然后,恢复在 WAL 检查点之后拒绝保留文件大小以及医生拥有的 `schema_meta` 收据中的合法更改。报告的结果是停机九个小时。该设计必须从普通激活中删除可选的物理重写,并消耗医生的证据,而不是维护 SQLite 状态的第二种解释。 | 数量 | 提供的基线 | 提议的变更/证据限制 | | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ | | 构建准备 | 约7分钟,Gateway仍在服务 | 保持偏离路线的准备;没有声称的构建加速。 | | 流走 | `update-immutable-activation.ts` 使用 `withGatewayMaintenanceDrain` 并在本地停止之前提交暂停切换。网关所有者验证原始租约并写入托管。 | 较旧的服务网关需要桥接版本;候选者 CLI 无法改造承诺的切换。 | | 网关启动 | 约4.5分钟 | 重启停机时间仍然是一个下限问题;启动工作属于338车道。 | | 清洁激活 | 从排水加启动大约需要 5 分钟,不包括重新连接稳定 | 指针发布消除了切换中的构建工作,但其本身并不能加快启动速度。没有测量后值。 | | 重新连接风暴 | 报告,未量化 | 保留现有的客户端恢复; 339 号车道拥有这一改进。 | | NOCOW故障 | 38 GB;在 2,400 秒处被杀死;总共停电约9小时 | 普通更新延迟NOCOW。明确的维护可以衡量工作预算和可恢复的进度。此通道中没有生产重播。 | 分别进行测量准备、入口关闭、排水、停止间隔、迁移、指针发布、验证准备情况以及重新连接沉降。验收目标是**零build/install工作和零可选NOCOW在常规切换内工作**。秒级中断目标需要启动和客户端测量;该设计不要求任何一项。 ## 主站现有业主 CLI 条目是 `src/cli/update-cli.ts` 和 `src/cli/update-cli/*`,而不是 `src/commands/update*` 实现。维护的用户参考是 [Update](/cli/update)、[更新如何运行](/cli/update/how-updates-run)、[状态和历史记录](/cli/update/status-and-history)以及[更新和插件测试](/help/testing-updates-plugins)。此版本中没有匹配的 `docs/help/update*` 系列。 ### 安装、准备和激活 | 表面 | 当前行为和来源 | 不可变的间隙 | | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | | 安装分类 | `update-install-kind.ts` 包括 `immutable`; `update-check.ts` 使用 `update-immutable-install.ts` 检查所采用的描述符和指针。 | 实施的。目录形状本身并不能证明所有权;未采用的布局不能落入可变的 Git。 | | git 结账 | `update-runner-git*.ts`自己源码编写。 `update-immutable-install.ts` 冻结官方 main 或验证确切的祖先 SHA,构建偏离路径,并密封一代而无需回退。 | 构建帐户隔离和资源策略仍有待添加到不可变适配器中。 | | Git 发布 | Mutable Git 促销仍保留在 `update-runner-git-runtime.ts` 中;不可变发布使用 `package-update-activation-immutable-pointer.ts` 和日志 rename/reconciliation. | 实现不可变指针发布以匹配模式合约;这不是完全迁移恢复。 | | 全球套餐 | `update-runner-install-surface.ts`、`update-global.ts`、`update-native-package-stage.ts` 和 `package-update-swap.ts` 通过管理器特定的所有权和恢复来暂存和验证 npm/pnpm/Bun 目标。考生入场使用包裹的 `openclaw.updateAdmissionProtocol` 标记。 | 独立提取的版本不是经过验证的全局包管理器根。不要仅仅因为它有 `package.json`,就通过 npm 路由它。 | | 其他安装 | 主机拥有的安装路由到其所有者。 Unsupported/unowned 安装表面记录有意跳过和下一步操作,而无需停止网关。容器保持镜像所有者更新。 | 显式引导不可变所有权;保留其他安装方法及其工具。 | ### 生命周期、迁移、恢复和报告 | 责任 | 当前实施情况 | 剩余整合 | | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | 服务身份和切换 | `update-immutable-service.ts` 绑定稳定安装、精确生成、服务定义、PID/start 身份、原始cgroup;激活在网关服务外部运行。 | 在编写迁移和主机维护许可时保留这些绑定。 | | 流走 | `update-immutable-activation.ts` 使用 `withGatewayMaintenanceDrain` 并在本地停止之前提交暂停切换。网关所有者验证原始租约并写入托管。 | 较旧的服务网关需要桥接版本;候选者 CLI 无法改造承诺的切换。 | | 暂停权力 | `src/gateway/server-methods/suspend.ts`将prepare/status/resume/handoff委托给`src/infra/gateway-suspend-coordinator.ts`; `server-active-work.ts` 提供生命周期检查。 | 使用其拦截器和托管事实,包括较新的类型;请勿提供 agent/chat/queue/root/session 阻断剂的冻结列表。 | | systemd 生命周期 | `update-immutable-service.ts` 委托给本机系统范围生命周期所有者,保留密封定义,并在指针发布之前检查原始 cgroup 消亡。 | 生命周期集成;更广泛的主机维护协调仍然是分开的。 | | 医生 | `src/commands/doctor-maintenance.ts`、`doctor-maintenance-state.ts` 和 `src/infra/update-doctor-result.ts` 拥有维护保管、config/schema 修复、类型化结果、配置写入链和数据库生成证据。 | 将准备好的迁移要求和现有权限传递给候选医生。控制器配置文件字符串不是新迁移 API。 | | WAL-aware 备份 | `update-database-backup.ts`、`update-database-generations.ts` 和 `update-database-restore.ts` 捕获经过验证的 SQLite 快照并拒绝不安全的恢复。快照卷准入预留 `2 × total family bytes + 3 × largest family + 64 MiB`;每个源卷还保留恢复空间。 | 重用覆盖率、空间、身份、摘要和外部写入检查。单独的指针回滚无法撤消数据库迁移。 | | NOCOW | `doctor-sqlite-nocow.ts`已经拥有btrfs检查、验证的WAL-aware快照、NOCOW副本、ACL/mode保存、完整性检查、原子目录交换和保留原件。 `doctor/shared/update-phase.ts` 和 `src/flows/doctor-health.ts` 在托管更新期间推迟它,除非明确选择加入。 | 保留该默认值。根据需要向 Doctor 添加阶段 work/progress 会计;删除部署端 rewrite/verifier 实现。 | | 持久运行历史 | `update-run-ledger.ts`、`update-run-schema.ts` 和 `update-run-recovery-store.ts` 在共享状态数据库中存储运行历史记录和恢复描述符,包括阶段计时和 intent/observed 效果。 | 报告不能是恢复自己数据库的唯一权威。 | | 独立激活日志 | `package-update-activation-immutable.ts` 和不可变指针适配器使用安装同级 `.control/operation.sqlite`;保留的产品运行时间贯穿密封的`recovery.mjs`。 | 实现了相同模式恢复。在此所有者中撰写 Doctor 迁移证据并转发恢复。 | | 回滚 | `update-immutable-activation.ts` 恢复已验证的兼容前身或保留待恢复;独立恢复可协调指针效应并验证已经健康的一代,而无需重新启动。 | 架构交叉在排出之前仍然拒绝。未实现完全不可变的迁移恢复。 | | 准备情况和状态 | `update-immutable-verification.ts` 验证准备情况和 generation/process 身份。不可变的记录投影公开 prepared/pending 事实、安全故障代码、保留的恢复命令以及对 CLI 和协议状态的可选历史网关验证。 | 历史 accepted/restored 收据不是实时运行状况或待更新成功。模型标记和更广泛的应用接受度仍然是分开的。 | | 保留 | 本机事务保留 failed/unverified package/runtime 备份并通过其所有者撤销经过验证的材料。 `update cleanup` 有一个单独的、明确的迁移原始合同。 | 永久发布生成集合需要一个所有者绑定的参考清单。不要将迁移清理重新用作发布目录删除。 | `docs/reference/RELEASING.md` 已链接 `.agents/skills/release-openclaw-maintainer/references/validation.md` 中的 **unshipped** 不可变运行时提案。它的关键要求适用于此:在启动 Node 之前解析生成,以便惰性导入保留在该生成中,并保留它直到其进程退出。 ### 控制器配置 按责任分类; “覆盖”意味着存在本机合约,而不是私人控制器当前调用它或不可变集成已经被证明。 | 控制器行为 | 处置 | | ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | 冻结主干; fetch/build 上菜时约7分钟 | **实现原生不可变准备。** 保留精确选择和旁路密封构建;构建帐户隔离仍然存在。 | | 级密封`releases/`和交换`current` | **实现了本机安装和指针适配器。** 采用绑定布局;期刊出版物选择密封的一代。 | | 激活阶段、收据、恢复日志 | **实现了原生不可变操作和状态投影。** 为迁移证据扩展相同的所有者;不要复制控制器阶段。 | | 排水租赁、中断政策、阻塞检查 | **覆盖生命周期所有者。** 重用suspension/stop集成;删除供应商的暂停代码。 | | 指针切换和systemd重启 | **集成用于匹配模式合约。** 不可变事务调用本机服务所有者。 | | 等待直播并CPU/load弃权 | **涵盖准备情况;需要预算整合。** 负载可能会证明更多的观察时间或明确的未经验证的结果是合理的,但绝不放弃 identity/readiness 证明。 | | 医生简介 `state-19-20`、`offline-doctor`、`+nocow` | **涵盖迁移;团队编排退休。** Doctor 从候选架构和当前存储中获取工作。 NOCOW 仍保持显式维护。 | | 离线 WAL-aware 备份 | **Covered.** 保留本机备份和恢复证据而不是并行 shell 检查。 | | Witness/inventory/precapture/NOCOW/rebinding 文物 | **通用证据部分覆盖;需要导入映射。** 保留原件,将来源映射到本地收据,重新获得实时保管。不要将每个私人工件都变成核心格式。 | | 回滚和 `--recover` 子模式 | **为匹配模式合约实现的原生不可变恢复。** `update recover` 消耗独立日志和保留运行时;模式交叉前向恢复仍然存在。 | | 发布retention/cleanup | **通用生成集合丢失。** 保护活动、先前、实时进程和恢复引用;将迁移原件保留在其现有所有者之下。 | | `--switch-runtime node\|bun` | **Team 表面从此切换中退出。** 初始采用保持经过验证的 Node 可执行;本机运行时选择保持独立。不要添加另一个运行时切换标志。 | | 经理配对采用和私人发布簿记 | **团队专用;一次性迁移后删除。** Core 采用经过验证的安装事实,而不是管理器身份或正在进行的配对协议。 | | 守夜人交接 | **没有核心依赖性。** 团队部署仍然需要操作 approval/restart 协调,直到 Peter 对其进行更改;产品更新程序不嵌入该组织特定的工作流程。 | | Bash NOCOW 编排和独立的 SQL 验证器 | **团队特定的重复; delete.** Doctor 是唯一的迁移和物理重写所有者。 | ## 建议合约 ### 检测并采用不可变安装 识别植根于`/opt/`和`current`选择直接、密封的`releases/`孩子。目录形状只是一个发现提示。需要更新者拥有的安装记录绑定已解析的父目录、服务identity/scope/account, state/config/profile、运行时可执行文件、源权限和生成构建标识。在任何突变之前验证符号链接包含、所有权、同一文件系统原子发布支持以及不存在竞争更新程序。外部指针或不明确的服务会产生指定的非结果,而先前的网关仍在运行。 使用现有的 installation/activation 控件 SQLite 所有者来获取权威的采用事实; package/build 清单是不可变的工件事实,而不是另一个可变的 JSON 状态存储。识别先于 Git/package 回退,仅适用于经过验证的本机采用。未采用的密封布局不得从路径或包名称获得写入权限。不要使 `macos-app` 主机标记过载。 分离三个身份:稳定安装(`/opt/`)、指针修订版、物理生成(`releases/` 加神器摘要)。 Run/Doctor 权限包括确切的本机服务和选定状态。构建元数据准备一次并通过激活进行;当其工件身份发生变化时使其失效。指针和服务观察在等待工作之后和每次效果之前立即重新验证。日志修订或令牌本身并不是实时执行者权限。 不需要新的 `openclaw.json` 选项。正常`openclaw update`,试运行、状态和维修应按所采用的安装类型进行调度。保留现有的 channel/target 选择,但将所选的官方修订版冻结一次。在实施之前,必须使用所属的 CLI 工作流程指定初始 installer/adoption 操作;该草案不会公布现有的 `--immutable` 或采用命令。例行调用不需要 Manager 存储库。 ### 在上一个网关服务期间做好一切可能的准备 使用现有的源准备管道来获取配置的官方源,解析完整提交,使用其固定的包管理器和冻结的锁定文件进行安装,并在发布文件系统上构建私有暂存。永远不要改变服务一代。选择目标后,请勿重新解析 `main` 或走回另一个 SHA。重试可以仅重用其源、工具链、依赖项和工件身份仍然与记录的准备相匹配的候选者。 在 WAL-aware 私有状态副本上运行候选人准入、工件验证、医生排练、插件准备以及排出前的隔离金丝雀。用于排练的副本不会成为现场状态或证明其后来的内容不变。密封前完成所有生成的runtime/plugin工件;在发布树之外路由可写缓存和状态。插件有效负载更改不得在激活后重写密封生成。 将经过验证的候选者发布到 `releases/` 中,而不替换现有目录。如果 SHA 已存在且具有不同的字节或不完整的工件,请报告冲突并保留它以供检查。同一 SHA 的 runtime/toolchain 变体不在初始布局合同范围内;不允许就地重建一代。在现有 run/activation 记录中记录源 SHA、构建摘要、运行时身份、模式契约和准备好的服务事实。通过安装所拥有的文件系统权限进行密封;网关帐户获得 read/execute 访问权限,而更新程序控制发布。 ### Drain,需要时迁移,然后激活 更新程序在网关的服务 cgroup 外部执行。现有的执行者和本地服务所有者通过以下顺序拥有安装权限;这些是概念性子步骤,而不是第二个顶级运行词汇。 1. 在独立激活日志中记录准备好的候选者和上一代。在关闭准入之前验证备份容量和迁移要求。通过现有运行通知所有者宣布激活。 2. 通过更新服务漏所有者重用暂停协调器。在耗尽时更新请求租约并将观察结果绑定到服务 boot/PID. 就绪状态会立即结束耗尽。现有的终端中断策略可以解决普通工作,但无法杀死未解决的写监管来满足任意 30 秒的目标。在中止的停靠站恢复确切的租约。 3. 通过本机服务所有者停止并确认旧进程和已接受的写入工作已解决。使用现有的维护托管,防止在离线迁移期间 Supervisor 重新启动。显式停止后启动是可迁移的重新启动序列; `ExecStartPre` 中没有构建。 4. 让候选医生根据维护权限验证最新的实时要求。排练并不意味着有权覆盖以后的更改。在突变之前捕获所需的已验证备份,仅运行所需的 repairs/migrations,并发布键入的结果。在确切的、已接纳的状态下,不要重写 NOCOW 的存储或仅因为切换而运行第二次完整迁移。 5. 坚持指针发布意图,包括预期的先前目标和物理身份。在 `current` 旁边创建一个临时相对符号链接,通过 `current` 原子重命名它,并通过 `directory-durability.ts` 持久同步父级。请勿先取消 `current` 的链接。在继续之前,读回效果并记录观察到的结果。 6. 通过相同的服务所有者启动,并保留稳定的定义。验证已解决的生成、新的 boot/PID、已验证的准备情况以及所需的 plugin/service 事实。仅从这些收据中承诺成功。 只有一代进程可以写入所选状态。这不是两个网关打开相同数据库的 blue/green 设计。可选NOCOW工作仍然是单独的维护操作;不可避免的不兼容迁移仍然可能需要停机时间,必须在停止服务之前估计停机时间。 ### 保持恢复独立于正在恢复的数据库 使用可区分的不可变发布描述符扩展 `package-update-activation-*` 及其恢复助手。重复使用耐用的revision/intent/observation和身份检查;不要将发布目录伪装为 npm 包备份。安装同级控制数据库保留在发布目录和 Doctor 的状态替换集之外。它记录保留的生成和备份清单引用、确切的服务标识、指针效果、迁移完成以及候选者可以接受写入的边界。现有的共享状态运行历史记录仍然是面向用户的记录,并在状态恢复后与权威操作进行协调;永远不要从丢失的行推断更新中止。 当前的共享账本恢复路径拒绝未解决的 `.openclaw-restore-*` 系列。概括地说,独立激活所有者必须在声明不可变迁移恢复之前明确覆盖该中断边界。现有的包日志阅读器保持版本控制:不要用新的描述符默默地重新解释旧的挂起操作。新的type/schema和recovery/retention语义在实现之前需要[存储设计检查点](/reference/database-schemas/storage-changes#review-checkpoint-for-material-changes);该草案记录了拟议的决定,而不是接受。 重新启动更新程序时,根据实际指针、进程、数据库系列和记录的所有者来协调持久意图。在重试之前观察到不确定的重命名、服务操作或恢复。只有在证明前任执行者退出并且所有承认的工作都已解决后才能恢复。保留的恢复助手必须在没有候选人或经理签出的情况下保持可执行状态。 | 失效边界 | 恢复行为 | | -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 排水前 | 继续服务之前的版本。记录 failure/skip 并仅收回经过验证保管的任务拥有的候选材料。 | | 耗尽但未停止 | 如果仍然拥有,则恢复确切的暂停。切勿恢复其他请求的租约。 | | 已停止,没有不兼容的状态更改 | 在允许的情况下恢复之前的pointer/config,重新启动上一代,并在报告`rolled-back`之前进行验证。 | | 医生在候选人启动前失败 | 使用 Doctor 验证的备份覆盖范围和当前的写入证据检查。仅在这些检查允许的情况下才恢复;保留迁移的原始文件。否则保留证据并报告所需的兼容恢复操作。 | | 候选开始或发生外部写入 | 不要自动回退数据库。模式兼容的先前运行时在现有回滚检查下仍然可以使用;不兼容的回滚需要显式恢复。保留新写入。 | | 启动缓慢或未经验证 | 在适当的情况下,从测量的启动延伸观察。保留诚实的 pending/unverified 结果和备份; CPU/load 豁免不能创造成功。当前状态行为不保证稍后自动确认。 | | 指针或数据库发布期间崩溃 | 独立的日志和助手在启动、恢复或重试之前协调确切的效果和保留的对象。共享状态账本恢复无法抹除恢复权限。 | 验证成功后,生成收集会保护当前生成、保留的回滚生成、每个实时进程引用以及每个待处理的恢复引用。未知引用会保留材料并产生清理警告。删除发生在切换之外,并在每次效果之前重新检查相同的 owner/revision。迁移原件和运营商备份保留其现有的显式 cleanup/retention 合同;采用安装并不授权删除它们。除了所有受保护的引用之外,初始生成保留在验证后还保留当前和以前的内容;本政策的接受属于设计审查。 ### 给医生描述工作的预算 Main 已经有了基于尺寸的检验预算。在 `src/infra/sqlite-readonly-worker.ts::resolveSqliteInspectionBudget` 中,余量为 `300 seconds + ceil(40 × family bytes / 32 MiB) seconds`:四次 copy/comparison 传递,具有十倍的慢速硬件余量。 `update-candidate-state.sizes.ts` 包括 SQLite 边车;汇总检查总和系列系列。 `update-finalization-budget.ts` 结合了状态、步骤、观察启动和插件工作。 `update-run-timeouts.ts` 中默认的 20 分钟跑步、30 分钟步数和 45 分钟自动步数与私人 2,400 秒截止时间不同。 对于 **38 GiB**,现有检查公式得出 **48,940 秒(13 小时 35 分 40 秒)**。这是保守的津贴,而不是测量的持续时间、建议的停机或 NOCOW 完成策略。该事件称 38 GB 没有字节数;请勿替换 GiB 作为其测量值。 重用这些预算所有者并扩展 Doctor 阶段的快照、重写、完整性验证和发布。根据测量的系列字节和保守观察到的存储吞吐量进行估计,保留 verification/recovery 时间,并在服务停止之前报告估计的工作。通过子流程携带一个父级截止日期及其来源;较短的隐藏父超时不得杀死其承认的大小衍生津贴较长的孩子。显式操作员超时仍然是显式的,并与其恢复结果一起报告。 进度报告应包括阶段、已完成的 bytes/work、已用时间和剩余估计。区分进展缓慢和没有进展;扩展消耗了所有者观察到的工作,而不是自由运行的心跳。取消会加入写入工作并留下记录的可恢复状态。各个本机工具调用保留其有界执行契约。不要在未加入的 Doctor 进程周围引入另一个团队超时常量集合或重试循环。 备份根据其自己的发布后 size/digest 和 SQLite 内容证据进行验证。 WAL 检查点可以更改源布局或大小,而不会丢失已提交的页面。 `update-database-generations.ts` 拥有这种区别。当 build/schema/agent 元数据更改时,医生的 `src/state/openclaw-agent-db-metadata-write.ts` 可以合法地刷新 `schema_meta`。消耗其写收据;不要求相同的元数据,也不简单地将所有 `schema_meta` 更改或外部写入排除在安全检查之外。报告的两个验证器故障需要通过 migration/recovery 入口点进行单独回归。 ### 服务定义 保留现有的系统服务、服务帐户、配置文件、状态路径、端口和批准的强化。预期的不变量是生成树外部的稳定启动器,它解析 `current` 一次,验证所选生成,更改其物理目录,并使用物理 `dist/index.js` 路径 `exec` 固定的外部 Node 可执行文件。孩子和懒惰的进口继承了这一代人。 Node 不得继续解析可变的 `current` 路径以供以后加载。 这是说明性的 **propose** 系统单元摘录,而不是安装命令: ```ini [Unit] Description=OpenClaw Gateway After=network-online.target Wants=network-online.target StartLimitBurst=10 StartLimitIntervalSec=300 [Service] Type=simple User=openclaw Group=openclaw WorkingDirectory=/opt/example ExecStart=/opt/example/bin/openclaw-gateway --port 18789 Environment=OPENCLAW_STATE_DIR=/var/lib/example EnvironmentFile=-/etc/example/gateway.env Restart=always RestartSec=5 RestartPreventExitStatus=78 SuccessExitStatus=0 143 KillMode=mixed OOMPolicy=continue [Install] WantedBy=multi-user.target ``` 服务呈现器必须从共享 `GATEWAY_SERVICE_STOP_TIMEOUT_MS` 策略提供 `TimeoutStopSec` 并保留允许的操作员覆盖。当前渲染器的 `TimeoutStartSec=30` 不是 `Type=simple` 的网关就绪截止日期;更新程序运行状况观察需要自己的 size/startup-aware 津贴。保留所选的服务环境和账户;上面的示例是占位符,而不是现有安装的新默认值。不要将 Doctor、构建或网络包安装添加到单元预启动挂钩中。 稳定启动器由 OpenClaw 打包,而不是其他部署控制器。只有更新者帐户可以发布版本或更改 launcher/pointer. 网关帐户读取密封代码并写入其现有的 state/cache 路径。当前的 systemd 生命周期已经需要 root 才能进行系统范围的突变;此设计不会添加广泛的 sudo 权限或提升聊天请求。非特权调用保留现有授权的 handoff/guidance 合约。更新检查必须明确识别启动器与生成器的关系;否则当前的服务根围栏将正确拒绝它。 ## 迁移当前控制器,无需两个写入器 引导程序是一次性所有者转移,而不是来自缺乏不可变支持的旧驱动程序的普通更新。领导必须通过当前的操作工作流程批准并协调实际的团队重启。该通道既不会禁用其调度程序,也不会部署候选者。 1. 盘点实际控制器版本、服务定义、current/previous 发布目标、日志、未完成的租约、备份位置和安装的运行时。提供的控制器库存不足以编写其导入解析器。保留导出和原始恢复可执行文件。 2. 停止调度新的控制器操作并证明任何活动操作已解决。中断的旧日志将保留在其旧的恢复所有者那里,直到明确解决;不要将待定阶段转换为成功的本机收据。切勿与控制者和本地出版机构重叠。 3. 准备并验证第一个具有不可变功能的版本路径外。导入已确定的历史作为来源,保留原始文物。在当前本机权限下,重新捕获安装、进程、状态和备份事实。所需结转如下图所示。 4. 在批准的重启窗口中,安装稳定的 launcher/service 联动,创建本机安装记录,并使用本机事务来激活和验证有能力的版本。通过引导回滚窗口保留之前的密封生成和原始恢复工具。 5. 证明已安装的版本启动了第二次更新,以及故障和恢复演练。只有这样才能删除控制器的计划执行、管理器对采用依赖性、私有 Bash/lib 安装和供应商暂停合同。将历史备份工件保留在其保留所有者之下;删除可执行文件不是备份删除。 | 现有状态 | 本机处理 | | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | 激活日志和收据 | 保留原始字节;导入已确定的 phase/outcome/source 参考文献作为出处。获得新的run/executor/service权限。待处理的工作在转移之前得到解决。 | | 保留释放对 | 将经过验证的物理代和兼容性绑定到本机激活描述符;经理配对标签并不是证据或权威。 | | 离线备份、见证、库存和预捕获工件 | 保留 paths/digests 并将实际数据库覆盖范围映射到本机备份清单。未知的覆盖范围仍然保留,并且无法授权自动恢复。 | | NOCOW 原件和快照 | 保留两者及其关联。验证当前文件系统属性和Doctor当前的receipt/generation证据;请勿仅仅为了采用而重新复制 38 GB。 | | 重新绑定和模式元数据证据 | 作为历史证据。医生重新获取当前身份并记录授权的元数据更改。不要恢复过时的托管令牌。 | | 运行时选择 | 采用现有的经过验证的 Node 可执行文件。运行时切换位于第一个不可变切换之外。 | 没有核心组件在采用后需要经理结帐或夜班会话。团队的部署批准和重新启动协调仍然是外部运营义务,而不是隐式删除的产品依赖性。 ## 证明矩阵和卷展切片 “更新始终有效”意味着尽力更新并记录结果、可恢复的警告以及在危险突变之前保留先前的服务安装。这并不意味着在准备失败后报告成功或承诺自动回滚每个迁移的存储。 现有已发布驱动程序覆盖范围位于 `scripts/e2e/published-driver-update-docker.sh` 和 `scripts/e2e/lib/upgrade-survivor/published-driver.mjs` 中,发布要求位于 [Releasing](/reference/RELEASING) 中。它针对固定候选者调用已安装的已发布更新程序,并验证持久结果、候选者身份、服务替换和准备情况。该装置使用 systemctl shim;它不能证明本机 systemd 或 btrfs。其 1,125 秒的总单元预算并不是大型商店的性能预算。其他一些幸存者场景手动启动网关,并且不证明更新程序拥有重新启动。 | 细胞 | 需要观察 | 所有者/证明层 | | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | 已发布的驱动程序 × 候选者 | 保留现有的受支持系列 package/git 单元、记录的驱动程序字节和确切的候选版本。练习标记实际上是由每个发货的驱动程序设置的。 | 现有的发布矩阵;候选代码无法修补预部署的旧驱动程序。 | | 第一个不可变的版本 | 旧的独立布局保持不变,直到明确采用;稳定和中断的控制器装置证明所有者 transfer/refusal. | 引导集成;没有被错误地标记为原生旧驱动程序不可变支持。 | | 已安装的可用版本 × 下一个候选版本 | 运行实际`openclaw update`;断言目标 SHA/digest、持久运行、指针更改、新服务 PID/boot、经过身份验证的就绪性和哨兵关联。 | 新的不可变集成单元。 | | 相同架构、当前版本和试运行 | 无需可选的 NOCOW 重写,切换期间无需构建,不变时无需重新启动;试运行不会导致采用或发布。 | 重点入口点检查和定时集成。 | | Fetch/build/admission/canary故障 | 老PID依然健康,指针不变,候选人从未承认过活着状态。 | 候选人准备整合。 | | 本机 systemd | 真实系统单元、保留的定义、服务 cgroup 外部的更新程序、正确的 account/environment、父项和惰性子项导入的物理生成。包括权限不足和竞争服务。 | 与真实 systemd 隔离的 Linux Testbox/VM。 | | 排水和并发 | 日常工作繁忙、写托管、租约到期、二次更新、住户更换、注销、失败停止统统解决,不盗权。 | 生命周期边界整合。 | | 每个效果的 Crash/restart | 注入终止 before/after 持久意图、指针重命名、Doctor 发布、本机 stop/start 和终端收据;重播前观察。 | Activation/recovery一体化,可重复故障挂钩。 | | 迁移和恢复 | WAL-轴承shared/agent存储、备份短缺、安全启动前恢复、更改配置、外部写入和启动后回滚拒绝;独立期刊在共享 DB 恢复中幸存下来。 | Doctor/update 集成。 | | 报告验证器失败 | 检查点更改 source/snapshot 尺寸; Doctor 合法地刷新模式元数据。恢复接受授权的更改并拒绝不相关的突变。 | 通过Doctor加回滚边界进行回归。 | | NOCOW 和大状态 | 实际的 btrfs、保留的 ACLs/originals、不支持的交换工具、部分 copy/cancellation、throughput/progress 以及代表性 38-GB 存储的充足的 parent/child 预算。 | 单独预算的release/performance电池;合成或授权的复制数据。 | | 准备情况和状态 | `update-immutable-verification.ts` 验证准备情况和 generation/process 身份。不可变的记录投影公开 prepared/pending 事实、安全故障代码、保留的恢复命令以及对 CLI 和协议状态的可选历史网关验证。 | 历史 accepted/restored 收据不是实时运行状况或待更新成功。模型标记和更广泛的应用接受度仍然是分开的。 | | 保留 | Current/previous/live/recovery/unknown 参考文献仍然存在;只有符合资格的自有一代才会在核实后退休。迁移备份保持不变。 | Recovery/cleanup 边界。 | 保持聚焦回归可重复且成本低廉。真正的多 GB 工作、真正的服务启动、btrfs 和崩溃恢复组合都属于 release/performance 证明。记录同一设备和存储类别的 before/after 中断和阶段持续时间。最初仅设计的车道没有运行此类行为证明;每个实现 PR 必须声明其自己的已执行单元和剩余间隙。 ### 三个提议的 PR 这些是评论切片,而不是打开或合并它们的权限。更喜欢三个;仅当其独立回归保证时,才将《Doctor》工作分成第四部分。 1. **不可变安装和准备生成。** 扩展 `src/infra/update-install-kind.ts`、`update-check.ts`、`update-runner-install-surface.ts` 和 `src/cli/update-cli/update-command.ts`;重复使用 `update-runner-git-preflight.ts` 和 `update-runner-git-target.ts`。添加窄 `src/infra/update-immutable-install.ts` 适配器和软件包拥有的稳定启动器。通过共享协议、状态和试运行消费者将安装鉴别器连接在一起。覆盖检测、密封、精确 SHA、无操作和候选失败,无需发布。在 PR 2 之前无法激活。 2. **激活和独立恢复。** 扩展`package-update-activation-schema.ts`、`package-update-activation-journal.ts`、`package-update-activation-paths.ts`、它们的恢复助手和具有类型化指针效果的`package-update-recovery-contract.ts`。集成`update-command-service-plan.ts`、`update-command-service-drain.ts`、`update-command-rollback.ts`、`update-run-recovery-store.ts`、`src/daemon/systemd-lifecycle.ts` /服务身份检查。完整的日记恢复、医生收据装订、准备和保留作为一个流程。仅添加 Doctor 和现有预算所有者中缺少的 NOCOW 阶段 budget/progress 集成;保留可选的延期。没有第二个日志或服务控制器。 3. **采用、证明和控制器退役。**通过installer/update所有者添加有界import/adoption,释放`scripts/e2e/`中的矩阵单元,以及`/cli/update`、`/install/updating`和下的用户文档医生。记录现有的不受支持的第一跃点并测试第二个本机更新。经过领导批准的部署和证明后,删除私有控制器在其自己的存储库中的重复执行路径。这种私人删除是一项单独的授权操作行为,而不是偶然的公共回购更改。 泛化应该留下期刊持久性、暂停、医生验证和服务操作的一种实现。现有发布的包日志格式保留了明确的兼容性读者;不可变模式获取类型化描述符,而不是具有重命名前缀的复制文件。初始范围不包括包管理器生成转换、运行时切换、新网关配置选项、架构策略更改和多网关状态共享。 ## 审查决定和证据差距 实现的相同模式切片不会建立更广泛的独立期刊 migration/restore 合约或真正的 systemd/btrfs 矩阵。生产所有者转移仍需要批准的部署窗口和 slice-3 证明。在此通道中未检查专用控制器的实际工件架构、ownership/permissions、运行时路径和当前恢复状态。 **原始设计通道证据:** 未执行运行时更改、生产重启、性能基准测试、已发布的驱动程序单元或不可变更新。文档的理智和审查结果与本地草案一起属于车道交接。请勿将此活动的“测试盒验证”标题解释为对此提议行为的验证。