From aaee14fcad4f20fe1f3ec8077e44adafbd7fa921 Mon Sep 17 00:00:00 2001 From: "openclaw-docs-i18n[bot]" Date: Tue, 5 May 2026 04:29:52 +0000 Subject: [PATCH] chore(i18n): refresh zh-CN translations --- docs/zh-CN/channels/telegram.md | 530 ++++++++-------- docs/zh-CN/ci.md | 380 ++++++------ docs/zh-CN/concepts/qa-e2e-automation.md | 333 +++++----- docs/zh-CN/help/testing-updates-plugins.md | 120 ++-- docs/zh-CN/help/testing.md | 683 +++++++++++---------- docs/zh-CN/reference/RELEASING.md | 423 ++++++------- docs/zh-CN/reference/test.md | 102 +-- 7 files changed, 1258 insertions(+), 1313 deletions(-) diff --git a/docs/zh-CN/channels/telegram.md b/docs/zh-CN/channels/telegram.md index 4e6413a52..ba3d81c0d 100644 --- a/docs/zh-CN/channels/telegram.md +++ b/docs/zh-CN/channels/telegram.md @@ -1,42 +1,42 @@ --- read_when: - - 处理 Telegram 功能或网络钩子 -summary: Telegram 机器人支持状态、能力和配置 + - 开发 Telegram 功能或网络钩子 +summary: Telegram 机器人支持状态、功能能力和配置 title: Telegram x-i18n: - generated_at: "2026-05-04T07:29:50Z" + generated_at: "2026-05-05T04:26:41Z" model: gpt-5.5 provider: openai - source_hash: 5711d53cf908a14024bc5a94f7d590bb4bcb6963a1d78049d7782871f4eae932 + source_hash: 03c75169335378482b80f1ceb669cefaa034ad3e589cf5f1d14c8252608ee46a source_path: channels/telegram.md workflow: 16 --- -通过 grammY,可用于生产环境中的 bot 私信和群组。默认模式是长轮询;webhook 模式可选。 +Production-ready for bot DMs and groups via grammY. Long polling is the default mode; webhook mode is optional. - - Telegram 的默认私信策略是配对。 + + Default DM policy for Telegram is pairing. - - 跨渠道诊断和修复手册。 + + Cross-channel diagnostics and repair playbooks. - - 完整的渠道配置模式和示例。 + + Full channel config patterns and examples. -## 快速设置 +## Quick setup - - 打开 Telegram 并与 **@BotFather** 聊天(确认账号名正是 `@BotFather`)。 + + Open Telegram and chat with **@BotFather** (confirm the handle is exactly `@BotFather`). - 运行 `/newbot`,按提示操作,并保存 token。 + Run `/newbot`, follow prompts, and save the token. - + ```json5 { @@ -51,12 +51,12 @@ x-i18n: } ``` - 环境变量回退:`TELEGRAM_BOT_TOKEN=...`(仅默认账号)。 - Telegram **不**使用 `openclaw channels login telegram`;请在配置/环境变量中配置 token,然后启动 gateway。 + Env fallback: `TELEGRAM_BOT_TOKEN=...` (default account only). + Telegram does **not** use `openclaw channels login telegram`; configure token in config/env, then start gateway. - + ```bash openclaw gateway @@ -64,119 +64,119 @@ openclaw pairing list telegram openclaw pairing approve telegram ``` - 配对码会在 1 小时后过期。 + Pairing codes expire after 1 hour. - - 将 bot 添加到你的群组,然后设置 `channels.telegram.groups` 和 `groupPolicy` 以匹配你的访问模型。 + + Add the bot to your group, then set `channels.telegram.groups` and `groupPolicy` to match your access model. -Token 解析顺序可感知账号。实际使用中,配置值优先于环境变量回退,且 `TELEGRAM_BOT_TOKEN` 仅适用于默认账号。 +Token resolution order is account-aware. In practice, config values win over env fallback, and `TELEGRAM_BOT_TOKEN` only applies to the default account. -## Telegram 侧设置 +## Telegram side settings - - Telegram bot 默认启用**隐私模式**,这会限制它们能收到哪些群组消息。 + + Telegram bots default to **Privacy Mode**, which limits what group messages they receive. - 如果 bot 必须看到所有群组消息,可以: + If the bot must see all group messages, either: - - 通过 `/setprivacy` 禁用隐私模式,或 - - 将 bot 设为群组管理员。 + - disable privacy mode via `/setprivacy`, or + - make the bot a group admin. - 切换隐私模式时,请在每个群组中移除并重新添加 bot,以便 Telegram 应用变更。 + When toggling privacy mode, remove + re-add the bot in each group so Telegram applies the change. - - 管理员状态在 Telegram 群组设置中控制。 + + Admin status is controlled in Telegram group settings. - 管理员 bot 会收到所有群组消息,这对于始终在线的群组行为很有用。 + Admin bots receive all group messages, which is useful for always-on group behavior. - + - - `/setjoingroups` 用于允许/拒绝加入群组 - - `/setprivacy` 用于群组可见性行为 + - `/setjoingroups` to allow/deny group adds + - `/setprivacy` for group visibility behavior -## 访问控制和激活 +## Access control and activation - - `channels.telegram.dmPolicy` 控制直接消息访问: + + `channels.telegram.dmPolicy` controls direct message access: - - `pairing`(默认) - - `allowlist`(要求 `allowFrom` 中至少有一个发送者 ID) - - `open`(要求 `allowFrom` 包含 `"*"`) + - `pairing` (default) + - `allowlist` (requires at least one sender ID in `allowFrom`) + - `open` (requires `allowFrom` to include `"*"`) - `disabled` - `dmPolicy: "open"` 搭配 `allowFrom: ["*"]` 会允许任何找到或猜到 bot 用户名的 Telegram 账号向 bot 发送命令。仅应将其用于工具受到严格限制、刻意公开的 bot;单所有者 bot 应使用带数字用户 ID 的 `allowlist`。 + `dmPolicy: "open"` with `allowFrom: ["*"]` lets any Telegram account that finds or guesses the bot username command the bot. Use it only for intentionally public bots with tightly restricted tools; one-owner bots should use `allowlist` with numeric user IDs. - `channels.telegram.allowFrom` 接受数字 Telegram 用户 ID。`telegram:` / `tg:` 前缀会被接受并规范化。 - 在多账号配置中,限制性的顶层 `channels.telegram.allowFrom` 会被视为安全边界:账号级 `allowFrom: ["*"]` 条目不会使该账号公开,除非合并后的有效账号允许列表仍包含显式通配符。 - `dmPolicy: "allowlist"` 搭配空的 `allowFrom` 会阻止所有私信,并会被配置验证拒绝。 - 设置流程只会请求数字用户 ID。 - 如果你已升级且配置中包含 `@username` 允许列表条目,请运行 `openclaw doctor --fix` 来解析它们(尽力而为;需要 Telegram bot token)。 - 如果你之前依赖配对存储允许列表文件,`openclaw doctor --fix` 可以在允许列表流程中将条目恢复到 `channels.telegram.allowFrom`(例如当 `dmPolicy: "allowlist"` 尚无显式 ID 时)。 + `channels.telegram.allowFrom` accepts numeric Telegram user IDs. `telegram:` / `tg:` prefixes are accepted and normalized. + In multi-account configs, a restrictive top-level `channels.telegram.allowFrom` is treated as a safety boundary: account-level `allowFrom: ["*"]` entries do not make that account public unless the effective account allowlist still contains an explicit wildcard after merging. + `dmPolicy: "allowlist"` with empty `allowFrom` blocks all DMs and is rejected by config validation. + Setup asks for numeric user IDs only. + If you upgraded and your config contains `@username` allowlist entries, run `openclaw doctor --fix` to resolve them (best-effort; requires a Telegram bot token). + If you previously relied on pairing-store allowlist files, `openclaw doctor --fix` can recover entries into `channels.telegram.allowFrom` in allowlist flows (for example when `dmPolicy: "allowlist"` has no explicit IDs yet). - 对于单所有者 bot,建议使用 `dmPolicy: "allowlist"` 并配置显式数字 `allowFrom` ID,以便在配置中持久保存访问策略(而不是依赖之前的配对批准)。 + For one-owner bots, prefer `dmPolicy: "allowlist"` with explicit numeric `allowFrom` IDs to keep access policy durable in config (instead of depending on previous pairing approvals). - 常见误解:私信配对批准并不意味着“此发送者在所有地方都已授权”。 - 配对授予私信访问权限。如果尚不存在命令所有者,第一次批准的配对也会设置 `commands.ownerAllowFrom`,使仅所有者命令和 exec 批准拥有显式操作员账号。 - 群组发送者授权仍来自显式配置允许列表。 - 如果你想要“我授权一次后,私信和群组命令都可用”,请将你的数字 Telegram 用户 ID 放入 `channels.telegram.allowFrom`;对于仅所有者命令,请确保 `commands.ownerAllowFrom` 包含 `telegram:`。 + Common confusion: DM pairing approval does not mean "this sender is authorized everywhere". + Pairing grants DM access. If no command owner exists yet, the first approved pairing also sets `commands.ownerAllowFrom` so owner-only commands and exec approvals have an explicit operator account. + Group sender authorization still comes from explicit config allowlists. + If you want "I am authorized once and both DMs and group commands work", put your numeric Telegram user ID in `channels.telegram.allowFrom`; for owner-only commands, make sure `commands.ownerAllowFrom` contains `telegram:`. - ### 查找你的 Telegram 用户 ID + ### Finding your Telegram user ID - 更安全(无第三方 bot): + Safer (no third-party bot): - 1. 给你的 bot 发送私信。 - 2. 运行 `openclaw logs --follow`。 - 3. 读取 `from.id`。 + 1. DM your bot. + 2. Run `openclaw logs --follow`. + 3. Read `from.id`. - 官方 Bot API 方法: + Official Bot API method: ```bash curl "https://api.telegram.org/bot/getUpdates" ``` - 第三方方法(隐私性较低):`@userinfobot` 或 `@getidsbot`。 + Third-party method (less private): `@userinfobot` or `@getidsbot`. - - 两个控制项会共同生效: + + Two controls apply together: - 1. **允许哪些群组**(`channels.telegram.groups`) - - 没有 `groups` 配置: - - 使用 `groupPolicy: "open"`:任何群组都可以通过群组 ID 检查 - - 使用 `groupPolicy: "allowlist"`(默认):群组会被阻止,直到你添加 `groups` 条目(或 `"*"`) - - 已配置 `groups`:作为允许列表生效(显式 ID 或 `"*"`) + 1. **Which groups are allowed** (`channels.telegram.groups`) + - no `groups` config: + - with `groupPolicy: "open"`: any group can pass group-ID checks + - with `groupPolicy: "allowlist"` (default): groups are blocked until you add `groups` entries (or `"*"`) + - `groups` configured: acts as allowlist (explicit IDs or `"*"`) - 2. **群组中允许哪些发送者**(`channels.telegram.groupPolicy`) + 2. **Which senders are allowed in groups** (`channels.telegram.groupPolicy`) - `open` - - `allowlist`(默认) + - `allowlist` (default) - `disabled` - `groupAllowFrom` 用于群组发送者过滤。如果未设置,Telegram 会回退到 `allowFrom`。 - `groupAllowFrom` 条目应为数字 Telegram 用户 ID(`telegram:` / `tg:` 前缀会被规范化)。 - 不要将 Telegram 群组或超级群组聊天 ID 放入 `groupAllowFrom`。负数聊天 ID 应放在 `channels.telegram.groups` 下。 - 非数字条目在发送者授权中会被忽略。 - 安全边界(`2026.2.25+`):群组发送者认证**不会**继承私信配对存储批准。 - 配对仅适用于私信。对于群组,请设置 `groupAllowFrom` 或每群组/每话题的 `allowFrom`。 - 如果未设置 `groupAllowFrom`,Telegram 会回退到配置中的 `allowFrom`,而不是配对存储。 - 单所有者 bot 的实用模式:在 `channels.telegram.allowFrom` 中设置你的用户 ID,保持 `groupAllowFrom` 未设置,并在 `channels.telegram.groups` 下允许目标群组。 - 运行时说明:如果完全缺少 `channels.telegram`,除非显式设置了 `channels.defaults.groupPolicy`,否则运行时默认以失败关闭方式使用 `groupPolicy="allowlist"`。 + `groupAllowFrom` is used for group sender filtering. If not set, Telegram falls back to `allowFrom`. + `groupAllowFrom` entries should be numeric Telegram user IDs (`telegram:` / `tg:` prefixes are normalized). + Do not put Telegram group or supergroup chat IDs in `groupAllowFrom`. Negative chat IDs belong under `channels.telegram.groups`. + Non-numeric entries are ignored for sender authorization. + Security boundary (`2026.2.25+`): group sender auth does **not** inherit DM pairing-store approvals. + Pairing stays DM-only. For groups, set `groupAllowFrom` or per-group/per-topic `allowFrom`. + If `groupAllowFrom` is unset, Telegram falls back to config `allowFrom`, not the pairing store. + Practical pattern for one-owner bots: set your user ID in `channels.telegram.allowFrom`, leave `groupAllowFrom` unset, and allow the target groups under `channels.telegram.groups`. + Runtime note: if `channels.telegram` is completely missing, runtime defaults to fail-closed `groupPolicy="allowlist"` unless `channels.defaults.groupPolicy` is explicitly set. - 示例:允许某个特定群组中的任何成员: + Example: allow any member in one specific group: ```json5 { @@ -193,7 +193,7 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - 示例:只允许某个特定群组中的特定用户: + Example: allow only specific users inside one specific group: ```json5 { @@ -211,34 +211,34 @@ curl "https://api.telegram.org/bot/getUpdates" ``` - 常见错误:`groupAllowFrom` 不是 Telegram 群组允许列表。 + Common mistake: `groupAllowFrom` is not a Telegram group allowlist. - - 将像 `-1001234567890` 这样的负数 Telegram 群组或超级群组聊天 ID 放在 `channels.telegram.groups` 下。 - - 当你想限制允许群组中哪些人可以触发 bot 时,将像 `8734062810` 这样的 Telegram 用户 ID 放在 `groupAllowFrom` 下。 - - 仅当你希望允许群组中的任何成员都能与 bot 对话时,才使用 `groupAllowFrom: ["*"]`。 + - Put negative Telegram group or supergroup chat IDs like `-1001234567890` under `channels.telegram.groups`. + - Put Telegram user IDs like `8734062810` under `groupAllowFrom` when you want to limit which people inside an allowed group can trigger the bot. + - Use `groupAllowFrom: ["*"]` only when you want any member of an allowed group to be able to talk to the bot. - - 群组回复默认需要提及。 + + Group replies require mention by default. - 提及可以来自: + Mention can come from: - - 原生 `@botusername` 提及,或 - - 以下位置的提及模式: + - native `@botusername` mention, or + - mention patterns in: - `agents.list[].groupChat.mentionPatterns` - `messages.groupChat.mentionPatterns` - 会话级命令开关: + Session-level command toggles: - `/activation always` - `/activation mention` - 这些只会更新会话状态。使用配置来持久化。 + These update session state only. Use config for persistence. - 持久化配置示例: + Persistent config example: ```json5 { @@ -252,45 +252,45 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - 获取群组聊天 ID: + Getting the group chat ID: - - 将群组消息转发给 `@userinfobot` / `@getidsbot` - - 或从 `openclaw logs --follow` 读取 `chat.id` - - 或检查 Bot API `getUpdates` + - forward a group message to `@userinfobot` / `@getidsbot` + - or read `chat.id` from `openclaw logs --follow` + - or inspect Bot API `getUpdates` -## 运行时行为 +## Runtime behavior -- Telegram 由 gateway 进程拥有。 -- 路由是确定性的:Telegram 入站消息会回复到 Telegram(模型不会选择渠道)。 -- 入站消息会规范化为共享渠道信封,包含回复元数据和媒体占位符。 -- 群组会话按群组 ID 隔离。论坛话题会追加 `:topic:` 以保持话题隔离。 -- 私信消息可以携带 `message_thread_id`;OpenClaw 会保留线程 ID 用于回复,但默认保持私信使用扁平会话。当你有意需要私信话题会话隔离时,请配置 `channels.telegram.dm.threadReplies: "inbound"`、`channels.telegram.direct..threadReplies: "inbound"`、`requireTopic: true`,或匹配的话题配置。 -- 长轮询使用 grammY runner,并按每聊天/每线程排序。整体 runner sink 并发使用 `agents.defaults.maxConcurrent`。 -- 每个 gateway 进程内部都会保护长轮询,因此同一时间只有一个活跃 poller 可以使用一个 bot token。如果你仍然看到 `getUpdates` 409 冲突,很可能是另一个 OpenClaw gateway、脚本或外部 poller 正在使用同一个 token。 -- 默认情况下,长轮询看门狗重启会在 120 秒没有完成 `getUpdates` 存活检查后触发。只有当你的部署在长时间运行的工作期间仍看到误判的轮询停滞重启时,才增加 `channels.telegram.pollingStallThresholdMs`。该值以毫秒为单位,允许范围为 `30000` 到 `600000`;支持按账号覆盖。 -- Telegram Bot API 不支持已读回执(`sendReadReceipts` 不适用)。 +- Telegram is owned by the gateway process. +- Routing is deterministic: Telegram inbound replies back to Telegram (the model does not pick channels). +- Inbound messages normalize into the shared channel envelope with reply metadata and media placeholders. +- Group sessions are isolated by group ID. Forum topics append `:topic:` to keep topics isolated. +- DM messages can carry `message_thread_id`; OpenClaw preserves the thread ID for replies but keeps DMs on the flat session by default. Configure `channels.telegram.dm.threadReplies: "inbound"`, `channels.telegram.direct..threadReplies: "inbound"`, `requireTopic: true`, or a matching topic config when you intentionally want DM topic session isolation. +- Long polling uses grammY runner with per-chat/per-thread sequencing. Overall runner sink concurrency uses `agents.defaults.maxConcurrent`. +- Long polling is guarded inside each gateway process so only one active poller can use a bot token at a time. If you still see `getUpdates` 409 conflicts, another OpenClaw gateway, script, or external poller is likely using the same token. +- Long-polling watchdog restarts trigger after 120 seconds without completed `getUpdates` liveness by default. Increase `channels.telegram.pollingStallThresholdMs` only if your deployment still sees false polling-stall restarts during long-running work. The value is in milliseconds and is allowed from `30000` to `600000`; per-account overrides are supported. +- Telegram Bot API has no read-receipt support (`sendReadReceipts` does not apply). -## 功能参考 +## Feature reference - - OpenClaw 可以实时流式传输部分回复: + + OpenClaw can stream partial replies in real time: - - 直接聊天:预览消息 + `editMessageText` - - 群组/话题:预览消息 + `editMessageText` + - direct chats: preview message + `editMessageText` + - groups/topics: preview message + `editMessageText` - 要求: + Requirement: - - `channels.telegram.streaming` 为 `off | partial | block | progress`(默认:`partial`) - - `progress` 会保留一个可编辑的 Status 草稿,并使用工具进度更新它,直到最终送达 - - `streaming.preview.toolProgress` 控制工具/进度更新是否复用同一条已编辑预览消息(默认:预览流式传输启用时为 `true`) - - `streaming.preview.commandText` 控制这些工具进度行中的命令/exec 详情:`raw`(默认,保留已发布行为)或 `status`(仅工具标签) - - 会检测旧版 `channels.telegram.streamMode` 和布尔型 `streaming` 值;运行 `openclaw doctor --fix` 将它们迁移到 `channels.telegram.streaming.mode` + - `channels.telegram.streaming` is `off | partial | block | progress` (default: `partial`) + - `progress` keeps one editable status draft and updates it with tool progress until final delivery + - `streaming.preview.toolProgress` controls whether tool/progress updates reuse the same edited preview message (default: `true` when preview streaming is active) + - `streaming.preview.commandText` controls command/exec detail inside those tool-progress lines: `raw` (default, preserves released behavior) or `status` (tool label only) + - legacy `channels.telegram.streamMode` and boolean `streaming` values are detected; run `openclaw doctor --fix` to migrate them to `channels.telegram.streaming.mode` - 工具进度预览更新是在工具运行时显示的短 Status 行,例如命令执行、文件读取、规划更新或 patch 摘要。Telegram 默认启用这些更新,以匹配 `v2026.4.22` 及之后版本中已发布的 OpenClaw 行为。若要保留答案文本的已编辑预览,但隐藏工具进度行,请设置: + Tool-progress preview updates are the short status lines shown while tools run, for example command execution, file reads, planning updates, or patch summaries. Telegram keeps these enabled by default to match released OpenClaw behavior from `v2026.4.22` and later. To keep the edited preview for answer text but hide tool-progress lines, set: ```json { @@ -307,7 +307,7 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - 若要保持工具进度可见但隐藏命令/exec 文本,请设置: + To keep tool-progress visible but hide command/exec text, set: ```json { @@ -324,7 +324,7 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - 对于进度草稿模式,将同样的命令文本策略放在 `streaming.progress` 下: + 对于进度草稿模式,将相同的命令文本策略放在 `streaming.progress` 下: ```json { @@ -342,34 +342,35 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - 仅在你需要只交付最终内容时使用 `streaming.mode: "off"`:Telegram 预览编辑会被禁用,通用工具/进度杂讯会被抑制,而不是作为独立 Status 消息发送。审批提示、媒体载荷和错误仍会通过正常最终交付路径发送。当你只想保留回答预览编辑,同时隐藏工具进度 Status 行时,使用 `streaming.preview.toolProgress: false`。 + 仅当你希望只进行最终交付时,才使用 `streaming.mode: "off"`:Telegram 预览编辑会被禁用,通用工具/进度杂讯会被抑制,而不是作为独立 Status 消息发送。审批提示、媒体载荷和错误仍会通过正常的最终交付路径路由。当你只想保留答案预览编辑,同时隐藏工具进度 Status 行时,使用 `streaming.preview.toolProgress: false`。 - Telegram 选中引用回复是例外。当 `replyToMode` 为 `"first"`、`"all"` 或 `"batched"`,且入站消息包含选中的引用文本时,OpenClaw 会通过 Telegram 的原生引用回复路径发送最终回答,而不是编辑回答预览,因此 `streaming.preview.toolProgress` 无法显示该轮的简短 Status 行。不含选中引用文本的当前消息回复仍会保留预览流式传输。当工具进度可见性比原生引用回复更重要时,设置 `replyToMode: "off"`,或设置 `streaming.preview.toolProgress: false` 以确认这种取舍。 + Telegram 选中文本引用回复是例外。当 `replyToMode` 为 `"first"`、`"all"` 或 `"batched"`,且入站消息包含选中的引用文本时,OpenClaw 会通过 Telegram 的原生引用回复路径发送最终答案,而不是编辑答案预览,因此 `streaming.preview.toolProgress` 无法为该轮显示短 Status 行。没有选中引用文本的当前消息回复仍会保留预览流式传输。当工具进度可见性比原生引用回复更重要时,设置 `replyToMode: "off"`;或者设置 `streaming.preview.toolProgress: false` 以接受该取舍。 对于纯文本回复: - - 简短私信/群组/topic 预览:OpenClaw 会保留同一条预览消息,并在原位置执行最终编辑,除非预览出现后发送过一条可见的非预览消息 - - 预览之后跟随可见的非预览输出:OpenClaw 会将完成后的回复作为新的最终消息发送,并清理较旧的预览,因此最终回答会出现在中间输出之后 - - 超过约一分钟的预览:OpenClaw 会将完成后的回复作为新的最终消息发送,然后清理预览,因此 Telegram 的可见时间戳会反映完成时间,而不是预览创建时间 + - 简短私信/群组/topic 预览:OpenClaw 会保留同一条预览消息并在原位执行最终编辑,除非预览出现后发送过可见的非预览消息 + - 拆分成多条 Telegram 消息的长文本最终结果会尽可能复用现有预览作为第一个最终分块,然后只发送剩余分块 + - 预览之后出现可见的非预览输出:OpenClaw 会将完成后的回复作为新的最终消息发送,并清理旧预览,因此最终答案会出现在中间输出之后 + - 超过约一分钟的预览:OpenClaw 会将完成后的回复作为新的最终消息发送,然后清理预览,因此 Telegram 可见时间戳反映的是完成时间,而不是预览创建时间 - 对于复杂回复(例如媒体载荷),OpenClaw 会回退到正常最终交付,然后清理预览消息。 + 对于复杂回复(例如媒体载荷),OpenClaw 会回退到正常的最终交付,然后清理预览消息。 - 预览流式传输与分块流式传输相互独立。当为 Telegram 显式启用分块流式传输时,OpenClaw 会跳过预览流,以避免双重流式传输。 + 预览流式传输与分块流式传输是分开的。当为 Telegram 显式启用分块流式传输时,OpenClaw 会跳过预览流,以避免双重流式传输。 仅限 Telegram 的推理流: - - `/reasoning stream` 会在生成期间将推理发送到实时预览 + - `/reasoning stream` 会在生成过程中将推理发送到实时预览 - 最终交付后会删除推理预览;当推理应保持可见时,使用 `/reasoning on` - - 最终回答发送时不包含推理文本 + - 最终答案发送时不包含推理文本 - + 出站文本使用 Telegram `parse_mode: "HTML"`。 - - 类 Markdown 文本会渲染为 Telegram 安全的 HTML。 + - 类 Markdown 文本会渲染为 Telegram 安全 HTML。 - 原始模型 HTML 会被转义,以减少 Telegram 解析失败。 - 如果 Telegram 拒绝解析后的 HTML,OpenClaw 会以纯文本重试。 @@ -377,14 +378,14 @@ curl "https://api.telegram.org/bot/getUpdates" - + Telegram 命令菜单注册会在启动时通过 `setMyCommands` 处理。 原生命令默认值: - - `commands.native: "auto"` 会为 Telegram 启用原生命令 + - `commands.native: "auto"` 为 Telegram 启用原生命令 - 添加自定义命令菜单条目: + 添加自定义命令菜单项: ```json5 { @@ -401,47 +402,47 @@ curl "https://api.telegram.org/bot/getUpdates" 规则: - - 名称会规范化(去掉前导 `/`,转为小写) + - 名称会被规范化(移除前导 `/`,转为小写) - 有效模式:`a-z`、`0-9`、`_`,长度 `1..32` - 自定义命令不能覆盖原生命令 - 冲突/重复项会被跳过并记录日志 注意: - - 自定义命令只是菜单条目;它们不会自动实现行为 - - 插件/skill 命令即使未显示在 Telegram 菜单中,键入时仍可工作 + - 自定义命令仅是菜单项;它们不会自动实现行为 + - 即使未显示在 Telegram 菜单中,插件/skill 命令在输入时仍可工作 - 如果禁用原生命令,内置命令会被移除。自定义/插件命令在配置后仍可能注册。 + 如果原生命令被禁用,内置命令会被移除。自定义/插件命令如果已配置,仍可能注册。 常见设置失败: - - `setMyCommands failed` 带 `BOT_COMMANDS_TOO_MUCH` 表示 Telegram 菜单在裁剪后仍溢出;减少插件/skill/自定义命令,或禁用 `channels.telegram.commands.native`。 - - 当直接的 Bot API curl 命令可用,但 `deleteWebhook`、`deleteMyCommands` 或 `setMyCommands` 因 `404: Not Found` 失败时,可能表示 `channels.telegram.apiRoot` 被设置为了完整的 `/bot` 端点。`apiRoot` 必须只是 Bot API 根路径,`openclaw doctor --fix` 会移除意外尾随的 `/bot`。 - - `getMe returned 401` 表示 Telegram 拒绝了配置的 bot 令牌。使用当前 BotFather 令牌更新 `botToken`、`tokenFile` 或 `TELEGRAM_BOT_TOKEN`;OpenClaw 会在轮询前停止,因此这不会被报告为 webhook 清理失败。 - - `setMyCommands failed` 带网络/fetch 错误通常表示到 `api.telegram.org` 的出站 DNS/HTTPS 被阻止。 + - `setMyCommands failed` 并带有 `BOT_COMMANDS_TOO_MUCH` 表示 Telegram 菜单在裁剪后仍然溢出;减少插件/skill/自定义命令,或禁用 `channels.telegram.commands.native`。 + - 当直接 Bot API curl 命令可用,但 `deleteWebhook`、`deleteMyCommands` 或 `setMyCommands` 失败并返回 `404: Not Found` 时,可能表示 `channels.telegram.apiRoot` 被设置为完整的 `/bot` 端点。`apiRoot` 必须只是 Bot API 根地址,且 `openclaw doctor --fix` 会移除意外尾随的 `/bot`。 + - `getMe returned 401` 表示 Telegram 拒绝了已配置的 bot token。用当前 BotFather token 更新 `botToken`、`tokenFile` 或 `TELEGRAM_BOT_TOKEN`;OpenClaw 会在轮询前停止,因此这不会被报告为 webhook 清理失败。 + - `setMyCommands failed` 并带有网络/fetch 错误通常表示到 `api.telegram.org` 的出站 DNS/HTTPS 被阻止。 ### 设备配对命令(`device-pair` 插件) 安装 `device-pair` 插件后: 1. `/pair` 生成设置代码 - 2. 在 iOS 应用中粘贴代码 + 2. 在 iOS app 中粘贴代码 3. `/pair pending` 列出待处理请求(包括角色/作用域) 4. 批准请求: - `/pair approve ` 用于显式批准 - - `/pair approve` 用于只有一个待处理请求的情况 - - `/pair approve latest` 用于最新请求 + - 当只有一个待处理请求时使用 `/pair approve` + - `/pair approve latest` 用于最近的请求 - 设置代码携带一个短期有效的引导令牌。内置引导交接会将主节点令牌保持在 `scopes: []`;任何交接的 operator 令牌仍被限制在 `operator.approvals`、`operator.read`、`operator.talk.secrets` 和 `operator.write`。引导作用域检查带有角色前缀,因此该 operator 允许列表只满足 operator 请求;非 operator 角色仍需要其自身角色前缀下的作用域。 + 设置代码携带一个短生命周期的 bootstrap token。内置 bootstrap 移交会将主节点 token 保持在 `scopes: []`;任何被移交的 operator token 都会被限定在 `operator.approvals`、`operator.read`、`operator.talk.secrets` 和 `operator.write`。Bootstrap 作用域检查带有角色前缀,因此该 operator 允许列表只满足 operator 请求;非 operator 角色仍需要其自身角色前缀下的作用域。 - 如果设备使用变更后的认证详细信息重试(例如角色/作用域/公钥),之前的待处理请求会被取代,新的请求会使用不同的 `requestId`。批准前请重新运行 `/pair pending`。 + 如果设备使用变更后的认证详细信息(例如角色/作用域/公钥)重试,之前的待处理请求会被取代,新请求会使用不同的 `requestId`。批准前重新运行 `/pair pending`。 更多详情:[配对](/zh-CN/channels/pairing#pair-via-telegram-recommended-for-ios)。 - - 配置内联键盘范围: + + 配置内联键盘作用域: ```json5 { @@ -473,7 +474,7 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - 范围: + 作用域: - `off` - `dm` @@ -506,16 +507,16 @@ curl "https://api.telegram.org/bot/getUpdates" - + Telegram 工具操作包括: - - `sendMessage`(`to`、`content`、可选 `mediaUrl`、`replyToMessageId`、`messageThreadId`) + - `sendMessage`(`to`、`content`,可选 `mediaUrl`、`replyToMessageId`、`messageThreadId`) - `react`(`chatId`、`messageId`、`emoji`) - `deleteMessage`(`chatId`、`messageId`) - `editMessage`(`chatId`、`messageId`、`content`) - - `createForumTopic`(`chatId`、`name`、可选 `iconColor`、`iconCustomEmojiId`) + - `createForumTopic`(`chatId`、`name`,可选 `iconColor`、`iconCustomEmojiId`) - 渠道消息操作会暴露符合人体工学的别名(`send`、`react`、`delete`、`edit`、`sticker`、`sticker-search`、`topic-create`)。 + 频道消息操作暴露了符合人体工程学的别名(`send`、`react`、`delete`、`edit`、`sticker`、`sticker-search`、`topic-create`)。 门控控制: @@ -524,14 +525,14 @@ curl "https://api.telegram.org/bot/getUpdates" - `channels.telegram.actions.reactions` - `channels.telegram.actions.sticker`(默认:禁用) - 注意:`edit` 和 `topic-create` 当前默认启用,并且没有单独的 `channels.telegram.actions.*` 开关。 - 运行时发送使用活动配置/密钥快照(启动/重载),因此操作路径不会在每次发送时执行临时 SecretRef 重新解析。 + 注意:`edit` 和 `topic-create` 当前默认启用,且没有单独的 `channels.telegram.actions.*` 开关。 + 运行时发送使用活动配置/secrets 快照(启动/重新加载),因此操作路径不会在每次发送时执行临时 SecretRef 重新解析。 - 移除回应的语义:[/tools/reactions](/zh-CN/tools/reactions) + Reaction 移除语义:[/tools/reactions](/zh-CN/tools/reactions) - + Telegram 支持在生成输出中使用显式回复线程标签: - `[[reply_to_current]]` 回复触发消息 @@ -543,29 +544,29 @@ curl "https://api.telegram.org/bot/getUpdates" - `first` - `all` - 当启用回复线程,且原始 Telegram 文本或说明文字可用时,OpenClaw 会自动包含原生 Telegram 引用摘录。Telegram 将原生引用文本限制为 1024 个 UTF-16 代码单元,因此较长消息会从开头引用;如果 Telegram 拒绝该引用,则回退为普通回复。 + 当回复线程启用且原始 Telegram 文本或标题可用时,OpenClaw 会自动包含原生 Telegram 引用摘录。Telegram 将原生引用文本限制为 1024 个 UTF-16 代码单元,因此更长的消息会从开头引用;如果 Telegram 拒绝引用,则回退为普通回复。 注意:`off` 会禁用隐式回复线程。显式 `[[reply_to_*]]` 标签仍会被遵循。 - - 论坛超级群组: + + Forum supergroup: - topic 会话键会追加 `:topic:` - - 回复和正在输入目标指向 topic 线程 + - 回复和正在输入操作会指向 topic 线程 - topic 配置路径: `channels.telegram.groups..topics.` - 常规 topic(`threadId=1`)特殊情况: + General topic(`threadId=1`)特殊情况: - 消息发送会省略 `message_thread_id`(Telegram 会拒绝 `sendMessage(...thread_id=1)`) - - 正在输入操作仍包含 `message_thread_id` + - 正在输入操作仍会包含 `message_thread_id` Topic 继承:topic 条目会继承群组设置,除非被覆盖(`requireMention`、`allowFrom`、`skills`、`systemPrompt`、`enabled`、`groupPolicy`)。 - `agentId` 仅限 topic,不会从群组默认值继承。 + `agentId` 仅属于 topic,不会从群组默认值继承。 - **按 topic 的智能体路由**:每个 topic 都可以通过在 topic 配置中设置 `agentId` 路由到不同的智能体。这会让每个 topic 拥有各自隔离的工作区、记忆和会话。示例: + **按 topic 的智能体路由**:每个 topic 都可以通过在 topic 配置中设置 `agentId` 路由到不同智能体。这让每个 topic 都有自己的隔离工作区、记忆和会话。示例: ```json5 { @@ -585,26 +586,24 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - 然后每个 topic 都有自己的会话键:`agent:zu:telegram:group:-1001234567890:topic:3` + 随后每个 topic 都有自己的会话键:`agent:zu:telegram:group:-1001234567890:topic:3` - **持久 ACP topic 绑定**:论坛 topic 可以通过顶层类型化 ACP 绑定固定 ACP harness 会话(`bindings[]`,包含 `type: "acp"` 和 `match.channel: "telegram"`、`peer.kind: "group"`,以及类似 `-1001234567890:topic:42` 的 topic 限定 id)。当前范围限定为群组/超级群组中的论坛 topic。参见 [ACP Agents](/zh-CN/tools/acp-agents)。 + **持久 ACP topic 绑定**:Forum topic 可以通过顶层类型化 ACP 绑定(`bindings[]`,包含 `type: "acp"`、`match.channel: "telegram"`、`peer.kind: "group"`,以及类似 `-1001234567890:topic:42` 的 topic 限定 id)固定 ACP harness 会话。当前作用域限于群组/supergroup 中的 forum topic。参见 [ACP Agents](/zh-CN/tools/acp-agents)。 - **从聊天创建线程绑定 ACP**:`/acp spawn --thread here|auto` 会将当前 topic 绑定到新的 ACP 会话;后续消息会直接路由到那里。OpenClaw 会将创建确认固定在 topic 内。需要 `channels.telegram.threadBindings.spawnSessions` 保持启用(默认:`true`)。 + **从聊天生成线程绑定 ACP**:`/acp spawn --thread here|auto` 将当前 topic 绑定到新的 ACP 会话;后续消息会直接路由到那里。OpenClaw 会在 topic 内固定生成确认。需要保持启用 `channels.telegram.threadBindings.spawnSessions`(默认:`true`)。 - 模板上下文会暴露 `MessageThreadId` 和 `IsForum`。带有 `message_thread_id` 的私信聊天默认在扁平会话上保留私信路由和回复元数据;只有在配置了 `threadReplies: "inbound"`、`threadReplies: "always"`、`requireTopic: true` 或匹配的 topic 配置时,才会使用线程感知的会话键。使用顶层 `channels.telegram.dm.threadReplies` 设置账户默认值,或使用 `direct..threadReplies` 设置单个私信。 + 模板上下文会暴露 `MessageThreadId` 和 `IsForum`。带有 `message_thread_id` 的私信聊天默认在扁平会话上保留私信路由和回复元数据;只有在配置了 `threadReplies: "inbound"`、`threadReplies: "always"`、`requireTopic: true` 或匹配的主题配置时,它们才会使用线程感知的会话键。使用顶层 `channels.telegram.dm.threadReplies` 作为账号默认值,或使用 `direct..threadReplies` 针对某个私信设置。 - + ### 音频消息 - Telegram 会区分语音便签和音频文件。 + Telegram 会区分语音消息和音频文件。 - 默认:音频文件行为 - - 在智能体回复中添加标签 `[[audio_as_voice]]`,强制以语音便签发送 - - 入站语音便签转写会在智能体上下文中被标记为机器生成、 - 不受信任的文本;提及检测仍使用原始 - 转写,因此受提及门控的语音消息会继续工作。 + - 在智能体回复中添加标签 `[[audio_as_voice]]` 可强制作为语音消息发送 + - 入站语音消息的转录会在智能体上下文中被标记为机器生成的、不受信任的文本;提及检测仍使用原始转录,因此受提及门控的语音消息会继续生效。 消息操作示例: @@ -620,7 +619,7 @@ curl "https://api.telegram.org/bot/getUpdates" ### 视频消息 - Telegram 会区分视频文件和视频便签。 + Telegram 会区分视频文件和视频消息。 消息操作示例: @@ -634,7 +633,7 @@ curl "https://api.telegram.org/bot/getUpdates" } ``` - 视频便签不支持字幕;提供的消息文本会单独发送。 + 视频消息不支持说明文字;提供的消息文本会单独发送。 ### 贴纸 @@ -656,7 +655,7 @@ curl "https://api.telegram.org/bot/getUpdates" - `~/.openclaw/telegram/sticker-cache.json` - 贴纸会被描述一次(如果可行)并缓存,以减少重复的视觉调用。 + 贴纸会被描述一次(如果可行),并缓存以减少重复的视觉调用。 启用贴纸操作: @@ -696,10 +695,10 @@ curl "https://api.telegram.org/bot/getUpdates" - - Telegram 回应会作为 `message_reaction` 更新到达(与消息载荷分离)。 + + Telegram 表情回应会以 `message_reaction` 更新形式到达(独立于消息负载)。 - 启用后,OpenClaw 会将如下系统事件加入队列: + 启用后,OpenClaw 会将类似下面的系统事件加入队列: - `Telegram reaction added: 👍 by Alice (@alice) on msg 42` @@ -708,36 +707,36 @@ curl "https://api.telegram.org/bot/getUpdates" - `channels.telegram.reactionNotifications`:`off | own | all`(默认:`own`) - `channels.telegram.reactionLevel`:`off | ack | minimal | extensive`(默认:`minimal`) - 注意事项: + 说明: - - `own` 表示仅用户对机器人发送消息的回应(通过已发送消息缓存尽力实现)。 - - 回应事件仍遵循 Telegram 访问控制(`dmPolicy`、`allowFrom`、`groupPolicy`、`groupAllowFrom`);未授权发送者会被丢弃。 - - Telegram 不会在回应更新中提供线程 ID。 - - 非论坛群组路由到群组聊天会话 - - 论坛群组路由到群组通用 topic 会话(`:topic:1`),而不是确切的来源 topic + - `own` 表示仅用户对机器人发送消息的表情回应(通过已发送消息缓存尽力判断)。 + - 表情回应事件仍遵守 Telegram 访问控制(`dmPolicy`、`allowFrom`、`groupPolicy`、`groupAllowFrom`);未授权发送者会被丢弃。 + - Telegram 不会在表情回应更新中提供线程 ID。 + - 非论坛群组会路由到群聊会话 + - 论坛群组会路由到群组通用主题会话(`:topic:1`),而不是确切的来源主题 - 轮询/webhook 的 `allowed_updates` 会自动包含 `message_reaction`。 + 用于轮询/webhook 的 `allowed_updates` 会自动包含 `message_reaction`。 - - `ackReaction` 会在 OpenClaw 处理入站消息时发送一个确认 emoji。 + + `ackReaction` 会在 OpenClaw 处理入站消息时发送一个确认表情符号。 解析顺序: - `channels.telegram.accounts..ackReaction` - `channels.telegram.ackReaction` - `messages.ackReaction` - - 智能体身份 emoji 回退(`agents.list[].identity.emoji`,否则为 "👀") + - 智能体身份表情符号回退值(`agents.list[].identity.emoji`,否则为 “👀”) - 注意事项: + 说明: - - Telegram 期望使用 unicode emoji(例如 "👀")。 - - 使用 `""` 可为某个渠道或账户禁用回应。 + - Telegram 期望 unicode 表情符号(例如 “👀”)。 + - 使用 `""` 可为某个渠道或账号禁用该表情回应。 - + 渠道配置写入默认启用(`configWrites !== false`)。 Telegram 触发的写入包括: @@ -759,32 +758,32 @@ curl "https://api.telegram.org/bot/getUpdates" - - 默认使用长轮询。对于 webhook 模式,设置 `channels.telegram.webhookUrl` 和 `channels.telegram.webhookSecret`;可选设置 `webhookPath`、`webhookHost`、`webhookPort`(默认值为 `/telegram-webhook`、`127.0.0.1`、`8787`)。 + + 默认使用长轮询。若要使用 webhook 模式,请设置 `channels.telegram.webhookUrl` 和 `channels.telegram.webhookSecret`;可选设置 `webhookPath`、`webhookHost`、`webhookPort`(默认分别为 `/telegram-webhook`、`127.0.0.1`、`8787`)。 本地监听器绑定到 `127.0.0.1:8787`。对于公网入口,可以在本地端口前放置反向代理,或有意设置 `webhookHost: "0.0.0.0"`。 - webhook 模式会先验证请求守卫、Telegram secret token 和 JSON 正文,然后才向 Telegram 返回 `200`。 - 随后 OpenClaw 会通过与长轮询相同的每聊天/每 topic 机器人通道异步处理该更新,因此较慢的智能体轮次不会阻塞 Telegram 的投递 ACK。 + webhook 模式会在向 Telegram 返回 `200` 之前验证请求防护、Telegram secret token 和 JSON 正文。 + 随后 OpenClaw 会通过与长轮询相同的按聊天/按主题机器人通道异步处理该更新,因此较慢的智能体回合不会阻塞 Telegram 的投递 ACK。 - + - `channels.telegram.textChunkLimit` 默认值为 4000。 - - `channels.telegram.chunkMode="newline"` 在按长度拆分前会优先选择段落边界(空行)。 + - `channels.telegram.chunkMode="newline"` 会优先按段落边界(空行)切分,再按长度切分。 - `channels.telegram.mediaMaxMb`(默认 100)限制入站和出站 Telegram 媒体大小。 - - `channels.telegram.mediaGroupFlushMs`(默认 500)控制 Telegram 相册/媒体组在 OpenClaw 将其作为一条入站消息分发前的缓冲时长。如果相册部分到达较晚,请增大该值;如果要降低相册回复延迟,请减小该值。 - - `channels.telegram.timeoutSeconds` 覆盖 Telegram API 客户端超时(如果未设置,则使用 grammY 默认值)。机器人客户端会将配置值限制在低于 60 秒出站文本/typing 请求守卫的范围内,避免 grammY 在 OpenClaw 的传输守卫和回退运行前中止可见回复投递。长轮询仍使用 45 秒的 `getUpdates` 请求守卫,因此空闲轮询不会被无限期遗弃。 - - `channels.telegram.pollingStallThresholdMs` 默认值为 `120000`;仅在误报轮询停滞重启时,在 `30000` 到 `600000` 之间调节。 + - `channels.telegram.mediaGroupFlushMs`(默认 500)控制 Telegram 相册/媒体组在 OpenClaw 将其作为一条入站消息分发前缓冲多久。如果相册部分到达较晚,请增大该值;若要降低相册回复延迟,请减小该值。 + - `channels.telegram.timeoutSeconds` 会覆盖 Telegram API 客户端超时(若未设置,则使用 grammY 默认值)。机器人客户端会将配置值限制在 60 秒出站文本/输入状态请求防护以下,避免 grammY 在 OpenClaw 的传输防护和回退逻辑运行前中止可见回复投递。长轮询仍使用 45 秒 `getUpdates` 请求防护,因此空闲轮询不会被无限期放弃。 + - `channels.telegram.pollingStallThresholdMs` 默认值为 `120000`;只有在出现误报的轮询停滞重启时,才在 `30000` 到 `600000` 之间调节。 - 群组上下文历史使用 `channels.telegram.historyLimit` 或 `messages.groupChat.historyLimit`(默认 50);`0` 表示禁用。 - - 回复/引用/转发的补充上下文目前按接收内容传递。 - - Telegram 允许列表主要用于控制谁可以触发智能体,而不是完整的补充上下文删减边界。 + - 回复/引用/转发的补充上下文目前会按收到的内容传递。 + - Telegram 允许列表主要控制谁能触发智能体,而不是完整的补充上下文脱敏边界。 - 私信历史控制: - `channels.telegram.dmHistoryLimit` - `channels.telegram.dms[""].historyLimit` - - `channels.telegram.retry` 配置适用于 Telegram 发送辅助函数(CLI/工具/操作),用于可恢复的出站 API 错误。入站最终回复投递也会对 Telegram 预连接失败使用有界安全发送重试,但不会重试可能造成可见消息重复的模糊发送后网络信封。 + - `channels.telegram.retry` 配置适用于 Telegram 发送辅助函数(CLI/工具/操作)中的可恢复出站 API 错误。入站最终回复投递也会针对 Telegram 预连接失败使用有界安全发送重试,但不会重试可能导致可见消息重复的模糊发送后网络封装。 - CLI 和消息工具发送目标可以是数字聊天 ID、用户名或论坛 topic 目标: + CLI 和消息工具发送目标可以是数字聊天 ID、用户名或论坛主题目标: ```bash openclaw message send --channel telegram --target 123456789 --message "hi" @@ -792,7 +791,7 @@ openclaw message send --channel telegram --target @name --message "hi" openclaw message send --channel telegram --target -1001234567890:topic:42 --message "hi topic" ``` - Telegram 投票使用 `openclaw message poll`,并支持论坛 topic: + Telegram 投票使用 `openclaw message poll`,并支持论坛主题: ```bash openclaw message poll --channel telegram --target 123456789 \ @@ -802,57 +801,57 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \ --poll-duration-seconds 300 --poll-public ``` - 仅 Telegram 的投票标志: + 仅 Telegram 支持的投票标志: - - `--poll-duration-seconds`(5-600) + - `--poll-duration-seconds` (5-600) - `--poll-anonymous` - `--poll-public` - - 用于论坛 topic 的 `--thread-id`(或使用 `:topic:` 目标) + - `--thread-id` 用于论坛主题(或使用 `:topic:` 目标) Telegram 发送还支持: - - 当 `channels.telegram.capabilities.inlineButtons` 允许时,将 `--presentation` 与 `buttons` 块配合用于内联键盘 + - 当 `channels.telegram.capabilities.inlineButtons` 允许时,使用带 `buttons` 块的 `--presentation` 创建内联键盘 - 当机器人可以在该聊天中置顶时,使用 `--pin` 或 `--delivery '{"pin":true}'` 请求置顶投递 - 使用 `--force-document` 将出站图片和 GIF 作为文档发送,而不是压缩照片或动画媒体上传 操作门控: - `channels.telegram.actions.sendMessage=false` 会禁用出站 Telegram 消息,包括投票 - - `channels.telegram.actions.poll=false` 会禁用 Telegram 投票创建,同时保留常规发送启用 + - `channels.telegram.actions.poll=false` 会禁用 Telegram 投票创建,但保留常规发送功能 - - Telegram 支持在批准者私信中进行 exec 批准,也可以选择在来源聊天或 topic 中发布提示。批准者必须是数字 Telegram 用户 ID。 + + Telegram 支持在审批者私信中进行 exec 审批,也可以选择在来源聊天或主题中发布提示。审批者必须是数字 Telegram 用户 ID。 配置路径: - - `channels.telegram.execApprovals.enabled`(当至少一个批准者可解析时自动启用) - - `channels.telegram.execApprovals.approvers`(回退到 `commands.ownerAllowFrom` 中的数字 owner ID) + - `channels.telegram.execApprovals.enabled`(当至少一个审批者可解析时自动启用) + - `channels.telegram.execApprovals.approvers`(回退到 `commands.ownerAllowFrom` 中的数字所有者 ID) - `channels.telegram.execApprovals.target`:`dm`(默认)| `channel` | `both` - `agentFilter`、`sessionFilter` - `channels.telegram.allowFrom`、`groupAllowFrom` 和 `defaultTo` 控制谁可以与机器人对话,以及机器人把普通回复发送到哪里。它们不会让某人成为 exec 批准者。当尚无命令 owner 时,第一个已批准的私信配对会引导初始化 `commands.ownerAllowFrom`,因此单 owner 设置仍可工作,而无需在 `execApprovals.approvers` 下重复 ID。 + `channels.telegram.allowFrom`、`groupAllowFrom` 和 `defaultTo` 控制谁可以与机器人对话以及机器人将普通回复发送到哪里。它们不会让某人成为 exec 审批者。当尚不存在命令所有者时,首次获批的私信配对会引导生成 `commands.ownerAllowFrom`,因此单所有者设置仍可正常工作,而不必在 `execApprovals.approvers` 下重复 ID。 - 渠道投递会在聊天中显示命令文本;仅在受信任的群组/topic 中启用 `channel` 或 `both`。当提示落在论坛 topic 中时,OpenClaw 会为批准提示和后续消息保留该 topic。exec 批准默认在 30 分钟后过期。 + 渠道投递会在聊天中显示命令文本;只应在受信任的群组/主题中启用 `channel` 或 `both`。当提示落在论坛主题中时,OpenClaw 会为审批提示和后续消息保留该主题。exec 审批默认在 30 分钟后过期。 - 内联批准按钮还要求 `channels.telegram.capabilities.inlineButtons` 允许目标表面(`dm`、`group` 或 `all`)。以 `plugin:` 为前缀的批准 ID 会通过插件批准解析;其他 ID 会先通过 exec 批准解析。 + 内联审批按钮还要求 `channels.telegram.capabilities.inlineButtons` 允许目标界面(`dm`、`group` 或 `all`)。以 `plugin:` 为前缀的审批 ID 会通过插件审批解析;其他 ID 会先通过 exec 审批解析。 - 请参阅 [exec 批准](/zh-CN/tools/exec-approvals)。 + 参见 [Exec 审批](/zh-CN/tools/exec-approvals)。 ## 错误回复控制 -当智能体遇到投递或提供商错误时,Telegram 可以回复错误文本,也可以抑制错误回复。两个配置键控制此行为: +当智能体遇到投递或提供商错误时,Telegram 可以回复错误文本,也可以抑制它。两个配置键控制此行为: -| 键 | 值 | 默认值 | 描述 | -| ----------------------------------- | ----------------- | ------- | --------------------------------------------------------------------------------------- | -| `channels.telegram.errorPolicy` | `reply`, `silent` | `reply` | `reply` 会向聊天发送一条友好的错误消息。`silent` 会完全抑制错误回复。 | -| `channels.telegram.errorCooldownMs` | number (ms) | `60000` | 向同一聊天发送错误回复的最小间隔时间。防止中断期间出现错误垃圾消息。 | +| 键 | 值 | 默认值 | 描述 | +| ----------------------------------- | ----------------- | ------- | ----------------------------------------------------------------------------------------------- | +| `channels.telegram.errorPolicy` | `reply`, `silent` | `reply` | `reply` 会向聊天发送友好的错误消息。`silent` 会完全抑制错误回复。 | +| `channels.telegram.errorCooldownMs` | 数字(毫秒) | `60000` | 同一聊天两次错误回复之间的最短时间。防止故障期间产生错误刷屏。 | -支持按账户、按群组和按 topic 覆盖(继承方式与其他 Telegram 配置键相同)。 +支持按账号、按群组和按主题覆盖(继承方式与其他 Telegram 配置键相同)。 ```json5 { @@ -873,13 +872,13 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \ ## 故障排除 - + - 如果 `requireMention=false`,Telegram 隐私模式必须允许完整可见性。 - BotFather:`/setprivacy` -> Disable - - 然后将机器人从群组中移除并重新添加 - - 当配置预期接收未提及机器人的群组消息时,`openclaw channels status` 会发出警告。 - - `openclaw channels status --probe` 可以检查显式数字群组 ID;通配符 `"*"` 无法进行成员探测。 + - 然后移除机器人并重新添加到群组 + - 当配置预期接收未提及的群组消息时,`openclaw channels status` 会发出警告。 + - `openclaw channels status --probe` 可以检查明确的数字群组 ID;通配符 `"*"` 无法探测成员资格。 - 快速会话测试:`/activation always`。 @@ -887,8 +886,8 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \ - 当 `channels.telegram.groups` 存在时,群组必须被列出(或包含 `"*"`) - - 验证机器人在群组中的成员身份 - - 查看日志:`openclaw logs --follow` 以了解跳过原因 + - 验证机器人在群组中的成员资格 + - 查看日志:使用 `openclaw logs --follow` 查看跳过原因 @@ -896,33 +895,33 @@ openclaw message poll --channel telegram --target -1001234567890:topic:42 \ - 授权你的发送者身份(配对和/或数字 `allowFrom`) - 即使群组策略为 `open`,命令授权仍然适用 - - `setMyCommands failed` 携带 `BOT_COMMANDS_TOO_MUCH` 表示原生命令菜单条目过多;减少插件/skill/自定义命令,或禁用原生菜单 - - `deleteMyCommands` / `setMyCommands` 启动调用和 `sendChatAction` 输入状态调用都有边界限制,并会在请求超时时通过 Telegram 的传输回退重试一次。持续的网络/抓取错误通常表示到 `api.telegram.org` 的 DNS/HTTPS 可达性存在问题 + - `setMyCommands failed` 与 `BOT_COMMANDS_TOO_MUCH` 表示原生命令菜单条目过多;减少插件/Skill/自定义命令,或禁用原生命令菜单 + - `deleteMyCommands` / `setMyCommands` 启动调用和 `sendChatAction` 正在输入调用都有边界限制,并会在请求超时时通过 Telegram 的传输回退重试一次。持续的网络/抓取错误通常表示到 `api.telegram.org` 的 DNS/HTTPS 可达性存在问题 - - `getMe returned 401` 是已配置机器人令牌的 Telegram 身份验证失败。 - - 在 BotFather 中重新复制或重新生成机器人令牌,然后更新默认账户的 `channels.telegram.botToken`、`channels.telegram.tokenFile`、`channels.telegram.accounts..botToken` 或 `TELEGRAM_BOT_TOKEN`。 - - 启动期间出现 `deleteWebhook 401 Unauthorized` 也是身份验证失败;将其视为“没有 webhook 存在”只会把相同的错误令牌失败推迟到后续 API 调用。 + - `getMe returned 401` 是配置的机器人令牌发生 Telegram 身份验证失败。 + - 在 BotFather 中重新复制或重新生成机器人令牌,然后为默认账号更新 `channels.telegram.botToken`、`channels.telegram.tokenFile`、`channels.telegram.accounts..botToken` 或 `TELEGRAM_BOT_TOKEN`。 + - 启动期间的 `deleteWebhook 401 Unauthorized` 也是身份验证失败;将其视为“webhook 不存在”只会把同一个错误令牌失败推迟到后续 API 调用。 - - Node 22+ + 自定义 fetch/proxy 在 AbortSignal 类型不匹配时可能触发立即中止行为。 - - 一些主机会先将 `api.telegram.org` 解析为 IPv6;损坏的 IPv6 出站可能导致间歇性的 Telegram API 失败。 - - 如果日志包含 `TypeError: fetch failed` 或 `Network request for 'getUpdates' failed!`,OpenClaw 现在会将这些作为可恢复的网络错误重试。 - - 在轮询启动期间,OpenClaw 会为 grammY 复用启动时成功的 `getMe` 探测,因此运行器在第一次 `getUpdates` 之前不需要第二次 `getMe`。 - - 如果 `deleteWebhook` 在轮询启动期间因瞬时网络错误失败,OpenClaw 会继续进入长轮询,而不是再发起一次预轮询控制平面调用。仍处于活动状态的 webhook 会表现为 `getUpdates` 冲突;随后 OpenClaw 会重建 Telegram 传输并重试 webhook 清理。 - - 如果 Telegram 套接字按较短的固定周期回收,请检查是否存在过低的 `channels.telegram.timeoutSeconds`;机器人客户端会将低于出站和 `getUpdates` 请求保护值的配置值钳制到保护值以上,但旧版本在该值低于这些保护值时可能会中止每次轮询或回复。 - - 如果日志包含 `Polling stall detected`,OpenClaw 默认会在 120 秒没有完成长轮询存活信号后重启轮询并重建 Telegram 传输。 - - 当运行中的轮询账户在启动宽限期后未完成 `getUpdates`、运行中的 webhook 账户在启动宽限期后未完成 `setWebhook`,或最近一次成功的轮询传输活动已过期时,`openclaw channels status --probe` 和 `openclaw doctor` 会发出警告。 - - 仅当长时间运行的 `getUpdates` 调用健康、但你的主机仍报告误报的轮询停滞重启时,才增大 `channels.telegram.pollingStallThresholdMs`。持续停滞通常指向主机与 `api.telegram.org` 之间的代理、DNS、IPv6 或 TLS 出站问题。 - - Telegram 也会遵循 Bot API 传输的进程代理环境,包括 `HTTP_PROXY`、`HTTPS_PROXY`、`ALL_PROXY` 及其小写变体。`NO_PROXY` / `no_proxy` 仍可绕过 `api.telegram.org`。 - - 如果服务环境中通过 `OPENCLAW_PROXY_URL` 配置了 OpenClaw 托管代理,并且不存在标准代理环境,Telegram 也会将该 URL 用于 Bot API 传输。 - - 在直接出站/TLS 不稳定的 VPS 主机上,通过 `channels.telegram.proxy` 路由 Telegram API 调用: + - Node 22+ + 自定义 fetch/proxy 可能会在 AbortSignal 类型不匹配时触发立即中止行为。 + - 某些主机会先将 `api.telegram.org` 解析为 IPv6;损坏的 IPv6 出站可能导致间歇性 Telegram API 失败。 + - 如果日志包含 `TypeError: fetch failed` 或 `Network request for 'getUpdates' failed!`,OpenClaw 现在会将这些错误作为可恢复的网络错误重试。 + - 在轮询启动期间,OpenClaw 会为 grammY 复用成功的启动 `getMe` 探测,因此运行器在第一次 `getUpdates` 之前不需要第二次 `getMe`。 + - 如果 `deleteWebhook` 在轮询启动期间因瞬态网络错误失败,OpenClaw 会继续进入长轮询,而不是再发起一次轮询前的控制平面调用。仍处于活动状态的 webhook 会表现为 `getUpdates` 冲突;随后 OpenClaw 会重建 Telegram 传输并重试 webhook 清理。 + - 如果 Telegram 套接字按较短的固定周期回收,请检查是否设置了较低的 `channels.telegram.timeoutSeconds`;机器人客户端会将低于出站和 `getUpdates` 请求保护值的配置值钳制到保护值以上,但旧版本在该值低于这些保护值时可能会中止每次轮询或回复。 + - 如果日志包含 `Polling stall detected`,默认情况下,OpenClaw 会在 120 秒内没有完成的长轮询存活信号后重启轮询并重建 Telegram 传输。 + - 当正在运行的轮询账号在启动宽限期后尚未完成 `getUpdates`、正在运行的 webhook 账号在启动宽限期后尚未完成 `setWebhook`,或最后一次成功的轮询传输活动已过期时,`openclaw channels status --probe` 和 `openclaw doctor` 会发出警告。 + - 仅当长时间运行的 `getUpdates` 调用健康,但你的主机仍报告错误的轮询停滞重启时,才增加 `channels.telegram.pollingStallThresholdMs`。持续停滞通常指向主机与 `api.telegram.org` 之间的代理、DNS、IPv6 或 TLS 出站问题。 + - Telegram 也会遵循用于 Bot API 传输的进程代理环境变量,包括 `HTTP_PROXY`、`HTTPS_PROXY`、`ALL_PROXY` 及其小写变体。`NO_PROXY` / `no_proxy` 仍可绕过 `api.telegram.org`。 + - 如果在服务环境中通过 `OPENCLAW_PROXY_URL` 配置了 OpenClaw 托管代理,并且不存在标准代理环境变量,Telegram 也会将该 URL 用于 Bot API 传输。 + - 在直连出站/TLS 不稳定的 VPS 主机上,通过 `channels.telegram.proxy` 路由 Telegram API 调用: ```yaml channels: @@ -930,8 +929,8 @@ channels: proxy: socks5://:@proxy-host:1080 ``` - - Node 22+ 默认使用 `autoSelectFamily=true`(WSL2 除外)。Telegram DNS 结果顺序依次遵循 `OPENCLAW_TELEGRAM_DNS_RESULT_ORDER`、`channels.telegram.network.dnsResultOrder`、进程默认值(例如 `NODE_OPTIONS=--dns-result-order=ipv4first`);如果都不适用,Node 22+ 会回退到 `ipv4first`。 - - 如果你的主机是 WSL2,或明确在仅 IPv4 行为下工作得更好,请强制选择地址族: + - Node 22+ 默认使用 `autoSelectFamily=true`(WSL2 除外)。Telegram DNS 结果顺序依次遵循 `OPENCLAW_TELEGRAM_DNS_RESULT_ORDER`、`channels.telegram.network.dnsResultOrder`,然后是进程默认值,例如 `NODE_OPTIONS=--dns-result-order=ipv4first`;如果都不适用,Node 22+ 会回退到 `ipv4first`。 + - 如果你的主机是 WSL2,或明确在仅 IPv4 行为下工作更好,请强制选择地址族: ```yaml channels: @@ -940,7 +939,7 @@ channels: autoSelectFamily: false ``` - - 默认已允许 Telegram 媒体下载使用 RFC 2544 基准测试范围应答(`198.18.0.0/15`)。如果可信的 fake-IP 或透明代理在媒体下载期间将 `api.telegram.org` 重写为其他私有/内部/特殊用途地址,你可以选择启用仅限 Telegram 的绕过: + - 默认情况下,Telegram 媒体下载已允许 RFC 2544 基准测试范围答案(`198.18.0.0/15`)。如果可信的 fake-IP 或透明代理在媒体下载期间将 `api.telegram.org` 重写为其他私有/内部/特殊用途地址,你可以选择启用仅限 Telegram 的绕过: ```yaml channels: @@ -949,22 +948,19 @@ channels: dangerouslyAllowPrivateNetwork: true ``` - - 同一选择启用项也可按账户配置在 + - 同一个可选启用项也可在每个账号级别使用: `channels.telegram.accounts..network.dangerouslyAllowPrivateNetwork`。 - - 如果你的代理将 Telegram 媒体主机解析为 `198.18.x.x`,请先保持 - 危险标志关闭。Telegram 媒体默认已允许 RFC 2544 - 基准测试范围。 + - 如果你的代理将 Telegram 媒体主机解析为 `198.18.x.x`,请先保持该危险标志关闭。Telegram 媒体默认已经允许 RFC 2544 基准测试范围。 - `channels.telegram.network.dangerouslyAllowPrivateNetwork` 会削弱 Telegram - 媒体 SSRF 防护。仅在可信的运营者控制代理环境中使用,例如 Clash、Mihomo 或 Surge fake-IP 路由,并且它们会合成 RFC 2544 基准测试范围之外的私有或特殊用途应答。对于普通公网 Telegram 访问,请保持关闭。 + `channels.telegram.network.dangerouslyAllowPrivateNetwork` 会削弱 Telegram 媒体 SSRF 防护。仅在可信、由操作方控制的代理环境中使用它,例如 Clash、Mihomo 或 Surge fake-IP 路由,并且这些环境会合成 RFC 2544 基准测试范围之外的私有或特殊用途答案。对于普通公共互联网 Telegram 访问,请保持关闭。 - 环境覆盖(临时): - `OPENCLAW_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY=1` - `OPENCLAW_TELEGRAM_ENABLE_AUTO_SELECT_FAMILY=1` - `OPENCLAW_TELEGRAM_DNS_RESULT_ORDER=ipv4first` - - 验证 DNS 应答: + - 验证 DNS 答案: ```bash dig +short api.telegram.org A @@ -984,7 +980,7 @@ dig +short api.telegram.org AAAA - 启动/身份验证:`enabled`、`botToken`、`tokenFile`、`accounts.*`(`tokenFile` 必须指向常规文件;符号链接会被拒绝) - 访问控制:`dmPolicy`、`allowFrom`、`groupPolicy`、`groupAllowFrom`、`groups`、`groups.*.topics.*`、顶层 `bindings[]`(`type: "acp"`) -- 执行审批:`execApprovals`、`accounts.*.execApprovals` +- exec 批准:`execApprovals`、`accounts.*.execApprovals` - 命令/菜单:`commands.native`、`commands.nativeSkills`、`customCommands` - 线程/回复:`replyToMode`、`dm.threadReplies`、`direct.*.threadReplies` - 流式传输:`streaming`(预览)、`streaming.preview.toolProgress`、`blockStreaming` @@ -993,14 +989,14 @@ dig +short api.telegram.org AAAA - 自定义 API 根:`apiRoot`(仅 Bot API 根;不要包含 `/bot`) - webhook:`webhookUrl`、`webhookSecret`、`webhookPath`、`webhookHost` - 操作/能力:`capabilities.inlineButtons`、`actions.sendMessage|editMessage|deleteMessage|reactions|sticker` -- 表情回应:`reactionNotifications`、`reactionLevel` +- reaction:`reactionNotifications`、`reactionLevel` - 错误:`errorPolicy`、`errorCooldownMs` -- 写入/历史记录:`configWrites`、`historyLimit`、`dmHistoryLimit`、`dms.*.historyLimit` +- 写入/历史:`configWrites`、`historyLimit`、`dmHistoryLimit`、`dms.*.historyLimit` -多账户优先级:当配置了两个或更多账户 ID 时,设置 `channels.telegram.defaultAccount`(或包含 `channels.telegram.accounts.default`)以明确默认路由。否则 OpenClaw 会回退到第一个规范化账户 ID,且 `openclaw doctor` 会发出警告。命名账户会继承 `channels.telegram.allowFrom` / `groupAllowFrom`,但不会继承 `accounts.default.*` 值。 +多账号优先级:当配置了两个或更多账号 ID 时,请设置 `channels.telegram.defaultAccount`(或包含 `channels.telegram.accounts.default`)以明确默认路由。否则 OpenClaw 会回退到第一个规范化后的账号 ID,并且 `openclaw doctor` 会发出警告。命名账号会继承 `channels.telegram.allowFrom` / `groupAllowFrom`,但不会继承 `accounts.default.*` 值。 ## 相关 diff --git a/docs/zh-CN/ci.md b/docs/zh-CN/ci.md index 1a77f499e..5c4b5966d 100644 --- a/docs/zh-CN/ci.md +++ b/docs/zh-CN/ci.md @@ -1,94 +1,94 @@ --- read_when: - 你需要了解为什么某个 CI 作业运行了或没有运行 - - 你正在调试一个失败的 GitHub Actions 检查 - - 你正在协调一次发布验证的运行或重新运行 + - 你正在调试一项失败的 GitHub Actions 检查 + - 你正在协调发布验证的运行或重新运行 - 你正在更改 ClawSweeper 调度或 GitHub 活动转发 -summary: CI 作业图、作用域门禁、发布总括任务和本地等价命令 +summary: CI 作业图、范围门控、发布总括任务和本地命令等价项 title: CI 流水线 x-i18n: - generated_at: "2026-05-05T01:33:54Z" + generated_at: "2026-05-05T04:27:03Z" model: gpt-5.5 provider: openai - source_hash: 16771940889d1fa944a5bfafe1152a033d96625595a2d89ff2cedbd3022cee66 + source_hash: 31fe6704e18f9efc519a1a73fc3aa8ae3909d6a27553874eb477e73979a94af2 source_path: ci.md workflow: 16 --- -OpenClaw CI 会在每次推送到 `main` 和每个拉取请求上运行。`preflight` 作业会分类差异,并在只有无关区域发生变更时关闭昂贵的流水线。手动 `workflow_dispatch` 运行会有意绕过智能作用域划分,并为发布候选版本和广泛验证展开完整图。Android 流水线通过 `include_android` 保持可选启用。仅发布阶段的插件覆盖位于单独的 [`Plugin Prerelease`](#plugin-prerelease) 工作流中,并且只会从 [`Full Release Validation`](#full-release-validation) 或显式手动分发运行。 +OpenClaw CI 在每次推送到 `main` 以及每个 pull request 上运行。`preflight` 作业会对 diff 分类,并在只有无关区域发生变更时关闭昂贵的 lane。手动 `workflow_dispatch` 运行会有意绕过智能范围限定,并为候选发布版本和广泛验证展开完整图。Android lane 通过 `include_android` 保持选择加入。仅发布使用的插件覆盖率位于单独的 [`Plugin Prerelease`](#plugin-prerelease) workflow 中,并且只会从 [`Full Release Validation`](#full-release-validation) 或显式手动 dispatch 运行。 ## 流水线概览 -| 作业 | 目的 | 运行时机 | +| 作业 | 用途 | 运行时机 | | -------------------------------- | --------------------------------------------------------------------------------------------------------- | ---------------------------------- | -| `preflight` | 检测仅文档变更、变更作用域、变更插件,并构建 CI 清单 | 始终在非草稿推送和 PR 上运行 | -| `security-scm-fast` | 通过 `zizmor` 进行私钥检测和工作流审计 | 始终在非草稿推送和 PR 上运行 | -| `security-dependency-audit` | 针对 npm advisories 进行无依赖的生产锁文件审计 | 始终在非草稿推送和 PR 上运行 | -| `security-fast` | 快速安全作业的必需聚合项 | 始终在非草稿推送和 PR 上运行 | -| `check-dependencies` | 生产 Knip 仅依赖检查加未使用文件 allowlist 守卫 | Node 相关变更 | +| `preflight` | 检测仅文档变更、变更范围、变更插件,并构建 CI 清单 | 始终在非 draft 推送和 PR 上运行 | +| `security-scm-fast` | 通过 `zizmor` 进行私钥检测和 workflow 审计 | 始终在非 draft 推送和 PR 上运行 | +| `security-dependency-audit` | 针对 npm 公告,对 production lockfile 进行无依赖审计 | 始终在非 draft 推送和 PR 上运行 | +| `security-fast` | 快速安全作业所需的聚合项 | 始终在非 draft 推送和 PR 上运行 | +| `check-dependencies` | 仅 production Knip 依赖检查,加上未使用文件 allowlist 守卫 | Node 相关变更 | | `build-artifacts` | 构建 `dist/`、Control UI、构建产物检查,以及可复用的下游产物 | Node 相关变更 | -| `checks-fast-core` | 快速 Linux 正确性流水线,例如内置插件/插件契约/协议检查 | Node 相关变更 | -| `checks-fast-contracts-channels` | 分片的渠道契约检查,带有稳定的聚合检查结果 | Node 相关变更 | -| `checks-node-core-test` | 核心 Node 测试分片,不包括渠道、内置、契约和插件流水线 | Node 相关变更 | -| `check` | 分片的主本地门禁等价项:生产类型、lint、守卫、测试类型和严格 smoke | Node 相关变更 | +| `checks-fast-core` | 快速 Linux 正确性 lane,例如内置插件、插件契约和协议检查 | Node 相关变更 | +| `checks-fast-contracts-channels` | 分片的渠道契约检查,并提供稳定的聚合检查结果 | Node 相关变更 | +| `checks-node-core-test` | Core Node 测试分片,排除渠道、内置、契约和插件 lane | Node 相关变更 | +| `check` | 分片的主要本地 gate 等价项:production 类型、lint、守卫、测试类型和严格 smoke | Node 相关变更 | | `check-additional` | 架构、分片边界/提示词漂移、插件守卫、包边界和 Gateway 网关 watch | Node 相关变更 | | `build-smoke` | 已构建 CLI smoke 测试和启动内存 smoke | Node 相关变更 | | `checks` | 构建产物渠道测试的验证器 | Node 相关变更 | -| `checks-node-compat-node22` | Node 22 兼容性构建和 smoke 流水线 | 发布用手动 CI 分发 | -| `check-docs` | 文档格式、lint 和断链检查 | 文档已变更 | -| `skills-python` | Python 支持的 Skills 的 Ruff + pytest | Python Skill 相关变更 | -| `checks-windows` | Windows 专用进程/路径测试,以及共享运行时导入说明符回归测试 | Windows 相关变更 | -| `macos-node` | 使用共享构建产物的 macOS TypeScript 测试流水线 | macOS 相关变更 | +| `checks-node-compat-node22` | Node 22 兼容性构建和 smoke lane | 发布版手动 CI dispatch | +| `check-docs` | 文档格式化、lint 和断链检查 | 文档变更 | +| `skills-python` | Python 支撑的 Skills 的 Ruff + pytest | Python Skill 相关变更 | +| `checks-windows` | Windows 专用进程/路径测试,加上共享运行时导入 specifier 回归检查 | Windows 相关变更 | +| `macos-node` | 使用共享构建产物的 macOS TypeScript 测试 lane | macOS 相关变更 | | `macos-swift` | macOS 应用的 Swift lint、构建和测试 | macOS 相关变更 | -| `android` | 两种 flavor 的 Android 单元测试加一个 debug APK 构建 | Android 相关变更 | -| `test-performance-agent` | 受信任活动后的每日 Codex 慢测试优化 | 主 CI 成功或手动分发 | -| `openclaw-performance` | 每日/按需 Kova 运行时性能报告,包含 mock-provider、deep-profile 和 GPT 5.4 live 流水线 | 定时和手动分发 | +| `android` | 两种 flavor 的 Android 单元测试,加上一个 debug APK 构建 | Android 相关变更 | +| `test-performance-agent` | 可信活动之后的每日 Codex 慢测试优化 | 主 CI 成功或手动 dispatch | +| `openclaw-performance` | 每日/按需的 Kova 运行时性能报告,包含 mock provider、deep profile 和 GPT 5.4 live lane | 定时和手动 dispatch | -## Fail-fast 顺序 +## 快速失败顺序 -1. `preflight` 决定哪些流水线会存在。`docs-scope` 和 `changed-scope` 逻辑是此作业内的步骤,不是独立作业。 -2. `security-scm-fast`、`security-dependency-audit`、`security-fast`、`check`、`check-additional`、`check-docs` 和 `skills-python` 会快速失败,而不等待更重的产物和平台矩阵作业。 -3. `build-artifacts` 会与快速 Linux 流水线重叠运行,这样下游消费者可以在共享构建准备好后立即开始。 -4. 更重的平台和运行时流水线随后展开:`checks-fast-core`、`checks-fast-contracts-channels`、`checks-node-core-test`、`checks`、`checks-windows`、`macos-node`、`macos-swift` 和 `android`。 +1. `preflight` 决定哪些 lane 实际存在。`docs-scope` 和 `changed-scope` 逻辑是此作业内部的步骤,而不是独立作业。 +2. `security-scm-fast`、`security-dependency-audit`、`security-fast`、`check`、`check-additional`、`check-docs` 和 `skills-python` 会快速失败,无需等待更重的产物和平台矩阵作业。 +3. `build-artifacts` 与快速 Linux lane 重叠运行,使下游消费者可以在共享构建就绪后立即开始。 +4. 更重的平台和运行时 lane 随后展开:`checks-fast-core`、`checks-fast-contracts-channels`、`checks-node-core-test`、`checks`、`checks-windows`、`macos-node`、`macos-swift` 和 `android`。 -当同一个 PR 或 `main` ref 上有更新的推送落地时,GitHub 可能会将被取代的作业标记为 `cancelled`。除非同一 ref 的最新运行也失败,否则应将其视为 CI 噪声。聚合分片检查使用 `!cancelled() && always()`,因此它们仍会报告正常的分片失败,但不会在整个工作流已经被取代后继续排队。自动 CI 并发键带版本号(`CI-v7-*`),这样 GitHub 端旧队列组中的僵尸项无法无限期阻塞新的 main 运行。手动全套件运行使用 `CI-manual-v1-*`,并且不会取消正在进行的运行。 +当同一个 PR 或 `main` ref 上有更新的推送落地时,GitHub 可能会将被取代的作业标记为 `cancelled`。除非同一 ref 的最新运行也失败,否则应将其视为 CI 噪声。聚合分片检查使用 `!cancelled() && always()`,因此它们仍会报告正常的分片失败,但不会在整个 workflow 已被取代后继续排队。自动 CI 并发键带有版本号(`CI-v7-*`),因此 GitHub 侧旧队列组中的僵尸项不能无限期阻塞较新的 main 运行。手动全套件运行使用 `CI-manual-v1-*`,并且不会取消正在进行的运行。 -## 作用域和路由 +## 范围和路由 -作用域逻辑位于 `scripts/ci-changed-scope.mjs`,并由 `src/scripts/ci-changed-scope.test.ts` 中的单元测试覆盖。手动分发会跳过 changed-scope 检测,并让 preflight 清单表现得像每个受作用域约束的区域都已变更一样。 +范围逻辑位于 `scripts/ci-changed-scope.mjs`,并由 `src/scripts/ci-changed-scope.test.ts` 中的单元测试覆盖。手动 dispatch 会跳过 changed-scope 检测,并让 preflight 清单表现得像每个限定范围区域都发生了变更。 -- **CI 工作流编辑**会验证 Node CI 图和工作流 linting,但不会单独强制 Windows、Android 或 macOS 原生构建;这些平台流水线仍限定为平台源代码变更。 -- **仅 CI 路由编辑、选定的廉价核心测试 fixture 编辑,以及窄范围插件契约 helper/测试路由编辑**使用快速 Node-only 清单路径:`preflight`、security 和单个 `checks-fast-core` 任务。当变更仅限于该快速任务直接执行的路由或 helper 表面时,该路径会跳过构建产物、Node 22 兼容性、渠道契约、完整核心分片、内置插件分片和额外守卫矩阵。 -- **Windows Node 检查**限定于 Windows 专用进程/路径 wrapper、npm/pnpm/UI runner helper、包管理器配置,以及执行该流水线的 CI 工作流表面;无关源码、插件、install-smoke 和仅测试变更仍留在 Linux Node 流水线上。 +- **CI workflow 编辑**会验证 Node CI 图和 workflow lint,但其本身不会强制运行 Windows、Android 或 macOS native 构建;这些平台 lane 仍限定在平台源代码变更上。 +- **仅 CI 路由编辑、选定的廉价 core-test fixture 编辑,以及窄范围插件契约 helper/test-routing 编辑**使用快速 Node-only 清单路径:`preflight`、security 和单个 `checks-fast-core` 任务。当变更仅限于快速任务直接覆盖的路由或 helper 表面时,该路径会跳过构建产物、Node 22 兼容性、渠道契约、完整 core 分片、内置插件分片和额外守卫矩阵。 +- **Windows Node 检查**限定在 Windows 专用进程/路径 wrapper、npm/pnpm/UI runner helper、包管理器配置,以及执行该 lane 的 CI workflow 表面;无关源代码、插件、install-smoke 和仅测试变更会留在 Linux Node lane 上。 -最慢的 Node 测试族会被拆分或均衡,使每个作业保持较小规模且不过度预留 runner:渠道契约作为三个加权分片运行,核心单元 fast/support 流水线单独运行,核心运行时基础设施拆分为 state 和 process/config 分片,auto-reply 以均衡 worker 运行(reply 子树拆分为 agent-runner、dispatch 和 commands/state-routing 分片),agentic Gateway 网关/server 配置拆分到 chat/auth/model/http-plugin/runtime/startup 流水线,而不是等待构建产物。广泛的浏览器、QA、媒体和杂项插件测试使用各自专用的 Vitest 配置,而不是共享插件 catch-all。Include-pattern 分片使用 CI 分片名称记录 timing 条目,因此 `.artifacts/vitest-shard-timings.json` 可以区分整个配置和过滤后的分片。`check-additional` 将 package-boundary compile/canary 工作放在一起,并将运行时拓扑架构与 Gateway 网关 watch 覆盖分开;边界守卫列表跨四个矩阵分片条带化,每个分片并发运行选定的独立守卫并打印每项检查的 timing,包括 `pnpm prompt:snapshots:check`,这样 Codex 运行时 happy-path 提示词漂移会固定到导致它的 PR 上。Gateway 网关 watch、渠道测试和核心 support-boundary 分片会在 `dist/` 和 `dist-runtime/` 已经构建完成后,在 `build-artifacts` 内并发运行。 +最慢的 Node 测试族会被拆分或均衡,使每个作业保持较小规模而不过度预留 runner:渠道契约作为三个加权分片运行,core unit fast/support lane 单独运行,core runtime infra 在 state 和 process/config 分片之间拆分,auto-reply 作为均衡 worker 运行(reply 子树拆分为 agent-runner、dispatch 和 commands/state-routing 分片),agentic gateway/server 配置则拆分到 chat/auth/model/http-plugin/runtime/startup lane 中,而不是等待构建产物。广泛的浏览器、QA、媒体和杂项插件测试使用其专用 Vitest 配置,而不是共享插件 catch-all。Include-pattern 分片使用 CI 分片名称记录计时条目,因此 `.artifacts/vitest-shard-timings.json` 可以区分完整配置和过滤后的分片。`check-additional` 将 package-boundary compile/canary 工作保持在一起,并将运行时拓扑架构与 Gateway 网关 watch 覆盖率分开;边界守卫列表按四个矩阵分片条带化,每个分片并发运行选定的独立守卫并打印每项检查的计时,包括 `pnpm prompt:snapshots:check`,这样 Codex 运行时 happy-path 提示词漂移会被钉在造成它的 PR 上。Gateway 网关 watch、渠道测试和 core support-boundary 分片会在 `dist/` 和 `dist-runtime/` 已构建完成后,在 `build-artifacts` 内部并发运行。 -Android CI 会同时运行 `testPlayDebugUnitTest` 和 `testThirdPartyDebugUnitTest`,然后构建 Play debug APK。third-party flavor 没有单独的 source set 或 manifest;其单元测试流水线仍会使用 SMS/call-log BuildConfig 标志编译该 flavor,同时避免在每个 Android 相关推送上重复执行 debug APK 打包作业。 +Android CI 会运行 `testPlayDebugUnitTest` 和 `testThirdPartyDebugUnitTest`,随后构建 Play debug APK。third-party flavor 没有单独的 source set 或 manifest;它的单元测试 lane 仍会使用 SMS/call-log BuildConfig flag 编译该 flavor,同时避免在每次 Android 相关推送上重复执行 debug APK 打包作业。 -`check-dependencies` 分片运行 `pnpm deadcode:dependencies`(生产 Knip 仅依赖检查,固定到最新 Knip 版本,并为 `dlx` 安装禁用 pnpm 的最小发布年龄)和 `pnpm deadcode:unused-files`,后者会将 Knip 的生产未使用文件发现结果与 `scripts/deadcode-unused-files.allowlist.mjs` 进行比较。当 PR 添加新的未审查未使用文件,或留下过期 allowlist 条目时,未使用文件守卫会失败,同时保留 Knip 无法静态解析的有意动态插件、生成内容、构建、live-test 和包桥接表面。 +`check-dependencies` 分片运行 `pnpm deadcode:dependencies`(仅 production Knip 依赖检查,固定到最新 Knip 版本,并在 `dlx` 安装中禁用 pnpm 的最低发布年龄限制)和 `pnpm deadcode:unused-files`,后者会将 Knip 的 production 未使用文件发现与 `scripts/deadcode-unused-files.allowlist.mjs` 进行比较。当 PR 添加新的未经审查的未使用文件,或留下陈旧 allowlist 条目时,未使用文件守卫会失败,同时保留 Knip 无法静态解析的有意动态插件、生成内容、构建、live-test 和包 bridge 表面。 ## ClawSweeper 活动转发 -`.github/workflows/clawsweeper-dispatch.yml` 是从 OpenClaw 仓库活动到 ClawSweeper 的目标侧桥接。它不会检出或执行不受信任的拉取请求代码。该工作流会从 `CLAWSWEEPER_APP_PRIVATE_KEY` 创建 GitHub App token,然后向 `openclaw/clawsweeper` 分发紧凑的 `repository_dispatch` payload。 +`.github/workflows/clawsweeper-dispatch.yml` 是从 OpenClaw 仓库活动到 ClawSweeper 的目标侧 bridge。它不会 checkout 或执行不可信的 pull request 代码。该 workflow 会从 `CLAWSWEEPER_APP_PRIVATE_KEY` 创建 GitHub App token,然后向 `openclaw/clawsweeper` dispatch 紧凑的 `repository_dispatch` payload。 -该工作流有四条流水线: +该 workflow 有四个 lane: -- `clawsweeper_item` 用于精确的 issue 和拉取请求审查请求; -- `clawsweeper_comment` 用于 issue 评论中的显式 ClawSweeper 命令; -- `clawsweeper_commit_review` 用于 `main` 推送上的提交级审查请求; +- `clawsweeper_item` 用于精确 issue 和 pull request review 请求; +- `clawsweeper_comment` 用于 issue comment 中显式的 ClawSweeper 命令; +- `clawsweeper_commit_review` 用于 `main` 推送上的 commit 级 review 请求; - `github_activity` 用于 ClawSweeper agent 可能检查的一般 GitHub 活动。 -`github_activity` 流水线仅转发规范化元数据:事件类型、操作、actor、仓库、条目编号、URL、标题、状态,以及存在评论或审查时的短摘录。它有意避免转发完整 webhook body。`openclaw/clawsweeper` 中的接收工作流是 `.github/workflows/github-activity.yml`,它会将规范化事件发布到 OpenClaw Gateway 网关 hook,供 ClawSweeper agent 使用。 +`github_activity` lane 只转发规范化元数据:事件类型、action、actor、仓库、item 编号、URL、标题、状态,以及存在 comment 或 review 时的简短摘录。它有意避免转发完整 webhook body。`openclaw/clawsweeper` 中接收方 workflow 是 `.github/workflows/github-activity.yml`,它会将规范化事件发布到 ClawSweeper agent 的 OpenClaw Gateway 网关 hook。 -一般活动是观察,而不是默认投递。ClawSweeper agent 会在其提示词中接收 Discord 目标,并且只有当事件令人意外、可操作、有风险或对运营有用时,才应发布到 `#clawsweeper`。常规打开、编辑、bot 变动、重复 webhook 噪声和正常审查流量都应产生 `NO_REPLY`。 +一般活动是观察,而不是默认投递。ClawSweeper agent 会在其提示词中接收 Discord 目标,并且只有在事件令人意外、可行动、有风险或具有运维用途时才应发布到 `#clawsweeper`。常规打开、编辑、bot churn、重复 webhook 噪声和正常 review 流量应产生 `NO_REPLY`。 -在这条路径中,始终将 GitHub 标题、评论、正文、审查文本、分支名称和提交消息视为不受信任的数据。它们是摘要和分流的输入,而不是工作流或 agent 运行时的指令。 +在整个路径中,将 GitHub 标题、comment、body、review 文本、分支名称和 commit message 视为不可信数据。它们是摘要和分流的输入,不是 workflow 或 agent 运行时的指令。 -## 手动分发 +## 手动 dispatch -手动 CI 触发会运行与普通 CI 相同的作业图,但会强制启用每个非 Android 范围通道:Linux Node 分片、内置插件分片、渠道契约、Node 22 兼容性、`check`、`check-additional`、构建冒烟、文档检查、Python Skills、Windows、macOS 和 Control UI i18n。独立的手动 CI 触发仅在 `include_android=true` 时运行 Android;完整发布总括流程通过传入 `include_android=true` 启用 Android。插件预发布静态检查、仅发布使用的 `agentic-plugins` 分片、完整插件批量扫描以及插件预发布 Docker 通道均排除在 CI 之外。Docker 预发布套件只会在 `Full Release Validation` 触发单独的 `Plugin Prerelease` 工作流并启用发布验证门禁时运行。 +手动 CI 调度运行与普通 CI 相同的作业图,但会强制开启所有非 Android 作用域的 lane:Linux Node 分片、内置插件分片、渠道合约、Node 22 兼容性、`check`、`check-additional`、构建 smoke、文档检查、Python Skills、Windows、macOS 和 Control UI i18n。独立的手动 CI 调度仅在 `include_android=true` 时运行 Android;完整发布总控通过传入 `include_android=true` 启用 Android。插件预发布静态检查、仅发布用的 `agentic-plugins` 分片、完整扩展批量 sweep,以及插件预发布 Docker lane 均不包含在 CI 中。Docker 预发布套件仅在 `Full Release Validation` 以启用发布验证 gate 的方式调度单独的 `Plugin Prerelease` 工作流时运行。 -手动运行使用唯一的并发组,因此候选发布版本的完整套件不会被同一 ref 上的其他 push 或 PR 运行取消。可选的 `target_ref` 输入允许受信任的调用方在使用所选触发 ref 中工作流文件的同时,针对某个分支、标签或完整提交 SHA 运行该作业图。 +手动运行使用唯一的并发组,因此候选发布版本的完整套件不会被同一 ref 上的其他 push 或 PR 运行取消。可选的 `target_ref` 输入允许受信任调用方在使用所选调度 ref 中的工作流文件时,针对分支、标签或完整提交 SHA 运行该作业图。 ```bash gh workflow run ci.yml --ref release/YYYY.M.D @@ -100,10 +100,10 @@ gh workflow run full-release-validation.yml --ref main -f ref= | 运行器 | 作业 | | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `ubuntu-24.04` | `preflight`、快速安全作业和聚合(`security-scm-fast`、`security-dependency-audit`、`security-fast`)、快速协议/契约/内置检查、分片渠道契约检查、除 lint 之外的 `check` 分片、`check-additional` 分片和聚合、Node 测试聚合验证器、文档检查、Python Skills、workflow-sanity、labeler、auto-response;install-smoke preflight 也使用 GitHub 托管的 Ubuntu,这样 Blacksmith 矩阵可以更早排队 | -| `blacksmith-4vcpu-ubuntu-2404` | `CodeQL Critical Quality`、较低权重的插件分片、`checks-fast-core`、`checks-node-compat-node22`、`check-prod-types` 和 `check-test-types` | +| `ubuntu-24.04` | `preflight`,快速安全作业和聚合(`security-scm-fast`、`security-dependency-audit`、`security-fast`),快速协议/合约/内置检查,分片渠道合约检查,除 lint 外的 `check` 分片,`check-additional` 分片和聚合,Node 测试聚合验证器,文档检查,Python Skills,workflow-sanity,labeler,auto-response;install-smoke preflight 也使用 GitHub 托管的 Ubuntu,以便 Blacksmith 矩阵可以更早排队 | +| `blacksmith-4vcpu-ubuntu-2404` | `CodeQL Critical Quality`、较低权重的扩展分片、`checks-fast-core`、`checks-node-compat-node22`、`check-prod-types` 和 `check-test-types` | | `blacksmith-8vcpu-ubuntu-2404` | `build-artifacts`、build-smoke、Linux Node 测试分片、内置插件测试分片、`android` | -| `blacksmith-16vcpu-ubuntu-2404` | `check-lint`(对 CPU 足够敏感,以至于 8 vCPU 的成本高于节省的时间);install-smoke Docker 构建(32-vCPU 排队时间的成本高于节省的时间) | +| `blacksmith-16vcpu-ubuntu-2404` | `check-lint`(对 CPU 足够敏感,8 vCPU 的成本高于节省的时间);install-smoke Docker 构建(32 vCPU 的排队时间成本高于节省的时间) | | `blacksmith-16vcpu-windows-2025` | `checks-windows` | | `blacksmith-6vcpu-macos-latest` | `openclaw/openclaw` 上的 `macos-node`;fork 回退到 `macos-latest` | | `blacksmith-12vcpu-macos-latest` | `openclaw/openclaw` 上的 `macos-swift`;fork 回退到 `macos-latest` | @@ -137,7 +137,7 @@ pnpm perf:kova:summary --report .artifacts/kova/reports/mock-provider/report.jso ## OpenClaw 性能 -`OpenClaw Performance` 是产品/运行时性能工作流。它每天在 `main` 上运行,也可以手动触发: +`OpenClaw Performance` 是产品/运行时性能工作流。它每天在 `main` 上运行,也可以手动调度: ```bash gh workflow run openclaw-performance.yml --ref main -f profile=diagnostic -f repeat=3 @@ -145,25 +145,25 @@ gh workflow run openclaw-performance.yml --ref main -f profile=smoke -f repeat=1 gh workflow run openclaw-performance.yml --ref main -f target_ref=v2026.5.2 -f profile=diagnostic -f repeat=3 ``` -手动触发通常会对工作流 ref 进行基准测试。设置 `target_ref` 可使用当前工作流实现对发布标签或其他分支进行基准测试。已发布报告路径和 latest 指针按被测试 ref 编排,每个 `index.md` 都会记录被测试的 ref/SHA、工作流 ref/SHA、Kova ref、profile、通道认证模式、模型、重复次数和场景过滤器。 +手动调度通常会对工作流 ref 进行基准测试。设置 `target_ref` 可使用当前工作流实现对发布标签或其他分支进行基准测试。已发布的报告路径和 latest 指针按被测试的 ref 编码,每个 `index.md` 都记录被测试的 ref/SHA、工作流 ref/SHA、Kova ref、profile、lane 认证模式、模型、重复次数和场景过滤器。 -该工作流会从固定版本安装 OCM,并从 `openclaw/Kova` 的固定 `kova_ref` 输入安装 Kova,然后运行三个通道: +该工作流从固定发布版本安装 OCM,并从 `openclaw/Kova` 的固定 `kova_ref` 输入安装 Kova,然后运行三个 lane: -- `mock-provider`:Kova 诊断场景,针对使用确定性伪 OpenAI 兼容认证的本地构建运行时。 -- `mock-deep-profile`:针对启动、Gateway 网关和智能体轮次热点的 CPU/堆/跟踪性能分析。 -- `live-gpt54`:一次真实的 OpenAI `openai/gpt-5.4` 智能体轮次;当 `OPENAI_API_KEY` 不可用时跳过。 +- `mock-provider`:使用确定性的伪 OpenAI 兼容认证,针对本地构建运行时运行 Kova 诊断场景。 +- `mock-deep-profile`:针对启动、Gateway 网关和智能体轮次热点进行 CPU/堆/trace profiling。 +- `live-gpt54`:真实的 OpenAI `openai/gpt-5.4` 智能体轮次,在 `OPENAI_API_KEY` 不可用时跳过。 -mock-provider 通道还会在 Kova 通过后运行 OpenClaw 原生源码探测:默认、hook 和 50 插件启动场景下的 Gateway 网关启动时间和内存;重复的 mock-OpenAI `channel-chat-baseline` hello 循环;以及针对已启动 Gateway 网关的 CLI 启动命令。源码探测 Markdown 摘要位于报告包中的 `source/index.md`,原始 JSON 放在旁边。 +mock-provider lane 还会在 Kova 通过后运行 OpenClaw 原生源码 probe:覆盖默认、hook 和 50 插件启动场景下的 Gateway 网关启动时间和内存;重复的模拟 OpenAI `channel-chat-baseline` hello 循环;以及针对已启动 Gateway 网关的 CLI 启动命令。源码 probe 的 Markdown 摘要位于报告包中的 `source/index.md`,旁边有原始 JSON。 -每个通道都会上传 GitHub 构件。配置 `CLAWGRIT_REPORTS_TOKEN` 后,该工作流还会将 `report.json`、`report.md`、包、`index.md` 和源码探测构件提交到 `openclaw/clawgrit-reports`,路径为 `openclaw-performance//-//`。当前被测试 ref 指针会写入为 `openclaw-performance//latest-.json`。 +每个 lane 都会上传 GitHub artifacts。配置 `CLAWGRIT_REPORTS_TOKEN` 后,工作流还会将 `report.json`、`report.md`、包、`index.md` 和源码 probe artifacts 提交到 `openclaw/clawgrit-reports` 的 `openclaw-performance//-//` 下。当前被测试 ref 的指针会写为 `openclaw-performance//latest-.json`。 ## 完整发布验证 -`Full Release Validation` 是用于“发布前运行所有内容”的手动总括工作流。它接受分支、标签或完整提交 SHA,使用该目标触发手动 `CI` 工作流,触发 `Plugin Prerelease` 以提供仅发布使用的插件/包/静态/Docker 证明,并触发 `OpenClaw Release Checks` 以执行安装冒烟、包验收、跨 OS 包检查、QA Lab parity、Matrix 和 Telegram 通道。稳定版/默认运行会把完整的 live/E2E 和 Docker 发布路径覆盖保留在 `run_release_soak=true` 之后;`release_profile=full` 会强制启用该 soak 覆盖,因此广泛的 advisory 验证仍然保持广泛。使用 `rerun_group=all` 和 `release_profile=full` 时,它还会针对来自 release checks 的 `release-package-under-test` 构件运行 `NPM Telegram Beta E2E`。发布后,传入 `npm_telegram_package_spec` 可针对已发布的 npm 包重新运行同一个 Telegram 包通道。 +`Full Release Validation` 是用于“发布前运行所有内容”的手动总控工作流。它接受分支、标签或完整提交 SHA,使用该目标调度手动 `CI` 工作流,调度 `Plugin Prerelease` 以提供仅发布用的插件/包/静态/Docker 证明,并调度 `OpenClaw Release Checks` 以运行安装 smoke、包验收、跨 OS 包检查、QA Lab parity、Matrix 和 Telegram lane。稳定版/默认运行会将详尽的 live/E2E 和 Docker 发布路径覆盖保留在 `run_release_soak=true` 后面;`release_profile=full` 会强制开启该 soak 覆盖,以便广泛的 advisory 验证保持广泛覆盖。使用 `rerun_group=all` 和 `release_profile=full` 时,它还会针对 release checks 生成的 `release-package-under-test` artifact 运行 `NPM Telegram Beta E2E`。发布后,传入 `npm_telegram_package_spec` 可针对已发布的 npm 包重新运行相同的 Telegram 包 lane。 -请参阅[完整发布验证](/zh-CN/reference/full-release-validation),了解阶段矩阵、确切工作流作业名称、profile 差异、构件和定向重运行句柄。 +请参阅[完整发布验证](/zh-CN/reference/full-release-validation),了解阶段矩阵、确切的工作流作业名称、profile 差异、artifacts,以及聚焦重跑句柄。 -`OpenClaw Release Publish` 是手动的变更型发布工作流。发布标签存在且 OpenClaw npm preflight 成功后,从 `release/YYYY.M.D` 或 `main` 触发它。它会验证 `pnpm plugins:sync:check`,为所有可发布插件包触发 `Plugin NPM Release`,为同一发布 SHA 触发 `Plugin ClawHub Release`,然后才会使用保存的 `preflight_run_id` 触发 `OpenClaw NPM Release`。 +`OpenClaw Release Publish` 是会产生变更的手动发布工作流。请在发布标签存在且 OpenClaw npm preflight 已成功后,从 `release/YYYY.M.D` 或 `main` 调度它。它会验证 `pnpm plugins:sync:check`,为所有可发布插件包调度 `Plugin NPM Release`,为同一发布 SHA 调度 `Plugin ClawHub Release`,然后才使用保存的 `preflight_run_id` 调度 `OpenClaw NPM Release`。 ```bash gh workflow run openclaw-release-publish.yml \ @@ -173,35 +173,35 @@ gh workflow run openclaw-release-publish.yml \ -f npm_dist_tag=beta ``` -若要在快速移动的分支上提供固定提交证明,请使用辅助命令,而不是 `gh workflow run ... --ref main -f ref=`: +对于快速移动分支上的固定提交证明,请使用 helper,而不是 `gh workflow run ... --ref main -f ref=`: ```bash pnpm ci:full-release --sha ``` -GitHub 工作流触发 ref 必须是分支或标签,不能是原始提交 SHA。该辅助命令会在目标 SHA 处推送一个临时 `release-ci/-...` 分支,从该固定 ref 触发 `Full Release Validation`,验证每个子工作流的 `headSha` 都与目标匹配,并在运行完成时删除临时分支。如果任何子工作流运行在不同的 SHA 上,总括验证器也会失败。 +GitHub 工作流调度 ref 必须是分支或标签,不能是原始提交 SHA。该 helper 会在目标 SHA 上推送一个临时 `release-ci/-...` 分支,从该固定 ref 调度 `Full Release Validation`,验证每个子工作流的 `headSha` 都与目标匹配,并在运行完成后删除临时分支。如果任何子工作流在不同 SHA 上运行,总控验证器也会失败。 -`release_profile` 控制传递给发布检查的实时/提供商覆盖范围。手动发布工作流默认使用 `stable`;只有在你有意需要宽泛的 advisory provider/media 矩阵时才使用 `full`。`run_release_soak` 控制 stable/default 发布检查是否运行详尽的实时/E2E 和 Docker 发布路径 soak;`full` 会强制启用 soak。 +`release_profile` 控制传入发布检查的实时/提供商覆盖范围。手动发布工作流默认使用 `stable`;只有当你有意需要广泛的 advisory 提供商/媒体矩阵时,才使用 `full`。`run_release_soak` 控制 stable/default 发布检查是否运行详尽的实时/E2E 和 Docker 发布路径 soak;`full` 会强制启用 soak。 -- `minimum` 保留最快的 OpenAI/core 发布关键通道。 -- `stable` 添加 stable provider/backend 集合。 -- `full` 运行宽泛的 advisory provider/media 矩阵。 +- `minimum` 保留最快的 OpenAI/核心发布关键通道。 +- `stable` 添加 stable 提供商/后端集合。 +- `full` 运行广泛的 advisory 提供商/媒体矩阵。 -总控流程会记录已调度的子运行 ID,最终的 `Verify full validation` 作业会重新检查当前子运行结论,并为每个子运行追加最慢作业表。如果某个子工作流被重新运行并转为绿色,只需重新运行父级 verifier 作业,以刷新总控结果和耗时摘要。 +总控工作流会记录已调度的子运行 ID,最终的 `Verify full validation` 作业会重新检查当前子运行结论,并为每个子运行追加最慢作业表。如果某个子工作流被重新运行并转为绿色,只需重新运行父级 verifier 作业,即可刷新总控结果和耗时摘要。 -对于恢复,`Full Release Validation` 和 `OpenClaw Release Checks` 都接受 `rerun_group`。发布候选版本使用 `all`;仅正常 full CI 子项使用 `ci`;仅插件预发布子项使用 `plugin-prerelease`;每个发布子项使用 `release-checks`;也可以在总控流程上使用更窄的分组:`install-smoke`、`cross-os`、`live-e2e`、`package`、`qa`、`qa-parity`、`qa-live` 或 `npm-telegram`。这样可以在完成聚焦修复后,将失败发布环境的重跑范围控制住。对于单个失败的 cross-OS 通道,将 `rerun_group=cross-os` 与 `cross_os_suite_filter` 结合使用,例如 `windows/packaged-upgrade`;长时间运行的 cross-OS 命令会输出 heartbeat 行,packaged-upgrade 摘要会包含各阶段耗时。QA release-check 通道是 advisory,因此仅 QA 失败会发出警告,但不会阻塞 release-check verifier。 +对于恢复,`Full Release Validation` 和 `OpenClaw Release Checks` 都接受 `rerun_group`。发布候选版本使用 `all`,仅普通完整 CI 子项使用 `ci`,仅插件预发布子项使用 `plugin-prerelease`,每个发布子项使用 `release-checks`,或在总控工作流上使用更窄的组:`install-smoke`、`cross-os`、`live-e2e`、`package`、`qa`、`qa-parity`、`qa-live` 或 `npm-telegram`。这样可以在做出聚焦修复后,将失败发布盒子的重新运行范围保持有界。对于单个失败的跨 OS 通道,将 `rerun_group=cross-os` 与 `cross_os_suite_filter` 组合使用,例如 `windows/packaged-upgrade`;长时间运行的跨 OS 命令会发出 heartbeat 行,packaged-upgrade 摘要会包含每阶段耗时。QA 发布检查通道是 advisory,因此仅 QA 失败会发出警告,但不会阻止发布检查 verifier。 -`OpenClaw Release Checks` 使用受信任的工作流 ref 将选定 ref 一次解析为 `release-package-under-test` tarball,然后将该 artifact 传递给 cross-OS 检查和包验收,以及在运行 soak 覆盖时传递给 live/E2E 发布路径 Docker 工作流。这样可以让各个发布环境中的包字节保持一致,并避免在多个子作业中重复打包同一个候选版本。 +`OpenClaw Release Checks` 使用受信任的工作流 ref,将所选 ref 一次解析为 `release-package-under-test` tarball,然后把该 artifact 传给跨 OS 检查和软件包验收,以及在运行 soak 覆盖时传给实时/E2E 发布路径 Docker 工作流。这样可以让发布盒子之间的软件包字节保持一致,并避免在多个子作业中重新打包同一个候选版本。 -针对 `ref=main` 和 `rerun_group=all` 的重复 `Full Release Validation` 运行会取代较旧的总控流程。当父级被取消时,父级 monitor 会取消它已调度的任何子工作流,因此较新的 main 验证不会排在过期的两小时 release-check 运行之后。发布分支/tag 验证和聚焦重跑分组会保持 `cancel-in-progress: false`。 +`ref=main` 和 `rerun_group=all` 的重复 `Full Release Validation` 运行会取代较旧的总控工作流。当父级被取消时,父级监控器会取消它已经调度的任何子工作流,因此较新的 main 验证不会卡在陈旧的两小时发布检查运行之后。发布分支/标签验证和聚焦重新运行组会保持 `cancel-in-progress: false`。 ## 实时和 E2E 分片 -发布 live/E2E 子项保留宽泛的原生 `pnpm test:live` 覆盖,但会通过 `scripts/test-live-shard.mjs` 以命名分片运行,而不是作为一个串行作业运行: +发布实时/E2E 子项保留广泛的原生 `pnpm test:live` 覆盖,但它通过 `scripts/test-live-shard.mjs` 以命名分片运行,而不是作为一个串行作业运行: - `native-live-src-agents` - `native-live-src-gateway-core` -- provider-filtered `native-live-src-gateway-profiles` 作业 +- 提供商过滤的 `native-live-src-gateway-profiles` 作业 - `native-live-src-gateway-backends` - `native-live-test` - `native-live-extensions-a-k` @@ -209,59 +209,59 @@ GitHub 工作流触发 ref 必须是分支或标签,不能是原始提交 SHA - `native-live-extensions-openai` - `native-live-extensions-o-z-other` - `native-live-extensions-xai` -- 拆分后的媒体音频/视频分片,以及 provider-filtered 音乐分片 +- 拆分的媒体音频/视频分片和提供商过滤的音乐分片 -这会保持相同的文件覆盖,同时让缓慢的实时提供商失败更容易重跑和诊断。聚合分片名称 `native-live-extensions-o-z`、`native-live-extensions-media` 和 `native-live-extensions-media-music` 对手动一次性重跑仍然有效。 +这样既保持相同的文件覆盖,又让缓慢的实时提供商失败更容易重新运行和诊断。聚合的 `native-live-extensions-o-z`、`native-live-extensions-media` 和 `native-live-extensions-media-music` 分片名称仍然可用于手动一次性重新运行。 -原生实时媒体分片在 `ghcr.io/openclaw/openclaw-live-media-runner:ubuntu-24.04` 中运行,该镜像由 `Live Media Runner Image` 工作流构建。该镜像预装了 `ffmpeg` 和 `ffprobe`;媒体作业只会在设置前验证这些二进制文件。将 Docker 支持的实时套件保留在普通 Blacksmith runner 上运行,因为容器作业不适合启动嵌套 Docker 测试。 +原生实时媒体分片在 `ghcr.io/openclaw/openclaw-live-media-runner:ubuntu-24.04` 中运行,该镜像由 `Live Media Runner Image` 工作流构建。该镜像预安装了 `ffmpeg` 和 `ffprobe`;媒体作业只会在设置前验证这些二进制文件。将 Docker 支持的实时套件保留在普通 Blacksmith runner 上运行——容器作业并不适合启动嵌套 Docker 测试。 -Docker 支持的实时 model/backend 分片会为每个选定提交使用一个单独共享的 `ghcr.io/openclaw/openclaw-live-test:` 镜像。实时发布工作流会构建并推送该镜像一次,然后 Docker 实时模型、按提供商分片的 Gateway 网关、CLI 后端、ACP bind 和 Codex harness 分片会以 `OPENCLAW_SKIP_DOCKER_BUILD=1` 运行。Gateway 网关 Docker 分片带有显式的脚本级 `timeout` 上限,低于工作流作业超时时间,因此卡住的容器或清理路径会快速失败,而不是耗尽整个 release-check 预算。如果这些分片独立重建完整 source Docker target,则发布运行配置有误,并会把 wall clock 浪费在重复镜像构建上。 +Docker 支持的实时模型/后端分片会为每个所选 commit 使用单独的共享 `ghcr.io/openclaw/openclaw-live-test:` 镜像。实时发布工作流会构建并推送该镜像一次,然后 Docker 实时模型、按提供商分片的 Gateway 网关、CLI 后端、ACP bind 和 Codex harness 分片会以 `OPENCLAW_SKIP_DOCKER_BUILD=1` 运行。Gateway 网关 Docker 分片带有明确的脚本级 `timeout` 上限,低于工作流作业超时,因此卡住的容器或清理路径会快速失败,而不是消耗整个发布检查预算。如果这些分片独立重新构建完整源 Docker 目标,则说明发布运行配置错误,并会在重复镜像构建上浪费实际耗时。 -## 包验收 +## 软件包验收 -当问题是“这个可安装的 OpenClaw 包作为产品是否可用?”时,使用 `Package Acceptance`。它不同于普通 CI:普通 CI 验证 source tree,而包验收会通过用户在安装或更新后使用的同一个 Docker E2E harness 来验证单个 tarball。 +当问题是“这个可安装的 OpenClaw 软件包作为产品能否工作?”时,使用 `Package Acceptance`。它不同于普通 CI:普通 CI 验证源代码树,而软件包验收会通过用户在安装或更新后实际使用的同一个 Docker E2E harness 验证单个 tarball。 ### 作业 -1. `resolve_package` 检出 `workflow_ref`,解析一个包候选,写入 `.artifacts/docker-e2e-package/openclaw-current.tgz`,写入 `.artifacts/docker-e2e-package/package-candidate.json`,将两者都作为 `package-under-test` artifact 上传,并在 GitHub step summary 中打印来源、workflow ref、package ref、版本、SHA-256 和 profile。 -2. `docker_acceptance` 使用 `ref=workflow_ref` 和 `package_artifact_name=package-under-test` 调用 `openclaw-live-and-e2e-checks-reusable.yml`。可复用工作流会下载该 artifact、验证 tarball 清单、在需要时准备 package-digest Docker 镜像,并针对该包运行选定 Docker 通道,而不是打包工作流 checkout。当一个 profile 选择多个目标 `docker_lanes` 时,可复用工作流会准备一次包和共享镜像,然后将这些通道扇出为并行的目标 Docker 作业,并带有唯一 artifact。 -3. `package_telegram` 可选调用 `NPM Telegram Beta E2E`。当 `telegram_mode` 不是 `none` 时运行;如果包验收已解析出一个包,它会安装同一个 `package-under-test` artifact;独立 Telegram 调度仍可安装已发布的 npm spec。 -4. `summary` 会在包解析、Docker 验收或可选 Telegram 通道失败时使工作流失败。 +1. `resolve_package` 检出 `workflow_ref`,解析一个软件包候选,写入 `.artifacts/docker-e2e-package/openclaw-current.tgz`,写入 `.artifacts/docker-e2e-package/package-candidate.json`,将两者作为 `package-under-test` artifact 上传,并在 GitHub 步骤摘要中打印来源、工作流 ref、软件包 ref、版本、SHA-256 和 profile。 +2. `docker_acceptance` 以 `ref=workflow_ref` 和 `package_artifact_name=package-under-test` 调用 `openclaw-live-and-e2e-checks-reusable.yml`。可复用工作流会下载该 artifact,验证 tarball inventory,在需要时准备 package-digest Docker 镜像,并针对该软件包运行所选 Docker 通道,而不是打包工作流检出内容。当某个 profile 选择多个目标 `docker_lanes` 时,可复用工作流会准备一次软件包和共享镜像,然后将这些通道扇出为并行的目标 Docker 作业,并使用唯一 artifact。 +3. `package_telegram` 可选调用 `NPM Telegram Beta E2E`。当 `telegram_mode` 不是 `none` 时运行,并且在软件包验收解析出 `package-under-test` artifact 时安装同一个 artifact;独立 Telegram 调度仍然可以安装已发布的 npm spec。 +4. 如果软件包解析、Docker 验收或可选 Telegram 通道失败,`summary` 会使工作流失败。 ### 候选来源 -- `source=npm` 只接受 `openclaw@beta`、`openclaw@latest`,或精确的 OpenClaw 发布版本,例如 `openclaw@2026.4.27-beta.2`。将它用于已发布的 prerelease/stable 验收。 -- `source=ref` 会打包一个受信任的 `package_ref` 分支、tag 或完整提交 SHA。解析器会获取 OpenClaw 分支/tag,验证选定提交可从仓库分支历史或发布 tag 访问,在 detached worktree 中安装依赖,并使用 `scripts/package-openclaw-for-docker.mjs` 打包。 -- `source=url` 会下载 HTTPS `.tgz`;`package_sha256` 必填。 -- `source=artifact` 会从 `artifact_run_id` 和 `artifact_name` 下载一个 `.tgz`;`package_sha256` 可选,但对于外部共享的 artifact 应提供。 +- `source=npm` 只接受 `openclaw@beta`、`openclaw@latest`,或精确的 OpenClaw 发布版本,例如 `openclaw@2026.4.27-beta.2`。将它用于已发布预发布版/stable 版验收。 +- `source=ref` 打包受信任的 `package_ref` 分支、标签或完整 commit SHA。解析器会获取 OpenClaw 分支/标签,验证所选 commit 可从仓库分支历史或发布标签到达,在 detached worktree 中安装依赖,并使用 `scripts/package-openclaw-for-docker.mjs` 打包。 +- `source=url` 下载 HTTPS `.tgz`;必须提供 `package_sha256`。 +- `source=artifact` 从 `artifact_run_id` 和 `artifact_name` 下载一个 `.tgz`;`package_sha256` 是可选的,但对于外部共享的 artifact 应提供。 -保持 `workflow_ref` 和 `package_ref` 分离。`workflow_ref` 是运行测试的受信任 workflow/harness 代码。`package_ref` 是在 `source=ref` 时会被打包的源提交。这让当前测试 harness 能够验证较旧的受信任源提交,而无需运行旧工作流逻辑。 +保持 `workflow_ref` 和 `package_ref` 分离。`workflow_ref` 是运行测试的受信任工作流/harness 代码。`package_ref` 是在 `source=ref` 时被打包的源 commit。这样当前测试 harness 就能验证较旧的受信任源 commit,而无需运行旧工作流逻辑。 ### 套件 profile - `smoke` — `npm-onboard-channel-agent`、`gateway-network`、`config-reload` - `package` — `npm-onboard-channel-agent`、`doctor-switch`、`update-channel-switch`、`upgrade-survivor`、`published-upgrade-survivor`、`plugins-offline`、`plugin-update` - `product` — `package` 加上 `mcp-channels`、`cron-mcp-cleanup`、`openai-web-search-minimal`、`openwebui` -- `full` — 带 OpenWebUI 的完整 Docker 发布路径 chunks +- `full` — 带 OpenWebUI 的完整 Docker 发布路径分块 - `custom` — 精确的 `docker_lanes`;当 `suite_profile=custom` 时必需 -`package` profile 使用离线插件覆盖,因此已发布包验证不会受实时 ClawHub 可用性限制。可选 Telegram 通道会在 `NPM Telegram Beta E2E` 中复用 `package-under-test` artifact,并为独立调度保留已发布 npm spec 路径。 +`package` profile 使用离线插件覆盖,因此已发布软件包验证不会受实时 ClawHub 可用性阻塞。可选 Telegram 通道会在 `NPM Telegram Beta E2E` 中复用 `package-under-test` artifact,并为独立调度保留已发布 npm spec 路径。 -有关专门的更新和插件测试策略,包括本地命令、Docker 通道、包验收输入、发布默认值和失败分诊,请参阅[更新和插件测试](/zh-CN/help/testing-updates-plugins)。 +有关专用更新和插件测试策略,包括本地命令、Docker 通道、软件包验收输入、发布默认值和失败分流,请参阅[更新和插件测试](/zh-CN/help/testing-updates-plugins)。 -发布检查会使用 `source=artifact`、准备好的发布包 artifact、`suite_profile=custom`、`docker_lanes='doctor-switch update-channel-switch upgrade-survivor published-upgrade-survivor plugins-offline plugin-update'` 和 `telegram_mode=mock-openai` 调用包验收。这样可以让包迁移、更新、陈旧插件依赖清理、已配置插件安装修复、离线插件、插件更新和 Telegram 证明都基于同一个已解析的包 tarball。设置 Full Release Validation 或 OpenClaw Release Checks 上的 `package_acceptance_package_spec`,可以针对已发布的 npm 包运行同一个矩阵,而不是针对 SHA 构建的 artifact。Cross-OS 发布检查仍覆盖 OS 特定的新手引导、安装程序和平台行为;包/更新产品验证应从包验收开始。`published-upgrade-survivor` Docker 通道会在阻塞发布路径中为每次运行验证一个已发布包基线。在包验收中,解析出的 `package-under-test` tarball 始终是候选版本,而 `published_upgrade_survivor_baseline` 会选择 fallback 已发布基线,默认值为 `openclaw@latest`;失败通道重跑命令会保留该基线。带有 `run_release_soak=true` 或 `release_profile=full` 的 Full Release Validation 会设置 `published_upgrade_survivor_baselines=all-since-2026.4.23` 和 `published_upgrade_survivor_scenarios=reported-issues`,以扩展覆盖从 `2026.4.23` 到 `latest` 的每个 stable npm release,以及面向问题的 fixtures,涵盖 Feishu 配置、保留的 bootstrap/persona 文件、已配置的 OpenClaw 插件安装、波浪号日志路径和陈旧的 legacy 插件依赖根。单独的 `Update Migration` 工作流在问题是详尽的已发布更新清理,而不是普通 Full Release CI 覆盖范围时,会使用 `update-migration` Docker 通道以及 `all-since-2026.4.23` 和 `plugin-deps-cleanup`。本地聚合运行可以通过 `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPECS` 传递精确包 spec;也可以通过 `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC` 保留单个通道,例如 `openclaw@2026.4.15`;或者设置 `OPENCLAW_UPGRADE_SURVIVOR_SCENARIOS` 以运行场景矩阵。已发布通道会使用内置的 `openclaw config set` 命令 recipe 配置基线,在 `summary.json` 中记录 recipe 步骤,并在 Gateway 网关启动后探测 `/healthz`、`/readyz` 以及 RPC status。Windows packaged 和 installer fresh 通道还会验证已安装包能够从原始绝对 Windows 路径导入 browser-control override。OpenAI cross-OS agent-turn smoke 在已设置时默认使用 `OPENCLAW_CROSS_OS_OPENAI_MODEL`,否则使用 `openai/gpt-5.4`,因此安装和 Gateway 网关证明会保留在 GPT-5 测试模型上,同时避免 GPT-4.x 默认值。 +发布检查会使用 `source=artifact`、准备好的发布软件包 artifact、`suite_profile=custom`、`docker_lanes='doctor-switch update-channel-switch upgrade-survivor published-upgrade-survivor plugins-offline plugin-update'` 和 `telegram_mode=mock-openai` 调用软件包验收。这样可以在同一个已解析的软件包 tarball 上完成软件包迁移、更新、陈旧插件依赖清理、已配置插件安装修复、离线插件、插件更新和 Telegram 证明。设置 Full Release Validation 或 OpenClaw Release Checks 上的 `package_acceptance_package_spec`,即可针对已发布的 npm 软件包运行同一矩阵,而不是针对按 SHA 构建的 artifact。跨 OS 发布检查仍会覆盖特定 OS 的新手引导、安装器和平台行为;软件包/更新产品验证应从软件包验收开始。`published-upgrade-survivor` Docker 通道会在阻塞发布路径中为每次运行验证一个已发布软件包基线。在软件包验收中,已解析的 `package-under-test` tarball 始终是候选版本,`published_upgrade_survivor_baseline` 选择 fallback 已发布基线,默认值为 `openclaw@latest`;失败通道重新运行命令会保留该基线。带有 `run_release_soak=true` 或 `release_profile=full` 的 Full Release Validation 会设置 `published_upgrade_survivor_baselines='last-stable-4 2026.4.23 2026.5.2 2026.4.15'` 和 `published_upgrade_survivor_scenarios=reported-issues`,以扩展到最新四个 stable npm 版本、固定的插件兼容性边界版本,以及针对 Feishu 配置、保留的 bootstrap/persona 文件、已配置 OpenClaw 插件安装、波浪号日志路径和陈旧旧版插件依赖根的问题形态 fixture。多基线 published-upgrade survivor 选择会按基线分片到单独的目标 Docker runner 作业中。单独的 `Update Migration` 工作流在问题是详尽的已发布更新清理,而不是普通 Full Release CI 覆盖范围时,使用 `update-migration` Docker 通道以及 `all-since-2026.4.23` 和 `plugin-deps-cleanup`。本地聚合运行可以使用 `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPECS` 传入精确软件包 spec,使用 `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC` 保留单个通道,例如 `openclaw@2026.4.15`,或设置 `OPENCLAW_UPGRADE_SURVIVOR_SCENARIOS` 以运行场景矩阵。已发布通道会用内置的 `openclaw config set` 命令 recipe 配置基线,在 `summary.json` 中记录 recipe 步骤,并在 Gateway 网关启动后探测 `/healthz`、`/readyz` 以及 RPC status。Windows packaged 和 installer fresh 通道还会验证已安装软件包能否从原始绝对 Windows 路径导入 browser-control override。OpenAI 跨 OS agent-turn smoke 会在设置时默认使用 `OPENCLAW_CROSS_OS_OPENAI_MODEL`,否则使用 `openai/gpt-5.4`,因此安装和 Gateway 网关证明会停留在 GPT-5 测试模型上,同时避免 GPT-4.x 默认值。 ### 旧版兼容窗口 -包验收对已发布包有有界的旧版兼容窗口。到 `2026.4.25` 为止的包,包括 `2026.4.25-beta.*`,可以使用兼容路径: +软件包验收为已经发布的软件包提供有界的旧版兼容窗口。直到 `2026.4.25` 的软件包,包括 `2026.4.25-beta.*`,都可以使用兼容路径: -- `dist/postinstall-inventory.json` 中已知的私有 QA 条目可以指向 tarball 省略的文件; -- 当包未暴露 `gateway install --wrapper` flag 时,`doctor-switch` 可以跳过该持久化子用例; -- `update-channel-switch` 可以从 tarball 派生的 fake git fixture 中剪除缺失的 `pnpm.patchedDependencies`,并可以记录缺失的持久化 `update.channel`; -- 插件 smoke 可以读取 legacy 安装记录位置,或接受缺失的 marketplace 安装记录持久化; -- `plugin-update` 可以允许配置元数据迁移,同时仍要求安装记录和 no-reinstall 行为保持不变。 +- `dist/postinstall-inventory.json` 中已知的私有 QA 条目可能指向 tarball 中省略的文件; +- 当软件包未暴露 `gateway install --wrapper` 标志时,`doctor-switch` 可以跳过其持久化子用例; +- `update-channel-switch` 可以从 tarball 派生的伪 git fixture 中修剪缺失的 `pnpm.patchedDependencies`,并且可以记录缺失的持久化 `update.channel`; +- 插件 smoke 可以读取旧版安装记录位置,或接受缺失的 marketplace 安装记录持久化; +- `plugin-update` 可以允许配置元数据迁移,同时仍要求安装记录和无重新安装行为保持不变。 -已发布的 `2026.4.26` 包也可以对已交付的本地构建元数据 stamp 文件发出警告。更晚的包必须满足现代契约;相同条件会失败,而不是警告或跳过。 +已发布的 `2026.4.26` 包也可能会对已经发布的本地构建元数据戳文件发出警告。后续包必须满足现代契约;相同条件会失败,而不是警告或跳过。 ### 示例 @@ -304,110 +304,110 @@ gh workflow run package-acceptance.yml \ -f docker_lanes='install-e2e plugin-update' ``` -调试失败的包验收运行时,从 `resolve_package` 摘要开始,确认包来源、版本和 SHA-256。然后检查 `docker_acceptance` 子运行及其 Docker 产物:`.artifacts/docker-tests/**/summary.json`、`failures.json`、车道日志、阶段计时和重新运行命令。优先重新运行失败的包配置文件或精确的 Docker 车道,而不是重新运行完整发布验证。 +调试失败的包验收运行时,先查看 `resolve_package` 摘要,确认包来源、版本和 SHA-256。然后检查 `docker_acceptance` 子运行及其 Docker 工件:`.artifacts/docker-tests/**/summary.json`、`failures.json`、lane 日志、阶段耗时和重新运行命令。优先重新运行失败的包配置文件或精确的 Docker lane,而不是重新运行完整发布验证。 ## 安装冒烟测试 -单独的 `Install Smoke` 工作流通过自己的 `preflight` 作业复用同一个范围脚本。它将冒烟覆盖拆分为 `run_fast_install_smoke` 和 `run_full_install_smoke`。 +独立的 `Install Smoke` 工作流通过自己的 `preflight` 作业复用同一个范围脚本。它将冒烟覆盖拆分为 `run_fast_install_smoke` 和 `run_full_install_smoke`。 -- **快速路径**会在拉取请求触及 Docker/包表面、内置插件包/清单变更,或 Docker 冒烟作业会覆盖的核心插件/渠道/Gateway 网关/插件 SDK 表面时运行。仅源代码的内置插件变更、仅测试编辑和仅文档编辑不会占用 Docker worker。快速路径会构建一次根 Dockerfile 镜像、检查 CLI、运行智能体删除共享工作区 CLI 冒烟测试、运行容器 Gateway 网关网络 e2e、验证内置插件构建参数,并在 240 秒聚合命令超时内运行有界的内置插件 Docker 配置文件(每个场景的 Docker 运行会单独设定上限)。 -- **完整路径**会保留 QR 包安装和安装器 Docker/更新覆盖,用于夜间定时运行、手动分发、workflow-call 发布检查,以及真正触及安装器/包/Docker 表面的拉取请求。在完整模式下,install-smoke 会准备或复用一个目标 SHA 的 GHCR 根 Dockerfile 冒烟镜像,然后将 QR 包安装、根 Dockerfile/Gateway 网关冒烟测试、安装器/更新冒烟测试,以及快速内置插件 Docker E2E 作为独立作业运行,这样安装器工作就不必等待根镜像冒烟测试完成。 +- **快速路径**会在 pull request 触及 Docker/包表面、内置插件包/清单变更,或 Docker 冒烟作业会覆盖的核心插件/渠道/Gateway 网关/插件 SDK 表面时运行。仅源码的内置插件变更、仅测试编辑和仅文档编辑不会预留 Docker worker。快速路径会构建一次根 Dockerfile 镜像、检查 CLI、运行 agents delete shared-workspace CLI 冒烟测试、运行容器 Gateway 网关网络 e2e、验证内置扩展构建参数,并在 240 秒聚合命令超时内运行有界的内置插件 Docker 配置文件(每个场景的 Docker 运行单独设置上限)。 +- **完整路径**保留 QR 包安装以及安装器 Docker/更新覆盖,用于夜间定时运行、手动分发、workflow-call 发布检查,以及真正触及安装器/包/Docker 表面的 pull request。在完整模式下,install-smoke 会准备或复用一个目标 SHA GHCR 根 Dockerfile 冒烟镜像,然后将 QR 包安装、根 Dockerfile/Gateway 网关冒烟、安装器/更新冒烟,以及快速内置插件 Docker E2E 作为独立作业运行,这样安装器工作就不会被根镜像冒烟阻塞。 -`main` 推送(包括合并提交)不会强制完整路径;当变更范围逻辑会在推送上请求完整覆盖时,工作流会保留快速 Docker 冒烟测试,并将完整安装冒烟测试留给夜间或发布验证。 +`main` 推送(包括合并提交)不会强制使用完整路径;当变更范围逻辑会在推送上请求完整覆盖时,工作流会保留快速 Docker 冒烟,并将完整安装冒烟留给夜间或发布验证。 -较慢的 Bun 全局安装 image-provider 冒烟测试由 `run_bun_global_install_smoke` 单独控制。它会在夜间计划和发布检查工作流中运行,手动 `Install Smoke` 分发可以选择启用它,但拉取请求和 `main` 推送不会运行。QR 和安装器 Docker 测试保留各自专注安装的 Dockerfile。 +较慢的 Bun 全局安装 image-provider 冒烟由 `run_bun_global_install_smoke` 单独控制。它会在夜间计划和发布检查工作流中运行,手动 `Install Smoke` 分发也可以选择加入,但 pull request 和 `main` 推送不会运行它。QR 和安装器 Docker 测试保留各自专注于安装的 Dockerfile。 ## 本地 Docker E2E -`pnpm test:docker:all` 会预构建一个共享的实时测试镜像,将 OpenClaw 打包一次为 npm tarball,并构建两个共享的 `scripts/e2e/Dockerfile` 镜像: +`pnpm test:docker:all` 会预构建一个共享 live-test 镜像,将 OpenClaw 打包一次为 npm tarball,并构建两个共享 `scripts/e2e/Dockerfile` 镜像: -- 一个用于安装器/更新/插件依赖车道的裸 Node/Git runner; -- 一个将同一 tarball 安装到 `/app` 中、用于常规功能车道的功能镜像。 +- 用于安装器/更新/插件依赖 lane 的裸 Node/Git runner; +- 一个功能镜像,会将同一个 tarball 安装到 `/app` 中,用于普通功能 lane。 -Docker 车道定义位于 `scripts/lib/docker-e2e-scenarios.mjs`,规划逻辑位于 `scripts/lib/docker-e2e-plan.mjs`,runner 只执行选中的计划。调度器使用 `OPENCLAW_DOCKER_E2E_BARE_IMAGE` 和 `OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE` 为每条车道选择镜像,然后用 `OPENCLAW_SKIP_DOCKER_BUILD=1` 运行车道。 +Docker lane 定义位于 `scripts/lib/docker-e2e-scenarios.mjs`,规划器逻辑位于 `scripts/lib/docker-e2e-plan.mjs`,runner 只执行选中的计划。调度器通过 `OPENCLAW_DOCKER_E2E_BARE_IMAGE` 和 `OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE` 为每个 lane 选择镜像,然后使用 `OPENCLAW_SKIP_DOCKER_BUILD=1` 运行 lane。 -### 可调参数 +### 可调项 -| 变量 | 默认值 | 用途 | -| -------------------------------------- | ------ | --------------------------------------------------------------------------------------------- | -| `OPENCLAW_DOCKER_ALL_PARALLELISM` | 10 | 常规车道的主池槽位数。 | -| `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM` | 10 | 对提供商敏感的尾部池槽位数。 | -| `OPENCLAW_DOCKER_ALL_LIVE_LIMIT` | 9 | 并发实时车道上限,避免提供商限流。 | -| `OPENCLAW_DOCKER_ALL_NPM_LIMIT` | 10 | 并发 npm 安装车道上限。 | -| `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT` | 7 | 并发多服务车道上限。 | -| `OPENCLAW_DOCKER_ALL_START_STAGGER_MS` | 2000 | 车道启动之间的错峰时间,用于避免 Docker daemon 创建风暴;设为 `0` 表示不使用错峰。 | -| `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS` | 7200000 | 每条车道的兜底超时(120 分钟);选定的实时/尾部车道使用更严格的上限。 | -| `OPENCLAW_DOCKER_ALL_DRY_RUN` | 未设置 | `1` 会打印调度器计划而不运行车道。 | -| `OPENCLAW_DOCKER_ALL_LANES` | 未设置 | 逗号分隔的精确车道列表;跳过清理冒烟测试,以便智能体复现单个失败车道。 | +| 变量 | 默认值 | 用途 | +| -------------------------------------- | ------- | --------------------------------------------------------------------------------------------- | +| `OPENCLAW_DOCKER_ALL_PARALLELISM` | 10 | 普通 lane 的主池槽位数。 | +| `OPENCLAW_DOCKER_ALL_TAIL_PARALLELISM` | 10 | 提供商敏感的尾池槽位数。 | +| `OPENCLAW_DOCKER_ALL_LIVE_LIMIT` | 9 | 并发 live lane 上限,避免提供商限流。 | +| `OPENCLAW_DOCKER_ALL_NPM_LIMIT` | 10 | 并发 npm install lane 上限。 | +| `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT` | 7 | 并发多服务 lane 上限。 | +| `OPENCLAW_DOCKER_ALL_START_STAGGER_MS` | 2000 | lane 启动之间的错峰时间,避免 Docker 守护进程创建风暴;设为 `0` 表示不做错峰。 | +| `OPENCLAW_DOCKER_ALL_LANE_TIMEOUT_MS` | 7200000 | 每个 lane 的兜底超时(120 分钟);选定的 live/tail lane 使用更严格的上限。 | +| `OPENCLAW_DOCKER_ALL_DRY_RUN` | unset | `1` 会打印调度器计划,而不运行 lane。 | +| `OPENCLAW_DOCKER_ALL_LANES` | unset | 逗号分隔的精确 lane 列表;跳过清理冒烟,以便智能体可以复现一个失败 lane。 | -超过其有效上限的车道仍可从空池启动,然后独占运行,直到释放容量。本地聚合会预检 Docker、移除陈旧的 OpenClaw E2E 容器、输出活动车道状态、持久化车道计时以便按最长优先排序,并且默认在第一次失败后停止调度新的池化车道。 +比有效上限更重的 lane 仍然可以从空池启动,然后独占运行,直到释放容量。本地聚合会预检 Docker、移除陈旧的 OpenClaw E2E 容器、输出活跃 lane 状态、持久化 lane 耗时以便按最长优先排序,并且默认在第一次失败后停止调度新的池化 lane。 -### 可复用实时/E2E 工作流 +### 可复用 live/E2E 工作流 -可复用实时/E2E 工作流会询问 `scripts/test-docker-all.mjs --plan-json` 需要哪些包、镜像类型、实时镜像、车道和凭证覆盖。随后 `scripts/docker-e2e.mjs` 会将该计划转换为 GitHub 输出和摘要。它要么通过 `scripts/package-openclaw-for-docker.mjs` 打包 OpenClaw,要么下载当前运行的包产物,要么从 `package_artifact_run_id` 下载包产物;验证 tarball 清单;当计划需要已安装包的车道时,通过 Blacksmith 的 Docker layer cache 构建并推送带包摘要标签的裸/功能 GHCR Docker E2E 镜像;并复用提供的 `docker_e2e_bare_image`/`docker_e2e_functional_image` 输入或现有包摘要镜像,而不是重新构建。Docker 镜像拉取会使用有界的每次尝试 180 秒超时重试,因此卡住的 registry/cache 流会快速重试,而不会消耗 CI 关键路径的大部分时间。 +可复用 live/E2E 工作流会询问 `scripts/test-docker-all.mjs --plan-json` 需要哪些包、镜像类型、live 镜像、lane 和凭证覆盖。随后 `scripts/docker-e2e.mjs` 会将该计划转换为 GitHub 输出和摘要。它会通过 `scripts/package-openclaw-for-docker.mjs` 打包 OpenClaw、下载当前运行的包工件,或从 `package_artifact_run_id` 下载包工件;验证 tarball 清单;在计划需要已安装包的 lane 时,通过 Blacksmith 的 Docker 层缓存构建并推送带包摘要标签的裸/功能 GHCR Docker E2E 镜像;并复用提供的 `docker_e2e_bare_image`/`docker_e2e_functional_image` 输入或现有的包摘要镜像,而不是重新构建。Docker 镜像拉取会使用有界的每次 180 秒超时进行重试,因此卡住的 registry/cache 流会快速重试,而不是消耗 CI 关键路径的大部分时间。 ### 发布路径分块 -发布 Docker 覆盖会使用较小的分块作业并设置 `OPENCLAW_SKIP_DOCKER_BUILD=1`,这样每个分块只拉取自己需要的镜像类型,并通过同一个加权调度器执行多条车道: +发布 Docker 覆盖使用较小的分块作业并设置 `OPENCLAW_SKIP_DOCKER_BUILD=1`,这样每个分块只拉取自己需要的镜像类型,并通过同一个加权调度器执行多个 lane: - `OPENCLAW_DOCKER_ALL_PROFILE=release-path` - `OPENCLAW_DOCKER_ALL_CHUNK=core | package-update-openai | package-update-anthropic | package-update-core | plugins-runtime-plugins | plugins-runtime-services | plugins-runtime-install-a..h` -当前发布 Docker 分块包括 `core`、`package-update-openai`、`package-update-anthropic`、`package-update-core`、`plugins-runtime-plugins`、`plugins-runtime-services`,以及从 `plugins-runtime-install-a` 到 `plugins-runtime-install-h`。`plugins-runtime-core`、`plugins-runtime` 和 `plugins-integrations` 仍是聚合插件/运行时别名。`install-e2e` 车道别名仍是两个提供商安装器车道的聚合手动重新运行别名。 +当前发布 Docker 分块为 `core`、`package-update-openai`、`package-update-anthropic`、`package-update-core`、`plugins-runtime-plugins`、`plugins-runtime-services`,以及从 `plugins-runtime-install-a` 到 `plugins-runtime-install-h`。`plugins-runtime-core`、`plugins-runtime` 和 `plugins-integrations` 仍然是聚合的插件/运行时别名。`install-e2e` lane 别名仍然是两个提供商安装器 lane 的聚合手动重跑别名。 -当完整发布路径覆盖请求 OpenWebUI 时,它会并入 `plugins-runtime-services`;只有 OpenWebUI 专用分发才保留独立的 `openwebui` 分块。内置渠道更新车道会针对瞬时 npm 网络故障重试一次。 +当完整发布路径覆盖请求 OpenWebUI 时,它会被并入 `plugins-runtime-services`,并且只为仅 OpenWebUI 分发保留独立的 `openwebui` 分块。内置渠道更新 lane 会针对临时 npm 网络故障重试一次。 -每个分块都会上传 `.artifacts/docker-tests/`,其中包含车道日志、计时、`summary.json`、`failures.json`、阶段计时、调度器计划 JSON、慢车道表和每条车道的重新运行命令。工作流的 `docker_lanes` 输入会针对已准备的镜像运行选中的车道,而不是运行分块作业;这会将失败车道调试限制在一个目标明确的 Docker 作业内,并为该运行准备、下载或复用包产物;如果选中的车道是实时 Docker 车道,目标作业会为这次重新运行在本地构建实时测试镜像。生成的每车道 GitHub 重新运行命令会在这些值存在时包含 `package_artifact_run_id`、`package_artifact_name` 和已准备镜像输入,因此失败车道可以复用失败运行中的精确包和镜像。 +每个分块都会上传 `.artifacts/docker-tests/`,其中包含 lane 日志、耗时、`summary.json`、`failures.json`、阶段耗时、调度器计划 JSON、慢 lane 表和每 lane 重新运行命令。工作流 `docker_lanes` 输入会针对准备好的镜像运行选定 lane,而不是运行分块作业,这会将失败 lane 调试限制在一个目标 Docker 作业内,并为该运行准备、下载或复用包工件;如果选定 lane 是 live Docker lane,目标作业会为该次重跑在本地构建 live-test 镜像。生成的每 lane GitHub 重新运行命令会在这些值存在时包含 `package_artifact_run_id`、`package_artifact_name` 和准备好的镜像输入,因此失败的 lane 可以复用失败运行中的精确包和镜像。 ```bash pnpm test:docker:rerun # download Docker artifacts and print combined/per-lane targeted rerun commands pnpm test:docker:timings # slow-lane and phase critical-path summaries ``` -计划的实时/E2E 工作流每天运行完整发布路径 Docker 套件。 +计划的 live/E2E 工作流每天运行完整发布路径 Docker 套件。 ## 插件预发布 -`Plugin Prerelease` 是成本更高的产品/包覆盖,因此它是一个单独的工作流,由 `Full Release Validation` 或明确的操作员分发触发。常规拉取请求、`main` 推送和独立的手动 CI 分发都不会启用该套件。它会在八个插件 worker 之间均衡内置插件测试;这些插件分片作业每次最多运行两个插件配置组,每组使用一个 Vitest worker 和更大的 Node 堆,因此导入较重的插件批次不会创建额外 CI 作业。仅发布的 Docker 预发布路径会以小组批量运行目标 Docker 车道,避免为一到三分钟的作业占用数十个 runner。 +`Plugin Prerelease` 是成本更高的产品/包覆盖,因此它是一个由 `Full Release Validation` 或显式操作员分发的独立工作流。普通 pull request、`main` 推送和独立手动 CI 分发会保持该套件关闭。它会在八个扩展 worker 之间平衡内置插件测试;这些扩展分片作业一次最多运行两个插件配置组,每组使用一个 Vitest worker 和更大的 Node 堆,这样导入密集的插件批次就不会创建额外 CI 作业。仅发布的 Docker 预发布路径会以小组批处理目标 Docker lane,避免为一到三分钟的作业预留数十个 runner。 ## QA Lab -QA Lab 拥有独立于主智能范围工作流之外的专用 CI 车道。Agentic parity 嵌套在广泛的 QA 和发布 harness 下,而不是独立的 PR 工作流。当 parity 应随广泛验证运行一起执行时,使用带有 `rerun_group=qa-parity` 的 `Full Release Validation`。 +QA Lab 在主智能范围工作流之外有专用 CI lane。Agentic parity 嵌套在宽泛 QA 和发布 harness 之下,而不是独立的 PR 工作流。当 parity 应随宽泛验证运行一起执行时,使用 `Full Release Validation` 并设置 `rerun_group=qa-parity`。 -- `QA-Lab - All Lanes` 工作流每晚在 `main` 上运行,也可手动分发;它会将 mock parity 车道、实时 Matrix 车道,以及实时 Telegram 和 Discord 车道展开为并行作业。实时作业使用 `qa-live-shared` 环境,Telegram/Discord 使用 Convex 租约。 +- `QA-Lab - All Lanes` 工作流每晚在 `main` 上运行,也可手动分发;它会将 mock parity lane、live Matrix lane,以及 live Telegram 和 Discord lane 扇出为并行作业。live 作业使用 `qa-live-shared` 环境,Telegram/Discord 使用 Convex 租约。 -发布检查会使用确定性 mock 提供商和 mock 限定模型(`mock-openai/gpt-5.5` 和 `mock-openai/gpt-5.5-alt`)运行 Matrix 和 Telegram 实时传输车道,因此渠道契约与实时模型延迟和常规提供商插件启动相隔离。实时传输 Gateway 网关会禁用记忆搜索,因为 QA parity 会单独覆盖记忆行为;提供商连接性由单独的实时模型、原生提供商和 Docker 提供商套件覆盖。 +发布检查会使用确定性的 mock 提供商和 mock 限定模型(`mock-openai/gpt-5.5` 和 `mock-openai/gpt-5.5-alt`)运行 Matrix 和 Telegram live 传输 lane,这样渠道契约就与 live 模型延迟和普通提供商插件启动隔离。live 传输 Gateway 网关会禁用记忆搜索,因为 QA parity 单独覆盖记忆行为;提供商连通性由独立的 live 模型、原生提供商和 Docker 提供商套件覆盖。 -Matrix 会为计划和发布门禁使用 `--profile fast`,仅在检出的 CLI 支持时添加 `--fail-fast`。CLI 默认值和手动工作流输入仍为 `all`;手动 `matrix_profile=all` 分发始终会将完整 Matrix 覆盖分片为 `transport`、`media`、`e2ee-smoke`、`e2ee-deep` 和 `e2ee-cli` 作业。 +Matrix 在计划和发布 gate 中使用 `--profile fast`,仅当检出的 CLI 支持时才添加 `--fail-fast`。CLI 默认值和手动工作流输入仍为 `all`;手动 `matrix_profile=all` 分发始终会将完整 Matrix 覆盖分片为 `transport`、`media`、`e2ee-smoke`、`e2ee-deep` 和 `e2ee-cli` 作业。 -`OpenClaw Release Checks` 也会在发布批准前运行发布关键的 QA Lab 车道;其 QA parity 门禁会将候选包和基线包作为并行车道作业运行,然后把两个产物都下载到一个小型报告作业中,用于最终 parity 比较。 +`OpenClaw Release Checks` 也会在发布批准前运行发布关键的 QA Lab lane;其 QA parity gate 会将候选包和基线包作为并行 lane 作业运行,然后把两个工件下载到一个小型报告作业中,用于最终 parity 对比。 -对于常规 PR,应遵循限定范围的 CI/检查证据,而不是将 parity 视为必需状态。 +对于普通 PR,遵循有范围限定的 CI/检查证据,而不是将 parity 视为必需状态。 ## CodeQL -`CodeQL` 工作流有意作为范围狭窄的第一遍安全扫描器,而不是完整仓库扫描。每日、手动和非草稿拉取请求守卫运行会扫描 Actions 工作流代码,以及最高风险的 JavaScript/TypeScript 表面,并使用高置信度安全查询筛选高/严重 `security-severity`。 +`CodeQL` 工作流有意作为一个范围较窄的第一轮安全扫描器,而不是完整的仓库扫描。每日、手动以及非草稿拉取请求保护运行会扫描 Actions 工作流代码,以及风险最高的 JavaScript/TypeScript 范围,并使用高置信度安全查询,筛选出高/严重 `security-severity`。 -拉取请求守卫保持轻量:它只会在 `.github/actions`、`.github/codeql`、`.github/workflows`、`packages` 或 `src` 下发生变更时启动,并运行与定时工作流相同的高置信度安全矩阵。Android 和 macOS CodeQL 不包含在 PR 默认项中。 +拉取请求保护保持轻量:它只会针对 `.github/actions`、`.github/codeql`、`.github/workflows`、`packages` 或 `src` 下的变更启动,并运行与定时工作流相同的高置信度安全矩阵。Android 和 macOS CodeQL 不包含在 PR 默认项中。 ### 安全类别 -| 类别 | 表面 | +| 类别 | 范围 | | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | | `/codeql-security-high/core-auth-secrets` | 认证、密钥、沙箱、cron 和 Gateway 网关基线 | -| `/codeql-security-high/channel-runtime-boundary` | 核心渠道实现契约,加上渠道插件运行时、Gateway 网关、插件 SDK、密钥、审计触点 | -| `/codeql-security-high/network-ssrf-boundary` | 核心 SSRF、IP 解析、网络守卫、Web 抓取和插件 SDK SSRF 策略表面 | -| `/codeql-security-high/mcp-process-tool-boundary` | MCP 服务器、进程执行辅助工具、出站投递,以及智能体工具执行门控 | -| `/codeql-security-high/plugin-trust-boundary` | 插件安装、加载器、清单、注册表、包管理器安装、源加载,以及插件 SDK 包契约信任表面 | +| `/codeql-security-high/channel-runtime-boundary` | 核心渠道实现契约,以及渠道插件运行时、Gateway 网关、插件 SDK、密钥、审计接触点 | +| `/codeql-security-high/network-ssrf-boundary` | 核心 SSRF、IP 解析、网络防护、web-fetch 和插件 SDK SSRF 策略范围 | +| `/codeql-security-high/mcp-process-tool-boundary` | MCP 服务器、进程执行辅助工具、出站投递,以及智能体工具执行闸门 | +| `/codeql-security-high/plugin-trust-boundary` | 插件安装、加载器、清单、注册表、包管理器安装、源码加载,以及插件 SDK 包契约信任范围 | ### 平台特定安全分片 -- `CodeQL Android Critical Security` — 定时 Android 安全分片。在工作流健全性接受的最小 Blacksmith Linux runner 上手动构建 Android 应用以供 CodeQL 使用。上传到 `/codeql-critical-security/android` 下。 -- `CodeQL macOS Critical Security` — 每周/手动 macOS 安全分片。在 Blacksmith macOS 上手动构建 macOS 应用以供 CodeQL 使用,从上传的 SARIF 中过滤依赖构建结果,并上传到 `/codeql-critical-security/macos` 下。它被排除在每日默认项之外,因为即使结果干净,macOS 构建也会主导运行时长。 +- `CodeQL Android Critical Security` — 定时 Android 安全分片。在工作流完整性检查接受的最小 Blacksmith Linux runner 上手动构建 Android 应用以供 CodeQL 使用。上传到 `/codeql-critical-security/android` 下。 +- `CodeQL macOS Critical Security` — 每周/手动 macOS 安全分片。在 Blacksmith macOS 上手动构建 macOS 应用以供 CodeQL 使用,从上传的 SARIF 中过滤掉依赖构建结果,并上传到 `/codeql-critical-security/macos` 下。它保留在每日默认项之外,因为即使结果干净,macOS 构建也会主导运行时间。 -### 关键质量类别 +### Critical Quality 类别 -`CodeQL Critical Quality` 是对应的非安全分片。它只在较小的 Blacksmith Linux runner 上,对范围狭窄的高价值表面运行错误严重级别、非安全 JavaScript/TypeScript 质量查询。它的拉取请求守卫有意小于定时配置:非草稿 PR 只会针对智能体命令/模型/工具执行和回复分发代码、配置架构/迁移/IO 代码、认证/密钥/沙箱/安全代码、核心渠道和内置渠道插件运行时、Gateway 网关协议/服务器方法、记忆运行时/SDK 粘合代码、MCP/进程/出站投递、提供商运行时/模型目录、会话诊断/投递队列、插件加载器、插件 SDK/包契约,或插件 SDK 回复运行时变更,运行匹配的 `agent-runtime-boundary`、`config-boundary`、`core-auth-secrets`、`channel-runtime-boundary`、`gateway-runtime-boundary`、`memory-runtime-boundary`、`mcp-process-runtime-boundary`、`provider-runtime-boundary`、`session-diagnostics-boundary`、`plugin-boundary`、`plugin-sdk-package-contract` 和 `plugin-sdk-reply-runtime` 分片。CodeQL 配置和质量工作流变更会运行全部十二个 PR 质量分片。 +`CodeQL Critical Quality` 是对应的非安全分片。它在较小的 Blacksmith Linux runner 上,仅对范围较窄的高价值表面运行错误严重级别、非安全 JavaScript/TypeScript 质量查询。它的拉取请求保护有意小于定时配置:非草稿 PR 只会针对智能体命令/模型/工具执行和回复调度代码、配置 schema/迁移/IO 代码、认证/密钥/沙箱/安全代码、核心渠道和内置渠道插件运行时、Gateway 网关协议/服务器方法、memory 运行时/SDK 胶水层、MCP/进程/出站投递、提供商运行时/模型目录、会话诊断/投递队列、插件加载器、插件 SDK/包契约,或插件 SDK 回复运行时变更,运行匹配的 `agent-runtime-boundary`、`config-boundary`、`core-auth-secrets`、`channel-runtime-boundary`、`gateway-runtime-boundary`、`memory-runtime-boundary`、`mcp-process-runtime-boundary`、`provider-runtime-boundary`、`session-diagnostics-boundary`、`plugin-boundary`、`plugin-sdk-package-contract` 和 `plugin-sdk-reply-runtime` 分片。CodeQL 配置和质量工作流变更会运行全部十二个 PR 质量分片。 手动调度接受: @@ -415,40 +415,40 @@ Matrix 会为计划和发布门禁使用 `--profile fast`,仅在检出的 CLI profile=all|agent-runtime-boundary|config-boundary|core-auth-secrets|channel-runtime-boundary|gateway-runtime-boundary|memory-runtime-boundary|mcp-process-runtime-boundary|plugin-boundary|plugin-sdk-package-contract|plugin-sdk-reply-runtime|provider-runtime-boundary|session-diagnostics-boundary ``` -狭窄配置是用于单独运行一个质量分片的教学/迭代钩子。 +窄配置是用于单独运行一个质量分片的教学/迭代钩子。 -| 类别 | 表面 | +| 类别 | 范围 | | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `/codeql-critical-quality/core-auth-secrets` | 认证、密钥、沙箱、cron 和 Gateway 网关安全边界代码 | -| `/codeql-critical-quality/config-boundary` | 配置架构、迁移、规范化和 IO 契约 | -| `/codeql-critical-quality/gateway-runtime-boundary` | Gateway 网关协议架构和服务器方法契约 | -| `/codeql-critical-quality/channel-runtime-boundary` | 核心渠道和内置渠道插件实现契约 | -| `/codeql-critical-quality/agent-runtime-boundary` | 命令执行、模型/提供商分发、自动回复分发和队列,以及 ACP 控制平面运行时契约 | -| `/codeql-critical-quality/mcp-process-runtime-boundary` | MCP 服务器和工具桥、进程监督辅助工具,以及出站投递契约 | -| `/codeql-critical-quality/memory-runtime-boundary` | 记忆主机 SDK、记忆运行时 facade、记忆插件 SDK 别名、记忆运行时激活粘合代码,以及记忆 Doctor 命令 | -| `/codeql-critical-quality/session-diagnostics-boundary` | 回复队列内部、会话投递队列、出站会话绑定/投递辅助工具、诊断事件/日志包表面,以及会话 Doctor CLI 契约 | -| `/codeql-critical-quality/plugin-sdk-reply-runtime` | 插件 SDK 入站回复分发、回复载荷/分块/运行时辅助工具、渠道回复选项、投递队列,以及会话/线程绑定辅助工具 | -| `/codeql-critical-quality/provider-runtime-boundary` | 模型目录规范化、提供商认证和设备发现、提供商运行时注册、提供商默认值/目录,以及 Web/搜索/抓取/嵌入注册表 | -| `/codeql-critical-quality/ui-control-plane` | 控制 UI 启动、本地持久化、Gateway 网关控制流,以及任务控制平面运行时契约 | -| `/codeql-critical-quality/web-media-runtime-boundary` | 核心 Web 抓取/搜索、媒体 IO、媒体理解、图像生成,以及媒体生成运行时契约 | -| `/codeql-critical-quality/plugin-boundary` | 加载器、注册表、公共表面,以及插件 SDK 入口点契约 | -| `/codeql-critical-quality/plugin-sdk-package-contract` | 已发布包侧插件 SDK 源代码和插件包契约辅助工具 | +| `/codeql-critical-quality/core-auth-secrets` | 认证、密钥、沙箱、cron 和 Gateway 网关安全边界代码 | +| `/codeql-critical-quality/config-boundary` | 配置 schema、迁移、规范化和 IO 契约 | +| `/codeql-critical-quality/gateway-runtime-boundary` | Gateway 网关协议 schema 和服务器方法契约 | +| `/codeql-critical-quality/channel-runtime-boundary` | 核心渠道和内置渠道插件实现契约 | +| `/codeql-critical-quality/agent-runtime-boundary` | 命令执行、模型/提供商调度、自动回复调度和队列,以及 ACP 控制平面运行时契约 | +| `/codeql-critical-quality/mcp-process-runtime-boundary` | MCP 服务器和工具桥接、进程监督辅助工具,以及出站投递契约 | +| `/codeql-critical-quality/memory-runtime-boundary` | Memory host SDK、memory 运行时 facade、memory 插件 SDK 别名、memory 运行时激活胶水层,以及 memory doctor 命令 | +| `/codeql-critical-quality/session-diagnostics-boundary` | 回复队列内部机制、会话投递队列、出站会话绑定/投递辅助工具、诊断事件/日志包范围,以及会话 doctor CLI 契约 | +| `/codeql-critical-quality/plugin-sdk-reply-runtime` | 插件 SDK 入站回复调度、回复载荷/分块/运行时辅助工具、渠道回复选项、投递队列,以及会话/thread 绑定辅助工具 | +| `/codeql-critical-quality/provider-runtime-boundary` | 模型目录规范化、提供商认证和设备发现、提供商运行时注册、提供商默认值/目录,以及 web/search/fetch/embedding 注册表 | +| `/codeql-critical-quality/ui-control-plane` | Control UI 引导启动、本地持久化、Gateway 网关控制流,以及任务控制平面运行时契约 | +| `/codeql-critical-quality/web-media-runtime-boundary` | 核心 web fetch/search、媒体 IO、媒体理解、图像生成,以及媒体生成运行时契约 | +| `/codeql-critical-quality/plugin-boundary` | 加载器、注册表、公共表面,以及插件 SDK 入口点契约 | +| `/codeql-critical-quality/plugin-sdk-package-contract` | 已发布包侧插件 SDK 源码和插件包契约辅助工具 | -质量与安全保持分离,这样质量发现就可以在不遮蔽安全信号的情况下进行定时、度量、禁用或扩展。Swift、Python 和内置插件 CodeQL 扩展应仅在狭窄配置拥有稳定运行时和信号之后,作为有范围或分片的后续工作加回。 +质量与安全保持分离,因此质量发现可以被定时、度量、禁用或扩展,而不会遮蔽安全信号。Swift、Python 和内置插件 CodeQL 扩展只应在窄配置具备稳定运行时间和信号之后,作为有范围限定或分片的后续工作加回。 ## 维护工作流 ### Docs Agent -`Docs Agent` 工作流是一个事件驱动的 Codex 维护通道,用于让现有文档与最近落地的变更保持一致。它没有纯定时计划:`main` 上成功的非机器人 push CI 运行可以触发它,手动调度也可以直接运行它。当 `main` 已继续前进,或过去一小时内已经创建了另一个未跳过的 Docs Agent 运行时,workflow-run 调用会跳过。运行时,它会审核从上一个未跳过的 Docs Agent 源 SHA 到当前 `main` 的提交范围,因此一次每小时运行可以覆盖自上次文档处理以来积累的所有 main 变更。 +`Docs Agent` 工作流是一个事件驱动的 Codex 维护通道,用于让现有文档与最近落地的变更保持一致。它没有纯定时计划:`main` 上一次成功的非机器人 push CI 运行可以触发它,手动调度也可以直接运行它。当 `main` 已经前移,或者过去一小时内创建了另一个未跳过的 Docs Agent 运行时,workflow-run 调用会跳过。运行时,它会审查从上一个未跳过 Docs Agent 来源 SHA 到当前 `main` 的提交范围,因此每小时一次的运行可以覆盖自上次文档处理以来累计的所有 main 变更。 ### Test Performance Agent -`Test Performance Agent` 工作流是一个事件驱动的 Codex 维护通道,用于处理慢测试。它没有纯定时计划:`main` 上成功的非机器人 push CI 运行可以触发它,但如果同一个 UTC 日已经有另一个 workflow-run 调用运行过或正在运行,它会跳过。手动调度会绕过该每日活动门控。该通道会构建完整套件分组 Vitest 性能报告,让 Codex 只做保持覆盖率的小型测试性能修复,而不是大范围重构,然后重新运行完整套件报告,并拒绝会降低通过基线测试数量的变更。如果基线存在失败测试,Codex 只能修复明显失败,且 agent 后的完整套件报告必须通过后才能提交任何内容。当机器人 push 落地前 `main` 前进时,该通道会 rebase 已验证补丁,重新运行 `pnpm check:changed`,并重试 push;有冲突的陈旧补丁会被跳过。它使用 GitHub 托管的 Ubuntu,因此 Codex action 可以保持与 docs agent 相同的 drop-sudo 安全姿态。 +`Test Performance Agent` 工作流是一个事件驱动的 Codex 维护通道,用于处理慢测试。它没有纯定时计划:`main` 上一次成功的非机器人 push CI 运行可以触发它,但如果当天 UTC 已经有另一个 workflow-run 调用运行过或正在运行,它会跳过。手动调度会绕过该每日活动闸门。该通道会构建完整测试套件分组 Vitest 性能报告,让 Codex 只做小规模、保持覆盖率的测试性能修复,而不是广泛重构,然后重新运行完整测试套件报告,并拒绝会降低通过基线测试数量的变更。如果基线存在失败测试,Codex 只能修复明显失败,并且 agent 后的完整测试套件报告必须通过后才能提交任何内容。当 `main` 在机器人 push 落地前前移时,该通道会 rebase 已验证的补丁,重新运行 `pnpm check:changed`,并重试 push;有冲突的过期补丁会被跳过。它使用 GitHub 托管的 Ubuntu,因此 Codex action 可以保持与 docs agent 相同的 drop-sudo 安全姿态。 ### 合并后的重复 PR -`Duplicate PRs After Merge` 工作流是一个手动维护者工作流,用于落地后的重复项清理。它默认 dry-run,且只有在 `apply=true` 时才会关闭显式列出的 PR。在修改 GitHub 前,它会验证已落地 PR 已合并,并且每个重复项都有共享的引用 issue 或重叠的变更 hunk。 +`Duplicate PRs After Merge` 工作流是一个手动维护者工作流,用于落地后的重复项清理。它默认 dry-run,并且只有在 `apply=true` 时才关闭明确列出的 PR。在修改 GitHub 之前,它会验证已落地的 PR 已合并,并且每个重复 PR 要么共享被引用的问题,要么存在重叠的变更 hunk。 ```bash gh workflow run duplicate-after-merge.yml \ @@ -457,29 +457,29 @@ gh workflow run duplicate-after-merge.yml \ -f apply=true ``` -## 本地检查门控和变更路由 +## 本地检查闸门和变更路由 -本地 changed-lane 逻辑位于 `scripts/changed-lanes.mjs`,并由 `scripts/check-changed.mjs` 执行。该本地检查门控在架构边界方面比宽泛的 CI 平台范围更严格: +本地 changed-lane 逻辑位于 `scripts/changed-lanes.mjs`,并由 `scripts/check-changed.mjs` 执行。这个本地检查闸门在架构边界上比广泛的 CI 平台范围更严格: -- 核心生产变更会运行核心生产和核心测试类型检查,加上核心 lint/guards; -- 仅核心测试变更只运行核心测试类型检查,加上核心 lint; -- 扩展生产变更会运行扩展生产和扩展测试类型检查,加上扩展 lint; -- 仅扩展测试变更会运行扩展测试类型检查,加上扩展 lint; -- 公共插件 SDK 或插件契约变更会扩展到扩展类型检查,因为扩展依赖这些核心契约(Vitest 扩展扫描仍然是显式测试工作); -- 仅发布元数据版本 bump 会运行定向版本/配置/根依赖检查; -- 未知 root/配置变更会故障安全地进入所有检查通道。 +- 核心生产变更会运行核心生产和核心测试类型检查,以及核心 lint/guard; +- 仅核心测试变更只会运行核心测试类型检查和核心 lint; +- 插件生产变更会运行插件生产和插件测试类型检查,以及插件 lint; +- 仅插件测试变更会运行插件测试类型检查和插件 lint; +- 公共插件 SDK 或插件契约变更会扩展到插件类型检查,因为插件依赖这些核心契约(Vitest 插件扫描仍然是显式测试工作); +- 仅发布元数据的版本 bump 会运行有针对性的版本/配置/根依赖检查; +- 未知的 root/配置变更会故障安全地进入全部检查通道。 -本地 changed-test 路由位于 `scripts/test-projects.test-support.mjs`,并且有意比 `check:changed` 更便宜:直接测试编辑会运行自身,源代码编辑优先使用显式映射,然后是同级测试和导入图依赖项。共享群组房间投递配置是显式映射之一:对群组可见回复配置、源回复投递模式或消息工具系统提示的变更,会经过核心回复测试以及 Discord 和 Slack 投递回归测试,因此共享默认值变更会在首次 PR push 前失败。只有当变更范围足够覆盖整个 harness,以至于廉价映射集合不是可信代理时,才使用 `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`。 +本地 changed-test 路由位于 `scripts/test-projects.test-support.mjs`,并且有意比 `check:changed` 更便宜:直接测试编辑会运行自身,源码编辑优先使用显式映射,然后运行同级测试和导入图依赖项。共享 group-room 投递配置是显式映射之一:对 group visible-reply 配置、源码回复投递模式或 message-tool 系统提示词的变更,会路由到核心回复测试,以及 Discord 和 Slack 投递回归测试,因此共享默认值变更会在第一次 PR push 之前失败。只有当变更影响范围足够覆盖整个 harness,以至于廉价映射集合不是可信代理时,才使用 `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`。 ## Testbox 验证 -从仓库根目录运行 Testbox,并优先使用全新预热的 box 进行广泛验证。在对复用过、已过期,或刚报告了异常大规模同步的 box 执行慢速 gate 之前,先在 box 内运行 `pnpm testbox:sanity`。 +从仓库根目录运行 Testbox,并优先为广泛验证使用全新预热的 box。在一个被复用、已过期,或刚刚报告了意外大规模同步的 box 上运行耗时检查前,先在 box 内运行 `pnpm testbox:sanity`。 -当所需的根文件(例如 `pnpm-lock.yaml`)消失,或 `git status --short` 显示至少 200 个已跟踪删除项时,sanity check 会快速失败。这通常意味着远程同步状态不是 PR 的可信副本;停止那个 box,并改为预热一个新的 box,而不是调试产品测试失败。对于有意进行大规模删除的 PR,请为该次 sanity run 设置 `OPENCLAW_TESTBOX_ALLOW_MASS_DELETIONS=1`。 +当 `pnpm-lock.yaml` 等必需的根文件消失,或 `git status --short` 显示至少 200 个已跟踪删除时,完整性检查会快速失败。这通常意味着远程同步状态不是 PR 的可信副本;停止该 box 并预热一个新的,而不是调试产品测试失败。对于有意进行大规模删除的 PR,请为该完整性检查设置 `OPENCLAW_TESTBOX_ALLOW_MASS_DELETIONS=1`。 -`pnpm testbox:run` 还会终止本地 Blacksmith CLI 调用:如果它在同步阶段停留超过五分钟且没有同步后的输出。设置 `OPENCLAW_TESTBOX_SYNC_TIMEOUT_MS=0` 可禁用该保护,或为异常大的本地 diff 使用更大的毫秒值。 +如果本地 Blacksmith CLI 调用在同步阶段停留超过五分钟且没有同步后输出,`pnpm testbox:run` 也会终止它。设置 `OPENCLAW_TESTBOX_SYNC_TIMEOUT_MS=0` 可禁用该保护,或为异常大的本地差异使用更大的毫秒值。 -Crabbox 是仓库自有的远程 box 包装器,用于维护者 Linux 验证。当某个检查对本地编辑循环来说过于广泛、CI 对等性很重要,或验证需要 secrets、Docker、package lanes、可复用 box,或远程日志时,请使用它。常规 OpenClaw 后端是 `blacksmith-testbox`;自有 AWS/Hetzner 容量是在 Blacksmith 中断、配额问题,或明确进行自有容量测试时的 fallback。 +Crabbox 是仓库自有的远程 box 包装器,用于维护者 Linux 验证。当某项检查对本地编辑循环来说过于宽泛、需要 CI 一致性,或验证需要密钥、Docker、包验证通道、可复用 box 或远程日志时使用它。正常的 OpenClaw 后端是 `blacksmith-testbox`;自有 AWS/Hetzner 容量是 Blacksmith 中断、配额问题或明确进行自有容量测试时的后备方案。 首次运行前,从仓库根目录检查包装器: @@ -487,9 +487,9 @@ Crabbox 是仓库自有的远程 box 包装器,用于维护者 Linux 验证。 pnpm crabbox:run -- --help | sed -n '1,120p' ``` -如果 Crabbox 二进制文件过旧且未声明 `blacksmith-testbox`,仓库包装器会拒绝运行。即使 `.crabbox.yaml` 有自有云默认值,也要显式传入 provider。 +如果 Crabbox 二进制文件过旧且未声明 `blacksmith-testbox`,仓库包装器会拒绝使用。即使 `.crabbox.yaml` 有自有云默认值,也要显式传入提供商。 -Changed gate: +变更检查门: ```bash pnpm crabbox:run -- --provider blacksmith-testbox \ @@ -534,21 +534,21 @@ pnpm crabbox:run -- --provider blacksmith-testbox \ "env CI=1 NODE_OPTIONS=--max-old-space-size=4096 OPENCLAW_TEST_PROJECTS_PARALLEL=6 OPENCLAW_VITEST_MAX_WORKERS=1 OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS=900000 pnpm test" ``` -阅读最终的 JSON 摘要。有用的字段是 `provider`、`leaseId`、`syncDelegated`、`exitCode`、`commandMs` 和 `totalMs`。一次性的 Blacksmith 后端 Crabbox 运行应自动停止 Testbox;如果运行被中断或清理状态不明确,请检查 live boxes,并只停止你创建的 box: +阅读最终 JSON 摘要。有用字段是 `provider`、`leaseId`、`syncDelegated`、`exitCode`、`commandMs` 和 `totalMs`。一次性的 Blacksmith 后端 Crabbox 运行应自动停止 Testbox;如果运行被中断或清理状态不明确,请检查实时 box,并只停止你创建的 box: ```bash blacksmith testbox list blacksmith testbox stop --id ``` -只有在你有意需要在同一个已 hydrated 的 box 上执行多条命令时,才使用复用: +仅在你有意需要在同一个已补水 box 上运行多个命令时使用复用: ```bash pnpm crabbox:run -- --provider blacksmith-testbox --id --no-sync --timing-json --shell -- "pnpm test " pnpm crabbox:stop -- ``` -如果 Crabbox 是损坏的层,但 Blacksmith 本身可用,请将 direct Blacksmith 作为窄 fallback: +如果 Crabbox 是出问题的层,但 Blacksmith 本身可用,请使用直接 Blacksmith 作为窄范围后备方案: ```bash blacksmith testbox warmup ci-check-testbox.yml --ref main --idle-timeout 90 @@ -556,7 +556,7 @@ blacksmith testbox run --id "env CI=1 NODE_OPTIONS=--max-old-space-size blacksmith testbox stop --id ``` -仅当 Blacksmith 宕机、受配额限制、缺少所需环境,或明确目标是自有容量时,才升级到自有 Crabbox 容量: +仅当 Blacksmith 不可用、受配额限制、缺少所需环境,或明确目标是自有容量时,才升级到自有 Crabbox 容量: ```bash pnpm crabbox:warmup -- --provider aws --class beast --market on-demand --idle-timeout 90m @@ -565,7 +565,7 @@ pnpm crabbox:run -- --id --timing-json --shell -- "env NODE_OPT pnpm crabbox:stop -- ``` -`.crabbox.yaml` 负责自有云 lanes 的 provider、sync 和 GitHub Actions hydration 默认值。它排除本地 `.git`,使 hydrated Actions checkout 保持自己的远程 Git 元数据,而不是同步维护者本地的 remotes 和 object stores;它还排除绝不应传输的本地 runtime/build artifacts。`.github/workflows/crabbox-hydrate.yml` 负责 checkout、Node/pnpm 设置、`origin/main` fetch,以及面向自有云 `crabbox run --id ` 命令的非 secret 环境交接。 +`.crabbox.yaml` 负责自有云通道的提供商、同步和 GitHub Actions 补水默认值。它会排除本地 `.git`,因此已补水的 Actions checkout 会保留自己的远程 Git 元数据,而不是同步维护者本地的 remotes 和对象存储;它还会排除绝不应传输的本地运行时/构建产物。`.github/workflows/crabbox-hydrate.yml` 负责自有云 `crabbox run --id ` 命令的 checkout、Node/pnpm 设置、`origin/main` 拉取,以及非密钥环境交接。 ## 相关 diff --git a/docs/zh-CN/concepts/qa-e2e-automation.md b/docs/zh-CN/concepts/qa-e2e-automation.md index 421c78164..c0bcfa5be 100644 --- a/docs/zh-CN/concepts/qa-e2e-automation.md +++ b/docs/zh-CN/concepts/qa-e2e-automation.md @@ -1,71 +1,71 @@ --- read_when: - - 了解 QA 栈如何协同工作 + - 了解 QA 技术栈如何协同工作 - 扩展 qa-lab、qa-channel 或传输适配器 - 添加由仓库支持的 QA 场景 - - 围绕 Gateway 网关仪表板构建更高真实度的 QA 自动化 -summary: QA 栈概览:qa-lab、qa-channel、由仓库支持的场景、实时传输通道、传输适配器和报告。 + - 围绕 Gateway 网关仪表板构建更贴近真实场景的 QA 自动化 +summary: QA 栈概览:qa-lab、qa-channel、仓库支持的场景、实时传输通道、传输适配器和报告。 title: QA overview x-i18n: - generated_at: "2026-05-05T01:21:32Z" + generated_at: "2026-05-05T04:27:07Z" model: gpt-5.5 provider: openai - source_hash: 83adbe934d73265a1b47ee463c98fdd3eddfb1cd063d3a46a83dfc7568df0a96 + source_hash: dac200f60fd6215ddee44a55cff947f0bfc09df51720710db4a5d1045b01f714 source_path: concepts/qa-e2e-automation.md workflow: 16 --- 私有 QA 栈旨在以比单个单元测试更真实、更贴近渠道形态的方式测试 OpenClaw。 -当前组成部分: +当前组成: -- `extensions/qa-channel`:合成消息渠道,包含私信、渠道、线程、回应、编辑和删除界面。 -- `extensions/qa-lab`:用于观察转录、注入入站消息并导出 Markdown 报告的调试器 UI 和 QA 总线。 -- `extensions/qa-matrix`,未来的运行器插件:实时传输适配器,在子 QA Gateway 网关内驱动真实渠道。 -- `qa/`:由仓库支持的启动任务和基线 QA 场景种子资产。 -- [Mantis](/zh-CN/concepts/mantis):用于需要真实传输、浏览器截图、VM 状态和 PR 证据的错误的前后实时验证。 +- `extensions/qa-channel`:合成消息渠道,包含私信、渠道、线程、回应、编辑和删除表面。 +- `extensions/qa-lab`:调试器 UI 和 QA 总线,用于观察转录、注入入站消息,以及导出 Markdown 报告。 +- `extensions/qa-matrix`、未来的运行器插件:实时传输适配器,会在子 QA Gateway 网关内驱动真实渠道。 +- `qa/`:由仓库托管的种子资产,用于启动任务和基线 QA 场景。 +- [Mantis](/zh-CN/concepts/mantis):用于需要真实传输、浏览器截图、VM 状态和 PR 证据的 bug,在修复前后进行实时验证。 -## 命令界面 +## 命令表面 每个 QA 流程都在 `pnpm openclaw qa ` 下运行。许多命令有 `pnpm qa:*` 脚本别名;两种形式都受支持。 | 命令 | 用途 | | --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `qa run` | 内置 QA 自检;写入 Markdown 报告。 | -| `qa suite` | 针对 QA Gateway 网关通道运行由仓库支持的场景。别名:`pnpm openclaw qa suite --runner multipass`,用于一次性 Linux VM。 | -| `qa coverage` | 打印 Markdown 场景覆盖率清单(`--json` 用于机器输出)。 | -| `qa parity-report` | 比较两个 `qa-suite-summary.json` 文件并写入智能体对等报告。 | -| `qa character-eval` | 跨多个实时模型运行角色 QA 场景,并生成评审报告。参见[报告](#reporting)。 | -| `qa manual` | 针对选定的提供商/模型通道运行一次性提示。 | +| `qa suite` | 针对 QA Gateway 网关通道运行仓库托管的场景。别名:`pnpm openclaw qa suite --runner multipass`,用于一次性 Linux VM。 | +| `qa coverage` | 打印 Markdown 场景覆盖率清单(使用 `--json` 输出机器可读内容)。 | +| `qa parity-report` | 比较两个 `qa-suite-summary.json` 文件,并写入智能体奇偶性报告。 | +| `qa character-eval` | 跨多个实时模型运行角色 QA 场景,并生成带评判的报告。参见[报告](#reporting)。 | +| `qa manual` | 针对所选提供商/模型通道运行一次性提示。 | | `qa ui` | 启动 QA 调试器 UI 和本地 QA 总线(别名:`pnpm qa:lab:ui`)。 | | `qa docker-build-image` | 构建预制 QA Docker 镜像。 | -| `qa docker-scaffold` | 为 QA 仪表板 + Gateway 网关通道写入 docker-compose 脚手架。 | -| `qa up` | 构建 QA 站点,启动由 Docker 支持的栈,打印 URL(别名:`pnpm qa:lab:up`;`:fast` 变体会添加 `--use-prebuilt-image --bind-ui-dist --skip-ui-build`)。 | -| `qa aimock` | 仅启动 AIMock 提供商服务器。 | -| `qa mock-openai` | 仅启动具备场景感知能力的 `mock-openai` 提供商服务器。 | -| `qa credentials doctor` / `add` / `list` / `remove` | 管理共享 Convex 凭据池。 | +| `qa docker-scaffold` | 为 QA 仪表盘 + Gateway 网关通道写入 docker-compose 脚手架。 | +| `qa up` | 构建 QA 站点,启动由 Docker 支撑的栈,打印 URL(别名:`pnpm qa:lab:up`;`:fast` 变体会添加 `--use-prebuilt-image --bind-ui-dist --skip-ui-build`)。 | +| `qa aimock` | 仅启动 AIMock 提供商服务器。 | +| `qa mock-openai` | 仅启动感知场景的 `mock-openai` 提供商服务器。 | +| `qa credentials doctor` / `add` / `list` / `remove` | 管理共享的 Convex 凭据池。 | | `qa matrix` | 针对一次性 Tuwunel homeserver 的实时传输通道。参见 [Matrix QA](/zh-CN/concepts/qa-matrix)。 | | `qa telegram` | 针对真实私有 Telegram 群组的实时传输通道。 | -| `qa discord` | 针对真实私有 Discord 公会渠道的实时传输通道。 | +| `qa discord` | 针对真实私有 Discord guild 渠道的实时传输通道。 | | `qa slack` | 针对真实私有 Slack 渠道的实时传输通道。 | -| `qa mantis` | 用于实时传输错误的前后验证运行器,包含 Discord 状态回应证据、Crabbox 桌面/浏览器冒烟测试,以及 Slack-in-VNC 冒烟测试。参见 [Mantis](/zh-CN/concepts/mantis)。 | +| `qa mantis` | 用于实时传输 bug 的修复前后验证运行器,包含 Discord 状态回应证据、Crabbox 桌面/浏览器冒烟测试,以及 Slack-in-VNC 冒烟测试。参见 [Mantis](/zh-CN/concepts/mantis)。 | -## 操作员流程 +## 操作者流程 -当前 QA 操作员流程是一个双窗格 QA 站点: +当前 QA 操作者流程是一个双窗格 QA 站点: -- 左侧:带有智能体的 Gateway 网关仪表板(Control UI)。 +- 左侧:带智能体的 Gateway 网关仪表盘(Control UI)。 - 右侧:QA Lab,显示类似 Slack 的转录和场景计划。 -使用以下命令运行: +运行方式: ```bash pnpm qa:lab:up ``` -这会构建 QA 站点,启动由 Docker 支持的 Gateway 网关通道,并公开 QA Lab 页面,操作员或自动化 loop 可以在其中给智能体分配 QA 任务、观察真实渠道行为,并记录哪些有效、失败或仍然受阻。 +这会构建 QA 站点,启动由 Docker 支撑的 Gateway 网关通道,并暴露 QA Lab 页面;操作者或自动化循环可以在该页面给智能体分配 QA 任务,观察真实渠道行为,并记录哪些有效、失败或仍被阻塞。 -为了更快地迭代 QA Lab UI,而不必每次都重建 Docker 镜像,请使用绑定挂载的 QA Lab bundle 启动栈: +为了更快迭代 QA Lab UI,而不必每次都重建 Docker 镜像,可使用绑定挂载的 QA Lab 包启动栈: ```bash pnpm openclaw qa docker-build-image @@ -74,27 +74,27 @@ pnpm qa:lab:up:fast pnpm qa:lab:watch ``` -`qa:lab:up:fast` 会让 Docker 服务使用预构建镜像,并将 `extensions/qa-lab/web/dist` 绑定挂载到 `qa-lab` 容器中。`qa:lab:watch` 会在变更时重建该 bundle,并且浏览器会在 QA Lab 资产哈希变化时自动重新加载。 +`qa:lab:up:fast` 会让 Docker 服务使用预构建镜像,并将 `extensions/qa-lab/web/dist` 绑定挂载到 `qa-lab` 容器中。`qa:lab:watch` 会在变更时重建该包,而浏览器会在 QA Lab 资产哈希变更时自动重新加载。 -要进行本地 OpenTelemetry trace 冒烟测试,请运行: +对于本地 OpenTelemetry 跟踪冒烟测试,运行: ```bash pnpm qa:otel:smoke ``` -该脚本会启动本地 OTLP/HTTP trace 接收器,在启用 `diagnostics-otel` 插件的情况下运行 `otel-trace-smoke` QA 场景,然后解码导出的 protobuf spans,并断言发布关键形态:必须存在 `openclaw.run`、`openclaw.harness.run`、`openclaw.model.call`、`openclaw.context.assembled` 和 `openclaw.message.delivery`;成功轮次中的模型调用不得导出 `StreamAbandoned`;原始诊断 ID 和 `openclaw.content.*` 属性必须留在 trace 之外。它会在 QA 套件工件旁写入 `otel-smoke-summary.json`。 +该脚本会启动本地 OTLP/HTTP 跟踪接收器,在启用 `diagnostics-otel` 插件的情况下运行 `otel-trace-smoke` QA 场景,然后解码导出的 protobuf span,并断言发布关键形态:必须存在 `openclaw.run`、`openclaw.harness.run`、`openclaw.model.call`、`openclaw.context.assembled` 和 `openclaw.message.delivery`;成功轮次上的模型调用不得导出 `StreamAbandoned`;原始诊断 ID 和 `openclaw.content.*` 属性必须留在跟踪之外。它会在 QA 套件工件旁写入 `otel-smoke-summary.json`。 -可观测性 QA 仅保留在源码 checkout 中。npm tarball 会有意省略 QA Lab,因此包 Docker 发布通道不会运行 `qa` 命令。修改诊断 instrumentation 时,请从已构建的源码 checkout 运行 `pnpm qa:otel:smoke`。 +可观测性 QA 仅限源码检出。npm tarball 会有意省略 QA Lab,因此包 Docker 发布通道不会运行 `qa` 命令。更改诊断 instrumentation 时,请从已构建的源码检出运行 `pnpm qa:otel:smoke`。 -要运行真实 Matrix 传输冒烟通道,请运行: +对于使用真实传输的 Matrix 冒烟通道,运行: ```bash pnpm openclaw qa matrix --profile fast --fail-fast ``` -该通道的完整 CLI 参考、profile/场景目录、环境变量和工件布局位于 [Matrix QA](/zh-CN/concepts/qa-matrix)。简要来说:它会在 Docker 中预配一次性 Tuwunel homeserver,注册临时的驱动/SUT/观察者用户,在限定到该传输的子 QA Gateway 网关内运行真实 Matrix 插件(不使用 `qa-channel`),然后在 `.artifacts/qa-e2e/matrix-/` 下写入 Markdown 报告、JSON 摘要、observed-events 工件和组合输出日志。 +该通道的完整 CLI 参考、profile/场景目录、环境变量和工件布局位于 [Matrix QA](/zh-CN/concepts/qa-matrix)。简要来说:它会在 Docker 中预配一次性 Tuwunel homeserver,注册临时 driver/SUT/observer 用户,在限定到该传输的子 QA Gateway 网关内运行真实 Matrix 插件(不使用 `qa-channel`),然后在 `.artifacts/qa-e2e/matrix-/` 下写入 Markdown 报告、JSON 摘要、observed-events 工件和合并输出日志。 -要运行真实传输的 Telegram、Discord 和 Slack 冒烟通道: +对于使用真实传输的 Telegram、Discord 和 Slack 冒烟通道: ```bash pnpm openclaw qa telegram @@ -102,9 +102,9 @@ pnpm openclaw qa discord pnpm openclaw qa slack ``` -它们会针对一个预先存在的真实渠道,并使用两个 bot(driver + SUT)。所需环境变量、场景列表、输出工件和 Convex 凭据池记录在下方的 [Telegram、Discord 和 Slack QA 参考](#telegram-discord-and-slack-qa-reference)中。 +它们会面向一个预先存在的真实渠道,并使用两个机器人(driver + SUT)。所需环境变量、场景列表、输出工件和 Convex 凭据池记录在下方的 [Telegram、Discord 和 Slack QA 参考](#telegram-discord-and-slack-qa-reference)中。 -要运行带有 VNC 救援的完整 Slack 桌面 VM,请运行: +对于带 VNC 救援的完整 Slack 桌面 VM 运行,运行: ```bash pnpm openclaw qa mantis slack-desktop-smoke \ @@ -113,62 +113,62 @@ pnpm openclaw qa mantis slack-desktop-smoke \ --keep-lease ``` -该命令会租用一台 Crabbox 桌面/浏览器机器,在 VM 内运行 Slack 实时通道,在 VNC 浏览器中打开 Slack Web,捕获桌面,并将 `slack-qa/` 以及 `slack-desktop-smoke.png` 复制回 Mantis 工件目录。通过 VNC 手动登录 Slack Web 后,可复用 `--lease-id `。使用 `--gateway-setup` 时,Mantis 会在 VM 内的端口 `38973` 上保留一个持久运行的 OpenClaw Slack Gateway 网关;不使用时,该命令会运行普通的 bot 到 bot Slack QA 通道,并在捕获工件后退出。 +该命令会租用一台 Crabbox 桌面/浏览器机器,在 VM 内运行 Slack 实时通道,在 VNC 浏览器中打开 Slack Web,捕获桌面,并将 `slack-qa/` 以及 `slack-desktop-smoke.png` 复制回 Mantis 工件目录。通过 VNC 手动登录 Slack Web 后,可复用 `--lease-id `。使用 `--gateway-setup` 时,Mantis 会在 VM 内留下一个持久运行的 OpenClaw Slack Gateway 网关,端口为 `38973`;不使用时,该命令会运行普通的机器人到机器人 Slack QA 通道,并在捕获工件后退出。 -使用池化实时凭据前,请运行: +使用池化实时凭据之前,运行: ```bash pnpm openclaw qa credentials doctor ``` -Doctor 会检查 Convex 代理环境,验证端点设置,并在存在维护者 secret 时验证 admin/list 可达性。它只报告 secret 的已设置/缺失状态。 +Doctor 会检查 Convex broker 环境、验证端点设置,并在存在维护者 secret 时验证 admin/list 可达性。它只报告 secret 的已设置/缺失状态。 ## 实时传输覆盖率 -实时传输通道共享一份契约,而不是各自发明自己的场景列表形态。`qa-channel` 是广泛的合成产品行为套件,不属于实时传输覆盖率矩阵。 +实时传输通道共享一个契约,而不是各自发明自己的场景列表形态。`qa-channel` 是广泛的合成产品行为套件,不属于实时传输覆盖率矩阵。 -| 通道 | Canary | 提及门控 | Bot 到 bot | 允许列表拦截 | 顶层回复 | 重启恢复 | 线程跟进 | 线程隔离 | 回应观察 | 帮助命令 | 原生命令注册 | -| -------- | ------ | -------- | ---------- | ------------ | -------- | -------- | -------- | -------- | -------- | -------- | ------------ | -| Matrix | x | x | x | x | x | x | x | x | x | | | -| Telegram | x | x | x | | | | | | | x | | -| Discord | x | x | x | | | | | | | | x | -| Slack | x | x | x | | | | | | | | | +| 通道 | Canary | Mention gating | Bot-to-bot | Allowlist block | Top-level reply | Restart resume | Thread follow-up | Thread isolation | Reaction observation | Help command | Native command registration | +| -------- | ------ | -------------- | ---------- | --------------- | --------------- | -------------- | ---------------- | ---------------- | -------------------- | ------------ | --------------------------- | +| Matrix | x | x | x | x | x | x | x | x | x | | | +| Telegram | x | x | x | | | | | | | x | | +| Discord | x | x | x | | | | | | | | x | +| Slack | x | x | x | | | | | | | | | -这会将 `qa-channel` 保持为广泛的产品行为套件,同时让 Matrix、Telegram 和未来的实时传输共享一份明确的传输契约清单。 +这会将 `qa-channel` 保持为广泛的产品行为套件,同时让 Matrix、Telegram 和未来的实时传输共享一个明确的传输契约清单。 -要运行一次性 Linux VM 通道而不把 Docker 带入 QA 路径,请运行: +对于无需把 Docker 带入 QA 路径的一次性 Linux VM 通道,运行: ```bash pnpm openclaw qa suite --runner multipass --scenario channel-chat-baseline ``` -这会启动一个全新的 Multipass 来宾系统,在来宾系统内安装依赖、构建 OpenClaw、运行 `qa suite`,然后把标准 QA 报告和摘要复制回宿主机的 `.artifacts/qa-e2e/...`。 -它复用与宿主机上 `qa suite` 相同的场景选择行为。 -默认情况下,宿主机和 Multipass 套件运行会使用隔离的 Gateway 网关 worker 并行执行多个选定场景。`qa-channel` 默认并发数为 4,并受选定场景数量限制。使用 `--concurrency ` 调整 worker 数量,或使用 `--concurrency 1` 进行串行执行。 -当任一场景失败时,该命令会以非零状态退出。如果你想获取产物但不想产生失败退出码,请使用 `--allow-failures`。 -实时运行会转发对来宾系统实用且受支持的 QA 认证输入:基于环境变量的提供商密钥、QA 实时提供商配置路径,以及存在时的 `CODEX_HOME`。将 `--output-dir` 保持在仓库根目录下,这样来宾系统才能通过挂载的工作区写回。 +这会启动一个全新的 Multipass 客机,安装依赖,在客机内构建 OpenClaw,运行 `qa suite`,然后把普通 QA 报告和摘要复制回主机上的 `.artifacts/qa-e2e/...`。 +它会复用与主机上 `qa suite` 相同的场景选择行为。 +主机和 Multipass 套件运行默认会使用隔离的 Gateway 网关 worker 并行执行多个已选场景。`qa-channel` 默认并发数为 4,并受已选场景数量限制。使用 `--concurrency ` 调整 worker 数量,或使用 `--concurrency 1` 进行串行执行。 +当任何场景失败时,该命令会以非零状态退出。如果你想获得工件但不希望退出码失败,请使用 `--allow-failures`。 +实时运行会转发对客机实用的受支持 QA 凭证输入:基于环境变量的提供商密钥、QA 实时提供商配置路径,以及存在时的 `CODEX_HOME`。请将 `--output-dir` 保持在仓库根目录下,这样客机才能通过挂载的工作区写回。 ## Telegram、Discord 和 Slack QA 参考 -Matrix 因为场景数量以及基于 Docker 的 homeserver 供应,有一个[专用页面](/zh-CN/concepts/qa-matrix)。Telegram、Discord 和 Slack 更小,每个只有少量场景,没有配置文件系统,并且针对预先存在的真实渠道,所以它们的参考内容放在这里。 +Matrix 有一个[专用页面](/zh-CN/concepts/qa-matrix),因为它的场景数量较多,并且需要基于 Docker 的 homeserver 预配。Telegram、Discord 和 Slack 更小,每个只有少量场景,没有配置文件系统,并针对预先存在的真实渠道运行,因此它们的参考内容放在这里。 ### 共享 CLI 标志 -这些 lane 通过 `extensions/qa-lab/src/live-transports/shared/live-transport-cli.ts` 注册,并接受相同的标志: +这些通道通过 `extensions/qa-lab/src/live-transports/shared/live-transport-cli.ts` 注册,并接受相同的标志: -| 标志 | 默认值 | 描述 | +| 标志 | 默认值 | 描述 | | ------------------------------------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | -| `--scenario ` | — | 只运行此场景。可重复。 | -| `--output-dir ` | `/.artifacts/qa-e2e/{telegram,discord,slack}-` | 报告、摘要、已观察消息和输出日志的写入位置。相对路径会根据 `--repo-root` 解析。 | -| `--repo-root ` | `process.cwd()` | 从中立 cwd 调用时的仓库根目录。 | -| `--sut-account ` | `sut` | QA Gateway 网关配置中的临时账号 id。 | -| `--provider-mode ` | `live-frontier` | `mock-openai` 或 `live-frontier`(旧版 `live-openai` 仍可使用)。 | -| `--model ` / `--alt-model ` | 提供商默认值 | 主模型/备用模型引用。 | -| `--fast` | 关闭 | 支持时启用提供商快速模式。 | -| `--credential-source ` | `env` | 请参阅 [Convex 凭证池](#convex-credential-pool)。 | -| `--credential-role ` | CI 中为 `ci`,否则为 `maintainer` | 使用 `--credential-source convex` 时采用的角色。 | +| `--scenario ` | — | 仅运行此场景。可重复使用。 | +| `--output-dir ` | `/.artifacts/qa-e2e/{telegram,discord,slack}-` | 报告、摘要、观测到的消息和输出日志的写入位置。相对路径会按 `--repo-root` 解析。 | +| `--repo-root ` | `process.cwd()` | 从中立 cwd 调用时的仓库根目录。 | +| `--sut-account ` | `sut` | QA Gateway 网关配置内的临时账号 id。 | +| `--provider-mode ` | `live-frontier` | `mock-openai` 或 `live-frontier`(旧版 `live-openai` 仍可使用)。 | +| `--model ` / `--alt-model ` | 提供商默认值 | 主/备用模型引用。 | +| `--fast` | 关闭 | 在支持的地方启用提供商快速模式。 | +| `--credential-source ` | `env` | 参见 [Convex 凭证池](#convex-credential-pool)。 | +| `--credential-role ` | CI 中为 `ci`,否则为 `maintainer` | `--credential-source convex` 时使用的角色。 | -任一场景失败时,每个 lane 都会以非零状态退出。`--allow-failures` 会写入产物,但不会设置失败退出码。 +任何场景失败时,每个通道都会以非零状态退出。`--allow-failures` 会写入工件,但不会设置失败退出码。 ### Telegram QA @@ -176,9 +176,9 @@ Matrix 因为场景数量以及基于 Docker 的 homeserver 供应,有一个[ pnpm openclaw qa telegram ``` -目标是一个真实的私有 Telegram 群组,并使用两个不同的 bot(driver + SUT)。SUT bot 必须有 Telegram 用户名;当两个 bot 都在 `@BotFather` 中启用 **Bot-to-Bot Communication Mode** 时,bot 到 bot 的观测效果最好。 +目标是一个真实的私有 Telegram 群组,并使用两个不同的机器人(driver + SUT)。SUT 机器人必须有 Telegram 用户名;当两个机器人都在 `@BotFather` 中启用 **Bot 到 Bot 通信模式** 时,机器人到机器人观测效果最佳。 -使用 `--credential-source env` 时必需的环境变量: +当 `--credential-source env` 时需要的环境变量: - `OPENCLAW_QA_TELEGRAM_GROUP_ID` — 数字聊天 id(字符串)。 - `OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKEN` @@ -186,7 +186,7 @@ pnpm openclaw qa telegram 可选: -- `OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT=1` 会在已观察消息产物中保留消息正文(默认会脱敏)。 +- `OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT=1` 会在观测消息工件中保留消息正文(默认会脱敏)。 场景(`extensions/qa-lab/src/live-transports/telegram/telegram-live.runtime.ts:44`): @@ -198,12 +198,14 @@ pnpm openclaw qa telegram - `telegram-tools-compact-command` - `telegram-whoami-command` - `telegram-context-command` +- `telegram-long-final-reuses-preview` +- `telegram-long-final-three-chunks` -输出产物: +输出工件: - `telegram-qa-report.md` -- `telegram-qa-summary.json` — 从 canary 开始,包含每条回复的 RTT(driver 发送 → 观察到 SUT 回复)。 -- `telegram-qa-observed-messages.json` — 除非设置 `OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT=1`,否则正文会被脱敏。 +- `telegram-qa-summary.json` — 包含从 canary 开始的每条回复 RTT(driver 发送 → 观测到 SUT 回复)。 +- `telegram-qa-observed-messages.json` — 正文会脱敏,除非设置了 `OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT=1`。 ### Discord QA @@ -211,28 +213,28 @@ pnpm openclaw qa telegram pnpm openclaw qa discord ``` -目标是一个真实的私有 Discord guild 渠道,并使用两个 bot:一个由 harness 控制的 driver bot,以及一个由子 OpenClaw Gateway 网关通过内置 Discord 插件启动的 SUT bot。它会验证渠道提及处理、SUT bot 是否已向 Discord 注册原生 `/help` 命令,以及选择启用的 Mantis 证据场景。 +目标是一个真实的私有 Discord guild 频道,并使用两个机器人:由 harness 控制的 driver 机器人,以及由子 OpenClaw Gateway 网关通过内置 Discord 插件启动的 SUT 机器人。它会验证频道提及处理、SUT 机器人是否已在 Discord 注册原生 `/help` 命令,以及选择加入的 Mantis 证据场景。 -使用 `--credential-source env` 时必需的环境变量: +当 `--credential-source env` 时需要的环境变量: - `OPENCLAW_QA_DISCORD_GUILD_ID` - `OPENCLAW_QA_DISCORD_CHANNEL_ID` - `OPENCLAW_QA_DISCORD_DRIVER_BOT_TOKEN` - `OPENCLAW_QA_DISCORD_SUT_BOT_TOKEN` -- `OPENCLAW_QA_DISCORD_SUT_APPLICATION_ID` — 必须与 Discord 返回的 SUT bot 用户 id 匹配(否则该 lane 会快速失败)。 +- `OPENCLAW_QA_DISCORD_SUT_APPLICATION_ID` — 必须匹配 Discord 返回的 SUT 机器人用户 id(否则该通道会快速失败)。 可选: -- `OPENCLAW_QA_DISCORD_CAPTURE_CONTENT=1` 会在已观察消息产物中保留消息正文。 +- `OPENCLAW_QA_DISCORD_CAPTURE_CONTENT=1` 会在观测消息工件中保留消息正文。 场景(`extensions/qa-lab/src/live-transports/discord/discord-live.runtime.ts:36`): - `discord-canary` - `discord-mention-gating` - `discord-native-help-command-registration` -- `discord-status-reactions-tool-only` — 选择启用的 Mantis 场景。该场景会单独运行,因为它会将 SUT 切换为始终开启、仅工具模式的 guild 回复,并设置 `messages.statusReactions.enabled=true`,然后捕获 REST reaction 时间线以及 HTML/PNG 视觉产物。 +- `discord-status-reactions-tool-only` — 选择加入的 Mantis 场景。它会单独运行,因为它会将 SUT 切换为始终开启、仅工具的 guild 回复,并设置 `messages.statusReactions.enabled=true`,然后捕获 REST reaction 时间线以及 HTML/PNG 可视工件。 -显式运行 Mantis status-reaction 场景: +显式运行 Mantis Status reaction 场景: ```bash pnpm openclaw qa discord \ @@ -243,12 +245,12 @@ pnpm openclaw qa discord \ --fast ``` -输出产物: +输出工件: - `discord-qa-report.md` - `discord-qa-summary.json` -- `discord-qa-observed-messages.json` — 除非设置 `OPENCLAW_QA_DISCORD_CAPTURE_CONTENT=1`,否则正文会被脱敏。 -- 运行 status-reaction 场景时会生成 `discord-qa-reaction-timelines.json` 和 `discord-status-reactions-tool-only-timeline.png`。 +- `discord-qa-observed-messages.json` — 正文会脱敏,除非设置了 `OPENCLAW_QA_DISCORD_CAPTURE_CONTENT=1`。 +- 运行 Status reaction 场景时会生成 `discord-qa-reaction-timelines.json` 和 `discord-status-reactions-tool-only-timeline.png`。 ### Slack QA @@ -256,9 +258,9 @@ pnpm openclaw qa discord \ pnpm openclaw qa slack ``` -目标是一个真实的私有 Slack 渠道,并使用两个不同的 bot:一个由 harness 控制的 driver bot,以及一个由子 OpenClaw Gateway 网关通过内置 Slack 插件启动的 SUT bot。 +目标是一个真实的私有 Slack 频道,并使用两个不同的机器人:由 harness 控制的 driver 机器人,以及由子 OpenClaw Gateway 网关通过内置 Slack 插件启动的 SUT 机器人。 -使用 `--credential-source env` 时必需的环境变量: +当 `--credential-source env` 时需要的环境变量: - `OPENCLAW_QA_SLACK_CHANNEL_ID` - `OPENCLAW_QA_SLACK_DRIVER_BOT_TOKEN` @@ -267,35 +269,35 @@ pnpm openclaw qa slack 可选: -- `OPENCLAW_QA_SLACK_CAPTURE_CONTENT=1` 会在已观察消息产物中保留消息正文。 +- `OPENCLAW_QA_SLACK_CAPTURE_CONTENT=1` 会在观测消息工件中保留消息正文。 场景(`extensions/qa-lab/src/live-transports/slack/slack-live.runtime.ts:39`): - `slack-canary` - `slack-mention-gating` -输出产物: +输出工件: - `slack-qa-report.md` - `slack-qa-summary.json` -- `slack-qa-observed-messages.json` — 除非设置 `OPENCLAW_QA_SLACK_CAPTURE_CONTENT=1`,否则正文会被脱敏。 +- `slack-qa-observed-messages.json` — 正文会脱敏,除非设置了 `OPENCLAW_QA_SLACK_CAPTURE_CONTENT=1`。 #### 设置 Slack 工作区 -该 lane 需要在一个工作区中有两个不同的 Slack 应用,以及一个两个 bot 都是成员的渠道: +该通道需要在一个工作区中有两个不同的 Slack 应用,以及一个两个机器人都已加入的频道: -- `channelId` — 两个 bot 都已被邀请加入的渠道的 `Cxxxxxxxxxx` id。请使用专用渠道;该 lane 每次运行都会发帖。 -- `driverBotToken` — **Driver** 应用的 bot token(`xoxb-...`)。 -- `sutBotToken` — **SUT** 应用的 bot token(`xoxb-...`),它必须是与 driver 分离的 Slack 应用,这样它的 bot 用户 id 才会不同。 -- `sutAppToken` — SUT 应用的应用级 token(`xapp-...`),带有 `connections:write`,供 Socket Mode 使用,使 SUT 应用能够接收事件。 +- `channelId` — 两个机器人都被邀请加入的频道的 `Cxxxxxxxxxx` id。请使用专用频道;该通道每次运行都会发帖。 +- `driverBotToken` — **Driver** 应用的机器人令牌(`xoxb-...`)。 +- `sutBotToken` — **SUT** 应用的机器人令牌(`xoxb-...`),它必须是与 driver 分开的 Slack 应用,以便其机器人用户 id 不同。 +- `sutAppToken` — SUT 应用的应用级令牌(`xapp-...`),带有 `connections:write`,供 Socket Mode 使用,以便 SUT 应用可以接收事件。 -相比复用生产工作区,更推荐使用专门用于 QA 的 Slack 工作区。 +建议使用专用于 QA 的 Slack 工作区,而不是复用生产工作区。 -下面的 SUT manifest 映射了内置 Slack 插件的生产安装(`extensions/slack/src/setup-shared.ts:10`)。关于用户看到的生产渠道设置,请参阅 [Slack 渠道快速设置](/zh-CN/channels/slack#quick-setup);QA Driver/SUT 对有意分开,因为该 lane 需要在同一个工作区中有两个不同的 bot 用户 id。 +下面的 SUT 清单与内置 Slack 插件的生产安装保持一致(`extensions/slack/src/setup-shared.ts:10`)。关于用户看到的生产频道设置,请参见 [Slack 频道快速设置](/zh-CN/channels/slack#quick-setup);QA Driver/SUT 组合是有意分开的,因为该通道需要在同一工作区中有两个不同的机器人用户 id。 **1. 创建 Driver 应用** -前往 [api.slack.com/apps](https://api.slack.com/apps) → _Create New App_ → _From a manifest_ → 选择 QA 工作区,粘贴以下 manifest,然后点击 _Install to Workspace_: +前往 [api.slack.com/apps](https://api.slack.com/apps) → _Create New App_ → _From a manifest_ → 选择 QA 工作区,粘贴以下清单,然后 _Install to Workspace_: ```json { @@ -320,11 +322,11 @@ pnpm openclaw qa slack } ``` -复制 _Bot User OAuth Token_(`xoxb-...`)— 它会成为 `driverBotToken`。driver 只需要发布消息并识别自身;不需要事件,也不需要 Socket Mode。 +复制 _Bot User OAuth Token_(`xoxb-...`)— 它会成为 `driverBotToken`。driver 只需要发送消息并识别自己;不需要事件,也不需要 Socket Mode。 **2. 创建 SUT 应用** -在同一个工作区中重复 _Create New App → From a manifest_。scope 集合映射了内置 Slack 插件的生产安装(`extensions/slack/src/setup-shared.ts:10`): +在同一工作区中重复 _Create New App → From a manifest_。scope 集合与内置 Slack 插件的生产安装保持一致(`extensions/slack/src/setup-shared.ts:10`): ```json { @@ -395,12 +397,12 @@ pnpm openclaw qa slack } ``` -Slack 创建应用后,在其设置页面执行两项操作: +Slack 创建应用后,在其设置页面执行两件事: - _Install to Workspace_ → 复制 _Bot User OAuth Token_ → 它会成为 `sutBotToken`。 - _Basic Information → App-Level Tokens → Generate Token and Scopes_ → 添加 scope `connections:write` → 保存 → 复制 `xapp-...` 值 → 它会成为 `sutAppToken`。 -通过对每个 token 调用 `auth.test` 来验证这两个机器人具有不同的用户 ID。运行时通过用户 ID 区分 driver 和 SUT;如果两者复用同一个应用,提及门控会立即失败。 +通过对每个 token 调用 `auth.test`,确认两个机器人具有不同的用户 ID。运行时通过用户 ID 区分驱动端和 SUT;两者复用同一个应用会导致提及门控立即失败。 **3. 创建渠道** @@ -411,13 +413,13 @@ Slack 创建应用后,在其设置页面执行两项操作: /invite @OpenClaw QA SUT ``` -从 _渠道信息 → 关于 → 渠道 ID_ 复制 `Cxxxxxxxxxx` ID,这会成为 `channelId`。公共渠道可用;如果你使用私有渠道,两个应用都已经有 `groups:history`,因此 harness 的历史读取仍会成功。 +从 _channel info → About → Channel ID_ 复制 `Cxxxxxxxxxx` ID,这会成为 `channelId`。公开渠道可用;如果你使用私有渠道,两个应用已经具有 `groups:history`,因此 harness 的历史读取仍会成功。 **4. 注册凭证** -有两种选择。单机调试时使用环境变量(设置四个 `OPENCLAW_QA_SLACK_*` 变量并传入 `--credential-source env`),或者为共享 Convex 池播种,让 CI 和其他维护者可以租用它们。 +有两个选项。单机调试使用环境变量(设置四个 `OPENCLAW_QA_SLACK_*` 变量并传入 `--credential-source env`),或者填充共享 Convex 池,以便 CI 和其他维护者可以租用它们。 -对于 Convex 池,将四个字段写入 JSON 文件: +对于 Convex 池,将四个字段写入一个 JSON 文件: ```json { @@ -428,7 +430,7 @@ Slack 创建应用后,在其设置页面执行两项操作: } ``` -在你的 shell 中导出 `OPENCLAW_QA_CONVEX_SITE_URL` 和 `OPENCLAW_QA_CONVEX_SECRET_MAINTAINER` 后,注册并验证: +在 shell 中导出 `OPENCLAW_QA_CONVEX_SITE_URL` 和 `OPENCLAW_QA_CONVEX_SECRET_MAINTAINER` 后,注册并验证: ```bash pnpm openclaw qa credentials add \ @@ -439,11 +441,11 @@ pnpm openclaw qa credentials add \ pnpm openclaw qa credentials list --kind slack --status all --json ``` -预期 `count: 1`、`status: "active"`,且没有 `lease` 字段。 +预期结果为 `count: 1`、`status: "active"`,且没有 `lease` 字段。 **5. 端到端验证** -在本地运行该 lane,确认两个机器人可以通过 broker 互相通信: +在本地运行该 lane,确认两个机器人可以通过 broker 彼此通信: ```bash pnpm openclaw qa slack \ @@ -452,19 +454,19 @@ pnpm openclaw qa slack \ --output-dir .artifacts/qa-e2e/slack-local ``` -绿色运行会在远少于 30 秒内完成,并且 `slack-qa-report.md` 会显示 `slack-canary` 和 `slack-mention-gating` 的 Status 都是 `pass`。如果该 lane 挂起约 90 秒后以 `Convex credential pool exhausted for kind "slack"` 退出,说明池为空或每一行都已被租用,`qa credentials list --kind slack --status all --json` 会告诉你是哪种情况。 +绿色运行会在远少于 30 秒内完成,并且 `slack-qa-report.md` 会显示 `slack-canary` 和 `slack-mention-gating` 的状态均为 `pass`。如果该 lane 挂起约 90 秒后退出,并显示 `Convex credential pool exhausted for kind "slack"`,则说明池为空或每一行都已被租用,`qa credentials list --kind slack --status all --json` 会告诉你具体是哪种情况。 ### Convex 凭证池 -Telegram、Discord 和 Slack lane 可以从共享 Convex 池租用凭证,而不是读取上面的环境变量。传入 `--credential-source convex`(或设置 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`);QA Lab 会获取独占租约,在运行期间发送 Heartbeat,并在关闭时释放。池种类是 `"telegram"`、`"discord"` 和 `"slack"`。 +Telegram、Discord 和 Slack lane 可以从共享 Convex 池租用凭证,而不是读取上面的环境变量。传入 `--credential-source convex`(或设置 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`);QA Lab 会获取一个独占租约,在运行期间发送 Heartbeat,并在关闭时释放它。池类型为 `"telegram"`、`"discord"` 和 `"slack"`。 broker 在 `admin/add` 上验证的 payload 形状: -- Telegram(`kind: "telegram"`):`{ groupId: string, driverToken: string, sutToken: string }` —— `groupId` 必须是数字聊天 ID 字符串。 +- Telegram(`kind: "telegram"`):`{ groupId: string, driverToken: string, sutToken: string }`,`groupId` 必须是数字聊天 ID 字符串。 - Discord(`kind: "discord"`):`{ guildId: string, channelId: string, driverBotToken: string, sutBotToken: string, sutApplicationId: string }`。 -- Slack(`kind: "slack"`):`{ channelId: string, driverBotToken: string, sutBotToken: string, sutAppToken: string }` —— `channelId` 必须匹配 `^[A-Z][A-Z0-9]+$`(类似 `Cxxxxxxxxxx` 的 Slack ID)。有关应用和 scope 配置,请参阅 [设置 Slack 工作区](#setting-up-the-slack-workspace)。 +- Slack(`kind: "slack"`):`{ channelId: string, driverBotToken: string, sutBotToken: string, sutAppToken: string }`,`channelId` 必须匹配 `^[A-Z][A-Z0-9]+$`(类似 `Cxxxxxxxxxx` 的 Slack ID)。请参阅[设置 Slack 工作区](#setting-up-the-slack-workspace),了解应用和 scope 配置。 -操作环境变量和 Convex broker 端点契约位于 [测试 → 通过 Convex 共享 Telegram 凭证](/zh-CN/help/testing#shared-telegram-credentials-via-convex-v1)(该章节名称早于 Discord 支持;两种类型的 broker 语义相同)。 +操作环境变量和 Convex broker 端点契约位于[测试 → 通过 Convex 共享 Telegram 凭证](/zh-CN/help/testing#shared-telegram-credentials-via-convex-v1)(该章节名称早于 Discord 支持;两种类型的 broker 语义相同)。 ## 仓库支持的种子 @@ -473,102 +475,102 @@ broker 在 `admin/add` 上验证的 payload 形状: - `qa/scenarios/index.md` - `qa/scenarios//*.md` -这些内容有意放在 git 中,让 QA 计划对人类和智能体都可见。 +这些内容有意放在 git 中,以便 QA 计划同时对人类和智能体可见。 -`qa-lab` 应保持为通用的 Markdown runner。每个场景 Markdown 文件都是一次测试运行的事实来源,并应定义: +`qa-lab` 应保持为通用 Markdown 运行器。每个场景 Markdown 文件都是一次测试运行的事实来源,并应定义: - 场景元数据 - 可选的类别、能力、lane 和风险元数据 - 文档和代码引用 -- 可选插件要求 -- 可选 Gateway 网关配置 patch +- 可选的插件要求 +- 可选的 Gateway 网关配置补丁 - 可执行的 `qa-flow` -支撑 `qa-flow` 的可复用运行时表面可以保持通用且跨领域。例如,Markdown 场景可以将传输侧 helper 与浏览器侧 helper 组合起来,后者通过 Gateway 网关 `browser.request` seam 驱动嵌入式 Control UI,而不需要添加特例 runner。 +支撑 `qa-flow` 的可复用运行时表面允许保持通用且横切。例如,Markdown 场景可以将传输侧 helper 与浏览器侧 helper 结合使用,通过 Gateway 网关 `browser.request` 接缝驱动嵌入式 Control UI,而无需添加特例运行器。 -场景文件应按产品能力分组,而不是按源码树文件夹分组。文件移动时保持场景 ID 稳定;使用 `docsRefs` 和 `codeRefs` 实现实现可追溯性。 +场景文件应按产品能力分组,而不是按源码树文件夹分组。文件移动时保持场景 ID 稳定;使用 `docsRefs` 和 `codeRefs` 实现实现可追踪性。 -基线列表应保持足够宽,以覆盖: +基线列表应保持足够广泛,以覆盖: - 私信和渠道聊天 - 线程行为 - 消息操作生命周期 - cron 回调 -- 记忆召回 +- 记忆回忆 - 模型切换 -- subagent handoff +- 子智能体交接 - 仓库读取和文档读取 - 一个小型构建任务,例如 Lobster Invaders -## 提供商 mock lane +## 提供商模拟 lane -`qa suite` 有两个本地提供商 mock lane: +`qa suite` 有两个本地提供商模拟 lane: -- `mock-openai` 是感知场景的 OpenClaw mock。它仍是仓库支持的 QA 和 parity gate 的默认确定性 mock lane。 -- `aimock` 会启动一个 AIMock 支持的提供商服务器,用于实验性协议、fixture、录制/回放和 chaos 覆盖。它是增量补充,不会替代 `mock-openai` 场景 dispatcher。 +- `mock-openai` 是具备场景感知能力的 OpenClaw 模拟。它仍然是仓库支持 QA 和一致性门禁的默认确定性模拟 lane。 +- `aimock` 会启动一个 AIMock 支持的提供商服务器,用于实验性协议、fixture、录制/回放和 chaos 覆盖。它是增量能力,不会替代 `mock-openai` 场景调度器。 -提供商 lane 实现位于 `extensions/qa-lab/src/providers/` 下。每个提供商拥有自己的默认值、本地服务器启动、Gateway 网关模型配置、auth-profile 暂存需求,以及 live/mock 能力标志。共享 suite 和 Gateway 网关代码应通过提供商 registry 路由,而不是按提供商名称分支。 +提供商 lane 实现位于 `extensions/qa-lab/src/providers/` 下。每个提供商拥有自己的默认值、本地服务器启动、Gateway 网关模型配置、auth-profile 暂存需求,以及 live/mock 能力标志。共享 suite 和 Gateway 网关代码应通过提供商注册表进行路由,而不是按提供商名称分支。 ## 传输适配器 -`qa-lab` 为 Markdown QA 场景拥有一个通用传输 seam。`qa-channel` 是该 seam 上的第一个适配器,但设计目标更广:未来的真实或合成渠道应接入同一个 suite runner,而不是添加传输专用的 QA runner。 +`qa-lab` 为 Markdown QA 场景拥有一个通用传输接缝。`qa-channel` 是该接缝上的第一个适配器,但设计目标更广:未来真实或合成渠道应接入同一个 suite 运行器,而不是添加传输特定的 QA 运行器。 -在架构层面,拆分如下: +在架构层面,划分如下: -- `qa-lab` 负责通用场景执行、worker 并发、artifact 写入和报告。 -- 传输适配器负责 Gateway 网关配置、就绪状态、入站和出站观察、传输操作,以及规范化传输状态。 +- `qa-lab` 拥有通用场景执行、worker 并发、artifact 写入和报告。 +- 传输适配器拥有 Gateway 网关配置、就绪状态、入站和出站观察、传输操作以及归一化传输状态。 - `qa/scenarios/` 下的 Markdown 场景文件定义测试运行;`qa-lab` 提供执行它们的可复用运行时表面。 ### 添加渠道 -向 Markdown QA 系统添加一个渠道只需要两件事: +向 Markdown QA 系统添加渠道只需要两件事: 1. 该渠道的传输适配器。 2. 覆盖渠道契约的场景包。 -当共享的 `qa-lab` host 可以拥有该流程时,不要添加新的顶层 QA 命令根。 +当共享 `qa-lab` 宿主能够拥有该流程时,不要添加新的顶层 QA 命令根。 -`qa-lab` 拥有共享 host 机制: +`qa-lab` 拥有共享宿主机制: - `openclaw qa` 命令根 -- suite 启动和 teardown +- suite 启动和清理 - worker 并发 - artifact 写入 - 报告生成 - 场景执行 - 旧版 `qa-channel` 场景的兼容别名 -Runner 插件拥有传输契约: +运行器插件拥有传输契约: -- `openclaw qa ` 如何挂载在共享 `qa` 根之下 -- Gateway 网关如何为该传输配置 +- 如何将 `openclaw qa ` 挂载到共享 `qa` 根下 +- 如何为该传输配置 Gateway 网关 - 如何检查就绪状态 - 如何注入入站事件 - 如何观察出站消息 -- 如何暴露 transcript 和规范化传输状态 +- 如何暴露 transcript 和归一化传输状态 - 如何执行传输支持的操作 -- 如何处理传输专用 reset 或清理 +- 如何处理传输特定的重置或清理 -新渠道的最低采纳门槛: +新渠道的最低采用标准: 1. 保持 `qa-lab` 作为共享 `qa` 根的所有者。 -2. 在共享 `qa-lab` host seam 上实现传输 runner。 -3. 将传输专用机制保留在 runner 插件或渠道 harness 内。 -4. 将 runner 挂载为 `openclaw qa `,而不是注册一个竞争性的根命令。Runner 插件应在 `openclaw.plugin.json` 中声明 `qaRunners`,并从 `runtime-api.ts` 导出匹配的 `qaRunnerCliRegistrations` 数组。保持 `runtime-api.ts` 轻量;惰性 CLI 和 runner 执行应留在单独入口点之后。 -5. 在主题化的 `qa/scenarios/` 目录下编写或改编 Markdown 场景。 -6. 为新场景使用通用场景 helper。 -7. 保持现有兼容别名可用,除非仓库正在进行有意的迁移。 +2. 在共享 `qa-lab` 宿主接缝上实现传输运行器。 +3. 将传输特定机制保留在运行器插件或渠道 harness 内。 +4. 将运行器挂载为 `openclaw qa `,而不是注册竞争性的根命令。运行器插件应在 `openclaw.plugin.json` 中声明 `qaRunners`,并从 `runtime-api.ts` 导出匹配的 `qaRunnerCliRegistrations` 数组。保持 `runtime-api.ts` 轻量;惰性 CLI 和运行器执行应位于单独入口点之后。 +5. 在按主题划分的 `qa/scenarios/` 目录下编写或改写 Markdown 场景。 +6. 对新场景使用通用场景 helper。 +7. 除非仓库正在进行有意迁移,否则保持现有兼容别名可用。 决策规则很严格: -- 如果行为可以在 `qa-lab` 中表达一次,就放到 `qa-lab` 中。 -- 如果行为依赖某一个渠道传输,就将它保留在对应 runner 插件或插件 harness 中。 -- 如果某个场景需要一个可被多个渠道使用的新能力,则添加通用 helper,而不是在 `suite.ts` 中添加渠道专用分支。 -- 如果某个行为只对一个传输有意义,则保持该场景为传输专用,并在场景契约中明确说明。 +- 如果行为可以在 `qa-lab` 中表达一次,就放入 `qa-lab`。 +- 如果行为依赖于某一个渠道传输,就将其保留在该运行器插件或插件 harness 中。 +- 如果某个场景需要一个可被多个渠道使用的新能力,请添加通用 helper,而不是在 `suite.ts` 中添加渠道特定分支。 +- 如果某个行为只对一种传输有意义,请保持该场景传输特定,并在场景契约中明确这一点。 ### 场景 helper 名称 -新场景的首选通用 helper: +新场景首选的通用 helper: - `waitForTransportReady` - `waitForChannelReady` @@ -583,20 +585,21 @@ Runner 插件拥有传输契约: - `formatTransportTranscript` - `resetTransport` -现有场景仍可使用兼容别名:`waitForQaChannelReady`、`waitForOutboundMessage`、`waitForNoOutbound`、`formatConversationTranscript`、`resetBus`,但新场景编写应使用通用名称。这些别名用于避免一次性迁移,而不是未来的模型。 +现有场景仍可使用兼容别名:`waitForQaChannelReady`、`waitForOutboundMessage`、`waitForNoOutbound`、`formatConversationTranscript`、`resetBus`,但新场景编写应使用通用名称。这些别名的存在是为了避免一次性迁移,而不是未来的模型。 ## 报告 -`qa-lab` 会根据观察到的 bus timeline 导出 Markdown 协议报告。报告应回答: +`qa-lab` 会从观察到的 bus 时间线导出 Markdown 协议报告。 +该报告应回答: -- 哪些内容有效 -- 哪些内容失败 -- 哪些内容仍被阻塞 +- 哪些有效 +- 哪些失败 +- 哪些仍被阻塞 - 哪些后续场景值得添加 -如需查看可用场景清单(在评估后续工作规模或接入新传输时很有用),运行 `pnpm openclaw qa coverage`(添加 `--json` 可获得机器可读输出)。 +要查看可用场景清单,这在评估后续工作规模或接入新传输时很有用,请运行 `pnpm openclaw qa coverage`(添加 `--json` 可获得机器可读输出)。 -如需进行角色和风格检查,请在多个 live 模型引用上运行同一个场景,并写入经过评审的 Markdown 报告: +对于角色和风格检查,请在多个 live 模型引用上运行同一场景,并写入经过评审的 Markdown 报告: ```bash pnpm openclaw qa character-eval \ @@ -615,16 +618,16 @@ pnpm openclaw qa character-eval \ --judge-concurrency 16 ``` -该命令运行本地 QA Gateway 网关子进程,而不是 Docker。角色评测场景应通过 `SOUL.md` 设置 persona,然后运行普通用户轮次,例如聊天、工作区帮助和小文件任务。不应告知候选模型它正在接受评测。该命令会保留每份完整 transcript,记录基本运行统计,然后以快速模式请求 judge models,并在支持的情况下使用 `xhigh` reasoning,按自然度、氛围和幽默感对运行结果排序。比较提供商时使用 `--blind-judge-models`:judge prompt 仍会获取每份 transcript 和运行状态,但候选引用会替换为中性标签,例如 `candidate-01`;报告会在解析后将排名映射回真实引用。 -候选运行默认使用 `high` thinking,GPT-5.5 使用 `medium`,较旧且支持的 OpenAI eval 引用使用 `xhigh`。可用 `--model provider/model,thinking=` 内联覆盖特定候选。`--thinking ` 仍会设置全局 fallback,较旧的 `--model-thinking ` 形式会保留以兼容。 -OpenAI 候选引用默认使用快速模式,因此在提供商支持时会使用 priority processing。当单个候选或 judge 需要覆盖时,可内联添加 `,fast`、`,no-fast` 或 `,fast=false`。仅当你想为每个候选模型强制开启快速模式时,才传入 `--fast`。候选和 judge 的耗时会记录在报告中以便基准分析,但 judge prompt 会明确说明不要按速度排名。 -候选和 judge 模型运行都默认并发数为 16。当提供商限制或本地 Gateway 网关压力导致运行噪声过大时,降低 `--concurrency` 或 `--judge-concurrency`。 -如果未传入候选 `--model`,角色评测在未传入 `--model` 时默认使用 `openai/gpt-5.5`、`openai/gpt-5.2`、`openai/gpt-5`、`anthropic/claude-opus-4-6`、`anthropic/claude-sonnet-4-6`、`zai/glm-5.1`、`moonshot/kimi-k2.5` 和 `google/gemini-3.1-pro-preview`。 -如果未传入 `--judge-model`,judge 默认使用 `openai/gpt-5.5,thinking=xhigh,fast` 和 `anthropic/claude-opus-4-6,thinking=high`。 +该命令会运行本地 QA Gateway 网关子进程,而不是 Docker。角色评估场景应通过 `SOUL.md` 设置 persona,然后运行普通用户轮次,例如聊天、工作区帮助和小型文件任务。不应告知候选模型它正在接受评估。该命令会保留每份完整 transcript,记录基本运行统计信息,然后让 judge 模型在快速模式下使用支持时的 `xhigh` 推理,根据自然度、vibe 和幽默感对运行结果进行排名。比较提供商时使用 `--blind-judge-models`:judge 提示仍会获得每份 transcript 和运行状态,但候选 ref 会替换为中性标签,例如 `candidate-01`;报告会在解析后将排名映射回真实 ref。 +候选运行默认使用 `high` thinking,GPT-5.5 使用 `medium`,较旧且支持它的 OpenAI eval ref 使用 `xhigh`。使用 `--model provider/model,thinking=` 为特定候选进行内联覆盖。`--thinking ` 仍会设置全局 fallback,旧版 `--model-thinking ` 形式会保留以保持兼容性。 +OpenAI 候选 ref 默认使用快速模式,因此在提供商支持时会使用优先处理。单个候选或 judge 需要覆盖时,可内联添加 `,fast`、`,no-fast` 或 `,fast=false`。仅当你想为每个候选模型强制开启快速模式时,才传入 `--fast`。候选和 judge 的耗时会记录在报告中用于 benchmark 分析,但 judge 提示会明确说明不要按速度排名。 +候选和 judge 模型运行默认并发数均为 16。当提供商限制或本地 Gateway 网关压力导致运行噪声过大时,请降低 `--concurrency` 或 `--judge-concurrency`。 +未传入候选 `--model` 时,角色评估默认使用 `openai/gpt-5.5`、`openai/gpt-5.2`、`openai/gpt-5`、`anthropic/claude-opus-4-6`、`anthropic/claude-sonnet-4-6`、`zai/glm-5.1`、`moonshot/kimi-k2.5` 和 `google/gemini-3.1-pro-preview`。 +未传入 `--judge-model` 时,judge 默认使用 `openai/gpt-5.5,thinking=xhigh,fast` 和 `anthropic/claude-opus-4-6,thinking=high`。 ## 相关文档 - [Matrix QA](/zh-CN/concepts/qa-matrix) - [QA Channel](/zh-CN/channels/qa-channel) - [测试](/zh-CN/help/testing) -- [仪表板](/zh-CN/web/dashboard) +- [仪表盘](/zh-CN/web/dashboard) diff --git a/docs/zh-CN/help/testing-updates-plugins.md b/docs/zh-CN/help/testing-updates-plugins.md index e9cc84f5f..9d1bcc1b2 100644 --- a/docs/zh-CN/help/testing-updates-plugins.md +++ b/docs/zh-CN/help/testing-updates-plugins.md @@ -1,34 +1,34 @@ --- read_when: - - 更改 OpenClaw 更新、Doctor、软件包验收或插件安装行为 - - 准备或批准发布候选版本 - - 调试包更新、插件依赖清理或插件安装回归问题 + - 更改 OpenClaw 更新、Doctor、包验收或插件安装行为 + - 准备或批准候选版本 + - 调试软件包更新、插件依赖清理或插件安装回归问题 sidebarTitle: Update and plugin tests -summary: OpenClaw 如何验证更新路径、包迁移以及插件安装/更新行为 +summary: OpenClaw 如何验证更新路径、包迁移和插件安装/更新行为 title: 更新和插件测试 x-i18n: - generated_at: "2026-05-04T20:59:52Z" + generated_at: "2026-05-05T04:26:56Z" model: gpt-5.5 provider: openai - source_hash: e83a847c76f424199b5fccbd9a2b30d0bf01e4f466c4f9822bf7693d1c2ad286 + source_hash: 3e5dbc85d567b9aec07d13e309d45da45d9088fb41dcbb2a07dae69dca6b09af source_path: help/testing-updates-plugins.md workflow: 16 --- -这是更新和插件验证的专用检查清单。目标很简单:证明可安装包能够更新真实用户状态,通过 `doctor` 修复过时的旧版状态,并且仍然能从受支持来源安装、加载、更新和卸载插件。 +这是更新和插件验证的专用检查清单。目标很简单:证明可安装包可以更新真实用户状态,通过 `doctor` 修复过时的旧版状态,并且仍然可以从受支持的来源安装、加载、更新和卸载插件。 -如需更广泛的测试运行器映射,请参阅[测试](/zh-CN/help/testing)。如需实时提供商密钥和会触达网络的套件,请参阅[实时测试](/zh-CN/help/testing-live)。 +关于更广泛的测试运行器映射,请参阅[测试](/zh-CN/help/testing)。关于 live 提供商密钥和会访问网络的套件,请参阅 [live 测试](/zh-CN/help/testing-live)。 ## 我们保护什么 -更新和插件测试保护这些契约: +更新和插件测试保护以下契约: -- 包 tarball 完整,包含有效的 `dist/postinstall-inventory.json`,并且不依赖未打包的仓库文件。 -- 用户可以从较旧的已发布包迁移到候选包,而不会丢失配置、智能体、会话、工作区、插件允许列表或渠道配置。 -- `openclaw doctor --fix --non-interactive` 负责旧版清理和修复路径。启动过程不应为过时插件状态增加隐藏的兼容性迁移。 +- 包 tarball 是完整的,包含有效的 `dist/postinstall-inventory.json`,且不依赖未打包的仓库文件。 +- 用户可以从较旧的已发布包迁移到候选包,而不会丢失配置、智能体、会话、工作区、插件 allowlist 或渠道配置。 +- `openclaw doctor --fix --non-interactive` 负责旧版清理和修复路径。启动流程不应为过时的插件状态增加隐藏的兼容性迁移。 - 插件安装可从本地目录、git 仓库、npm 包和 ClawHub 注册表路径正常工作。 -- 插件 npm 依赖安装在受管理的 npm 根目录中,在信任前会被扫描,并在卸载期间通过 npm 移除,因此提升安装的依赖不会残留。 -- 当没有任何变化时,插件更新保持稳定:安装记录、解析后的来源、已安装依赖布局和启用状态都保持完整。 +- 插件 npm 依赖会安装到托管 npm 根目录,在信任前被扫描,并在卸载时通过 npm 移除,以免提升安装的依赖残留。 +- 当没有变化时,插件更新保持稳定:安装记录、解析后的来源、已安装依赖布局和启用状态都保持不变。 ## 开发期间的本地证明 @@ -40,23 +40,23 @@ pnpm check:changed pnpm test:changed ``` -对于插件安装、卸载、依赖或包清单变更,还要运行覆盖已编辑边界的聚焦测试: +对于插件安装、卸载、依赖或包清单变更,还要运行覆盖已编辑接缝的聚焦测试: ```bash pnpm test src/plugins/uninstall.test.ts src/infra/package-dist-inventory.test.ts test/scripts/package-acceptance-workflow.test.ts ``` -在任何包 Docker 通道消费 tarball 之前,先证明包构件: +在任何包 Docker 通道消费 tarball 之前,先证明包产物: ```bash pnpm release:check ``` -`release:check` 会运行配置/文档/API 漂移检查,写入包 dist 清单,运行 `npm pack --dry-run`,拒绝被禁止打包的文件,将 tarball 安装到临时前缀中,运行 postinstall,并对内置渠道入口点执行冒烟测试。 +`release:check` 会运行配置/文档/API 漂移检查,写入包 dist 清单,运行 `npm pack --dry-run`,拒绝被禁止的打包文件,将 tarball 安装到临时 prefix,运行 postinstall,并对内置渠道入口点做冒烟测试。 ## Docker 通道 -Docker 通道是产品级证明。它们会在 Linux 容器内安装或更新真实包,并通过 CLI 命令、Gateway 网关启动、HTTP 探测、RPC Status 和文件系统状态断言行为。 +Docker 通道是产品级证明。它们会在 Linux 容器中安装或更新真实包,并通过 CLI 命令、Gateway 网关启动、HTTP 探测、RPC 状态和文件系统状态断言行为。 迭代时使用聚焦通道: @@ -71,14 +71,14 @@ pnpm test:docker:update-migration 重要通道: -- `test:docker:plugins` 验证插件安装冒烟测试、本地文件夹安装、本地文件夹更新跳过行为、带预安装依赖的本地文件夹、`file:` 包安装、带 CLI 执行的 git 安装、git 移动引用更新、带提升传递依赖的 npm 注册表安装、npm 更新空操作、本地 ClawHub fixture 安装和更新空操作、marketplace 更新行为,以及 Claude 包启用/检查。设置 `OPENCLAW_PLUGINS_E2E_CLAWHUB=0` 可让 ClawHub 区块保持封闭/离线。 -- `test:docker:plugin-lifecycle-matrix` 在裸容器中安装候选包,让一个 npm 插件经过安装、检查、禁用、启用、显式升级、显式降级,以及删除插件代码后的卸载。它会记录每个阶段的 RSS 和 CPU 指标。 -- `test:docker:plugin-update` 验证未变更的已安装插件在 `openclaw plugins update` 期间不会重新安装或丢失安装元数据。 -- `test:docker:upgrade-survivor` 将候选 tarball 安装到脏的旧用户 fixture 之上,运行包更新和非交互式 Doctor,然后启动 local loopback Gateway 网关并检查状态保留情况。 -- `test:docker:published-upgrade-survivor` 首先安装一个已发布基线,通过内置的 `openclaw config set` 配方对其进行配置,将其更新到候选 tarball,运行 Doctor,检查旧版清理,启动 Gateway 网关,并探测 `/healthz`、`/readyz` 和 RPC Status。 -- `test:docker:update-migration` 是清理密集型的已发布更新通道。它从已配置的 Discord/Telegram 风格用户状态开始,运行基线 Doctor,让已配置的插件依赖有机会落地,为已配置的打包插件植入旧版插件依赖残留,更新到候选 tarball,并要求更新后的 Doctor 移除旧版依赖根目录。 +- `test:docker:plugins` 验证插件安装冒烟、本地文件夹安装、本地文件夹更新跳过行为、带预装依赖的本地文件夹、`file:` 包安装、带 CLI 执行的 git 安装、git 移动引用更新、带提升安装的传递依赖的 npm 注册表安装、npm 更新空操作、本地 ClawHub fixture 安装和更新空操作、市场更新行为,以及 Claude bundle 启用/检查。设置 `OPENCLAW_PLUGINS_E2E_CLAWHUB=0` 可让 ClawHub 块保持 hermetic/离线。 +- `test:docker:plugin-lifecycle-matrix` 在裸容器中安装候选包,运行一个 npm 插件,覆盖安装、检查、禁用、启用、显式升级、显式降级,以及删除插件代码后的卸载。它会记录每个阶段的 RSS 和 CPU 指标。 +- `test:docker:plugin-update` 验证未变化的已安装插件在 `openclaw plugins update` 期间不会重新安装或丢失安装元数据。 +- `test:docker:upgrade-survivor` 将候选 tarball 安装到脏旧用户 fixture 之上,运行包更新和非交互式 doctor,然后启动 local loopback Gateway 网关并检查状态保留。 +- `test:docker:published-upgrade-survivor` 首先安装已发布基线,通过内置的 `openclaw config set` 配方进行配置,将其更新到候选 tarball,运行 doctor,检查旧版清理,启动 Gateway 网关,并探测 `/healthz`、`/readyz` 和 RPC 状态。 +- `test:docker:update-migration` 是清理密集型的已发布更新通道。它从已配置的 Discord/Telegram 风格用户状态开始,运行基线 doctor,使已配置插件依赖有机会物化,为已配置的打包插件植入旧版插件依赖碎片,更新到候选 tarball,并要求更新后 doctor 移除旧版依赖根目录。 -有用的已发布升级幸存者变体: +实用的已发布升级 survivor 变体: ```bash OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC=openclaw@2026.4.23 \ @@ -90,9 +90,9 @@ OPENCLAW_UPGRADE_SURVIVOR_SCENARIO=bootstrap-persona \ pnpm test:docker:published-upgrade-survivor ``` -可用场景包括 `base`、`feishu-channel`、`bootstrap-persona`、`plugin-deps-cleanup`、`configured-plugin-installs`、`stale-source-plugin-shadow`、`tilde-log-path` 和 `versioned-runtime-deps`。在聚合运行中,`OPENCLAW_UPGRADE_SURVIVOR_SCENARIOS=reported-issues` 会展开为所有呈现为已报告问题形态的场景,包括已配置插件安装迁移。 +可用场景包括 `base`、`feishu-channel`、`bootstrap-persona`、`plugin-deps-cleanup`、`configured-plugin-installs`、`stale-source-plugin-shadow`、`tilde-log-path` 和 `versioned-runtime-deps`。在聚合运行中,`OPENCLAW_UPGRADE_SURVIVOR_SCENARIOS=reported-issues` 会扩展为所有报告问题形态的场景,包括已配置插件安装迁移。 -完整更新迁移有意与完整发布 CI 分离。当发布问题是“从 `2026.4.23` 起每个已发布稳定版本是否都能更新到此候选版本并清理插件依赖残留?”时,请使用手动 `Update Migration` workflow: +完整更新迁移有意与 Full Release CI 分开。当发布问题是“从 2026.4.23 起的每个已发布稳定版本是否都能更新到此候选版本并清理插件依赖碎片?”时,请使用手动 `Update Migration` workflow: ```bash gh workflow run update-migration.yml \ @@ -103,38 +103,40 @@ gh workflow run update-migration.yml \ -f scenarios=plugin-deps-cleanup ``` -## 包验收 +## Package Acceptance -包验收是 GitHub 原生包门禁。它会将一个候选包解析为 `package-under-test` tarball,记录版本和 SHA-256,然后针对该精确 tarball 运行可复用 Docker E2E 通道。workflow harness 引用与包源码引用分离,因此当前测试逻辑可以验证较旧的受信任版本。 +Package Acceptance 是 GitHub 原生包关卡。它会将一个候选包解析为 `package-under-test` tarball,记录版本和 SHA-256,然后针对该精确 tarball 运行可复用的 Docker E2E 通道。workflow harness ref 与包来源 ref 分离,因此当前测试逻辑可以验证较旧的受信任版本。 候选来源: - `source=npm`:验证 `openclaw@beta`、`openclaw@latest` 或精确的已发布版本。 -- `source=ref`:使用选定的当前 harness 打包受信任的分支、标签或提交。 +- `source=ref`:使用选定的当前 harness 打包受信任分支、标签或提交。 - `source=url`:验证 HTTPS tarball,并要求提供 `package_sha256`。 - `source=artifact`:复用另一个 Actions 运行上传的 tarball。 -完整发布验证默认使用 `source=artifact`,基于解析后的发布 SHA 构建。对于发布后证明,传入 `package_acceptance_package_spec=openclaw@YYYY.M.D`,让同一升级矩阵以已发布的 npm 包为目标。 +Full Release Validation 默认使用 `source=artifact`,从解析出的发布 SHA 构建。对于发布后证明,传入 `package_acceptance_package_spec=openclaw@YYYY.M.D`,让同一升级矩阵改为目标已发布 npm 包。 -发布检查会用包/更新/插件集合调用包验收: +发布检查会使用包/更新/插件集合调用 Package Acceptance: ```text doctor-switch update-channel-switch upgrade-survivor published-upgrade-survivor plugins-offline plugin-update ``` -它们还会传入: +启用发布 soak 时,它们还会传入: ```text -published_upgrade_survivor_baselines=all-since-2026.4.23 +published_upgrade_survivor_baselines=last-stable-4 2026.4.23 2026.5.2 2026.4.15 published_upgrade_survivor_scenarios=reported-issues telegram_mode=mock-openai ``` -这会让包迁移、更新渠道切换、过时插件依赖清理、离线插件覆盖、插件更新行为和 Telegram 包 QA 使用同一个解析后的构件。 +这样会让包迁移、更新渠道切换、过时插件依赖清理、离线插件覆盖、插件更新行为和 Telegram 包 QA 保持在同一个已解析产物上,同时不会让默认发布包关卡遍历每个已发布版本。 -`all-since-2026.4.23` 是完整发布 CI 升级样本:从 `2026.4.23` 到 `latest` 的每个已发布到 npm 的稳定版本。对于穷尽式已发布更新迁移覆盖,请在单独的更新迁移 workflow 中使用 `all-since-2026.4.23`,而不是完整发布 CI。`release-history` 仍可用于手动更宽采样,适用于你还想包含旧版日期前锚点的情况。 +`last-stable-4` 会解析为最新四个已发布到 npm 的稳定 OpenClaw 版本。发布包验收将 `2026.4.23` 固定为第一个插件更新兼容性边界,将 `2026.5.2` 固定为插件架构变动边界,并将 `2026.4.15` 固定为较旧的 2026.4.1x 已发布更新基线;解析器会去重已包含在最新四个版本中的固定版本。对于穷尽式已发布更新迁移覆盖,请在单独的 Update Migration workflow 中使用 `all-since-2026.4.23`,而不是 Full Release CI。当你还想要旧版日期前锚点时,`release-history` 仍可用于手动更宽采样。 -在发布前验证候选包时,手动运行包 profile: +当选择多个已发布升级 survivor 基线时,可复用 Docker workflow 会将每个基线分片到自己的目标 runner job。每个基线分片仍会运行选定场景集合,但日志和产物会按基线保留,整体耗时受最慢分片限制,而不是一个大型串行 job。 + +发布前验证候选版本时,手动运行包 profile: ```bash gh workflow run package-acceptance.yml \ @@ -143,54 +145,54 @@ gh workflow run package-acceptance.yml \ -f source=npm \ -f package_spec=openclaw@beta \ -f suite_profile=package \ - -f published_upgrade_survivor_baselines=all-since-2026.4.23 \ + -f published_upgrade_survivor_baselines="last-stable-4 2026.4.23 2026.5.2 2026.4.15" \ -f published_upgrade_survivor_scenarios=reported-issues \ -f telegram_mode=mock-openai ``` -当发布问题包含 MCP 渠道、cron/subagent 清理、OpenAI web search 或 OpenWebUI 时,使用 `suite_profile=product`。只有在需要完整 Docker 发布路径覆盖时,才使用 `suite_profile=full`。 +当发布问题包含 MCP 渠道、cron/subagent 清理、OpenAI web search 或 OpenWebUI 时,使用 `suite_profile=product`。仅在需要完整 Docker 发布路径覆盖时使用 `suite_profile=full`。 -## 发布默认值 +## 发布默认项 对于候选发布版本,默认证明栈是: -1. `pnpm check:changed` 和 `pnpm test:changed`,用于源码级回归。 -2. `pnpm release:check`,用于包构件完整性。 -3. 包验收 `package` profile 或发布检查自定义包通道,用于安装/更新/插件契约。 -4. 跨 OS 发布检查,用于特定 OS 的安装器、新手引导和平台行为。 -5. 只有当变更表面触及提供商或托管服务行为时,才运行实时套件。 +1. `pnpm check:changed` 和 `pnpm test:changed` 用于源代码级回归。 +2. `pnpm release:check` 用于包产物完整性。 +3. Package Acceptance `package` profile 或 release-check 自定义包通道用于安装/更新/插件契约。 +4. Cross-OS release checks 用于特定操作系统的安装器、新手引导和平台行为。 +5. 仅当变更表面触及提供商或托管服务行为时,才运行 live 套件。 -在维护者机器上,宽范围门禁和 Docker/包产品证明应在 Testbox 中运行,除非明确要做本地证明。 +在维护者机器上,广泛关卡和 Docker/包产品证明应在 Testbox 中运行,除非明确要做本地证明。 ## 旧版兼容性 -兼容宽容范围很窄并且有时限: +兼容性宽容范围很窄且有时间限制: -- 到 `2026.4.25` 为止的包,包括 `2026.4.25-beta.*`,在包验收中可以容忍已经发布的包元数据缺口。 +- 到 `2026.4.25` 为止的包,包括 `2026.4.25-beta.*`,可以容忍 Package Acceptance 中已发布的包元数据缺口。 - 已发布的 `2026.4.26` 包可以对已经发布的本地构建元数据戳文件发出警告。 -- 后续包必须满足现代契约。同样的缺口会失败,而不是警告或跳过。 +- 后续包必须满足现代契约。相同缺口会失败,而不是警告或跳过。 -不要为这些旧形态添加新的启动迁移。添加或扩展 Doctor 修复,然后用 `upgrade-survivor` 或 `published-upgrade-survivor` 证明它。 +不要为这些旧形态添加新的启动迁移。添加或扩展 doctor 修复,然后用 `upgrade-survivor` 或 `published-upgrade-survivor` 证明它。 ## 添加覆盖 更改更新或插件行为时,在能因正确原因失败的最低层添加覆盖: -- 纯路径或元数据逻辑:源码旁的单元测试。 -- 包清单或打包文件行为:`package-dist-inventory` 或 tarball 检查器测试。 +- 纯路径或元数据逻辑:在源文件旁添加单元测试。 +- 包清单或打包文件行为:`package-dist-inventory` 或 tarball checker 测试。 - CLI 安装/更新行为:Docker 通道断言或 fixture。 - 已发布版本迁移行为:`published-upgrade-survivor` 场景。 - 注册表/包来源行为:`test:docker:plugins` fixture 或 ClawHub fixture 服务器。 -- 依赖布局或清理行为:同时断言运行时执行和文件系统边界。npm 依赖可能会被提升到受管理的 npm 根目录下,因此测试应证明该根目录被扫描/清理,而不是假设存在包本地的 `node_modules` 树。 +- 依赖布局或清理行为:同时断言运行时执行和文件系统边界。npm 依赖可能会提升安装到托管 npm 根目录下,因此测试应证明根目录会被扫描/清理,而不是假设存在包本地 `node_modules` 树。 -默认保持新的 Docker fixture 封闭。除非测试目的就是实时注册表行为,否则使用本地 fixture 注册表和假包。 +默认保持新的 Docker fixture hermetic。使用本地 fixture 注册表和假包,除非测试重点是真实注册表行为。 ## 失败分诊 -从构件身份开始: +从产物身份开始: -- 包验收 `resolve_package` 摘要:来源、版本、SHA-256 和构件名称。 -- Docker 构件:`.artifacts/docker-tests/**/summary.json`、`failures.json`、通道日志和重新运行命令。 -- 升级幸存者摘要:`.artifacts/upgrade-survivor/summary.json`,包括基线版本、候选版本、场景、阶段耗时和配方步骤。 +- Package Acceptance `resolve_package` 摘要:来源、版本、SHA-256 和产物名称。 +- Docker 产物:`.artifacts/docker-tests/**/summary.json`、`failures.json`、通道日志和重跑命令。 +- Upgrade survivor 摘要:`.artifacts/upgrade-survivor/summary.json`,包括基线版本、候选版本、场景、阶段耗时和配方步骤。 -优先使用同一个包构件重新运行失败的精确通道,而不是重新运行整个发布总括任务。 +优先使用同一包产物重跑失败的精确通道,而不是重跑整个发布总控流程。 diff --git a/docs/zh-CN/help/testing.md b/docs/zh-CN/help/testing.md index c3cc7c494..33bda8cfb 100644 --- a/docs/zh-CN/help/testing.md +++ b/docs/zh-CN/help/testing.md @@ -1,165 +1,177 @@ --- read_when: - 在本地或 CI 中运行测试 - - 为模型/提供商错误添加回归测试 + - 为模型/提供商缺陷添加回归测试 - 调试 Gateway 网关 + 智能体行为 -summary: 测试工具包:单元/e2e/实时测试套件、Docker 运行器,以及每项测试覆盖的内容 +summary: 测试工具包:unit/e2e/live 测试套件、Docker 运行器,以及每项测试覆盖的内容 title: 测试 x-i18n: - generated_at: "2026-05-04T23:56:21Z" + generated_at: "2026-05-05T04:26:55Z" model: gpt-5.5 provider: openai - source_hash: 8d051bf6a01f6caf7755ad1d7107f21ae2d440b55a65bb7f18ee4a81f5f0e3b2 + source_hash: 63f27190fb00b7091c99f64edcb990be14b1025db89bc091d9c54bd1322dda24 source_path: help/testing.md workflow: 16 --- -OpenClaw 有三个 Vitest 测试套件(单元/集成、e2e、live)和少量 Docker 运行器。本文档是一份“我们如何测试”指南: +OpenClaw 有三个 Vitest 测试套件(单元/集成、e2e、live)和一小组 +Docker runner。本文档是“我们如何测试”的指南: -- 每个套件覆盖什么(以及刻意_不_覆盖什么)。 +- 每个套件覆盖什么(以及它刻意 _不_ 覆盖什么)。 - 常见工作流(本地、推送前、调试)应运行哪些命令。 - live 测试如何发现凭证并选择模型/提供商。 - 如何为真实世界的模型/提供商问题添加回归测试。 -**QA 栈(qa-lab、qa-channel、live 传输通道)**已单独记录: +**QA 栈(qa-lab、qa-channel、live 传输通道)**另有单独文档: - [QA overview](/zh-CN/concepts/qa-e2e-automation) — 架构、命令表面、场景编写。 -- [Matrix QA](/zh-CN/concepts/qa-matrix) — `pnpm openclaw qa matrix` 参考。 -- [QA channel](/zh-CN/channels/qa-channel) — 仓库支持场景使用的合成传输插件。 +- [Matrix QA](/zh-CN/concepts/qa-matrix) — `pnpm openclaw qa matrix` 的参考。 +- [QA channel](/zh-CN/channels/qa-channel) — 由仓库支持的场景使用的合成传输插件。 -本页覆盖常规测试套件和 Docker/Parallels 运行器的运行方式。下面的 QA 专用运行器部分([QA 专用运行器](#qa-specific-runners))列出了具体的 `qa` 调用,并指回上面的参考资料。 +本页介绍如何运行常规测试套件和 Docker/Parallels runner。下面的 QA 专用 runner 部分([QA 专用 runner](#qa-specific-runners))列出了具体的 `qa` 调用,并指回上面的参考。 ## 快速开始 大多数时候: -- 完整门禁(推送前预期执行):`pnpm build && pnpm check && pnpm check:test-types && pnpm test` -- 在资源充足机器上更快运行本地完整套件:`pnpm test:max` -- 直接 Vitest 监听循环:`pnpm test:watch` -- 直接文件定位现在也会路由插件/渠道路径:`pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` -- 在迭代单个失败时,优先使用定向运行。 +- 完整门禁(推送前预期运行):`pnpm build && pnpm check && pnpm check:test-types && pnpm test` +- 在资源充足的机器上更快地运行本地完整套件:`pnpm test:max` +- 直接 Vitest 监视循环:`pnpm test:watch` +- 直接定位文件现在也会路由插件/渠道路径:`pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` +- 在迭代单个失败时,优先使用目标明确的运行。 - Docker 支持的 QA 站点:`pnpm qa:lab:up` - Linux VM 支持的 QA 通道:`pnpm openclaw qa suite --runner multipass --scenario channel-chat-baseline` -当你修改测试或想要额外信心时: +当你触碰测试或想要额外信心时: - 覆盖率门禁:`pnpm test:coverage` - E2E 套件:`pnpm test:e2e` 调试真实提供商/模型时(需要真实凭证): -- live 套件(模型 + Gateway 网关工具/图片探针):`pnpm test:live` +- live 套件(模型 + Gateway 网关工具/图片探测):`pnpm test:live` - 安静地定位一个 live 文件:`pnpm test:live -- src/agents/models.profiles.live.test.ts` -- 运行时性能报告:分派 `OpenClaw Performance`,使用 - `live_gpt54=true` 执行一个真实的 `openai/gpt-5.4` agent 回合,或使用 - `deep_profile=true` 生成 Kova CPU/堆/跟踪工件。每日定时运行会在配置 +- 运行时性能报告:分发 `OpenClaw Performance`,使用 + `live_gpt54=true` 进行一次真实的 `openai/gpt-5.4` 智能体回合,或使用 + `deep_profile=true` 生成 Kova CPU/堆/trace 工件。每日定时运行会在配置 `CLAWGRIT_REPORTS_TOKEN` 时,将 mock-provider、deep-profile 和 GPT 5.4 通道工件发布到 - `openclaw/clawgrit-reports`。mock-provider 报告还包含源码级 Gateway 网关启动、内存、 - plugin-pressure、重复 fake-model hello-loop,以及 CLI 启动数据。 + `openclaw/clawgrit-reports`。mock-provider 报告还包括源码级 Gateway 网关启动、内存、 + 插件压力、重复假模型 hello-loop,以及 CLI 启动数字。 - Docker live 模型扫描:`pnpm test:docker:live-models` - - 每个选定模型现在会运行一个文本回合和一个小型文件读取风格探针。 + - 每个选定模型现在会运行一个文本回合,以及一个小型文件读取风格探测。 元数据声明支持 `image` 输入的模型还会运行一个微型图片回合。 - 在隔离提供商故障时,可用 `OPENCLAW_LIVE_MODEL_FILE_PROBE=0` 或 - `OPENCLAW_LIVE_MODEL_IMAGE_PROBE=0` 禁用额外探针。 - - CI 覆盖范围:每日 `OpenClaw Scheduled Live And E2E Checks` 和手动 + 在隔离提供商失败时,可用 `OPENCLAW_LIVE_MODEL_FILE_PROBE=0` 或 + `OPENCLAW_LIVE_MODEL_IMAGE_PROBE=0` 禁用额外探测。 + - CI 覆盖:每日 `OpenClaw Scheduled Live And E2E Checks` 和手动 `OpenClaw Release Checks` 都会调用可复用的 live/E2E 工作流,并设置 - `include_live_suites: true`,其中包含按提供商分片的独立 Docker live 模型矩阵作业。 - - 对于聚焦的 CI 重跑,分派 `OpenClaw Live And E2E Checks (Reusable)`, + `include_live_suites: true`,其中包括按提供商分片的独立 Docker live 模型 + 矩阵任务。 + - 对于聚焦的 CI 重跑,分发 `OpenClaw Live And E2E Checks (Reusable)`, 并设置 `include_live_suites: true` 和 `live_models_only: true`。 - 将新的高信号提供商密钥添加到 `scripts/ci-hydrate-live-auth.sh`, 以及 `.github/workflows/openclaw-live-and-e2e-checks-reusable.yml` 和它的 定时/发布调用方。 -- 原生 Codex 绑定聊天冒烟测试:`pnpm test:docker:live-codex-bind` +- 原生 Codex 绑定聊天 smoke:`pnpm test:docker:live-codex-bind` - 针对 Codex app-server 路径运行 Docker live 通道,使用 `/codex bind` 绑定一个合成 Slack 私信,执行 `/codex fast` 和 - `/codex permissions`,然后验证普通回复和图片附件是否通过原生插件绑定而不是 ACP 路由。 -- Codex app-server harness 冒烟测试:`pnpm test:docker:live-codex-harness` - - 通过插件拥有的 Codex app-server harness 运行 Gateway 网关 agent 回合, - 验证 `/codex status` 和 `/codex models`,并默认执行图片、 - cron MCP、子 agent 和 Guardian 探针。在隔离其他 Codex + `/codex permissions`,然后验证普通回复和图片附件 + 通过原生插件绑定而不是 ACP 路由。 +- Codex app-server harness smoke:`pnpm test:docker:live-codex-harness` + - 通过插件拥有的 Codex app-server harness 运行 Gateway 网关智能体回合, + 验证 `/codex status` 和 `/codex models`,默认还会执行图片、 + cron MCP、子智能体和 Guardian 探测。在隔离其他 Codex app-server 失败时,可用 - `OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_PROBE=0` 禁用子 agent 探针。对于聚焦的子 agent 检查,禁用其他探针: + `OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_PROBE=0` 禁用子智能体探测。对于聚焦的子智能体检查,请禁用其他探测: `OPENCLAW_LIVE_CODEX_HARNESS_IMAGE_PROBE=0 OPENCLAW_LIVE_CODEX_HARNESS_MCP_PROBE=0 OPENCLAW_LIVE_CODEX_HARNESS_GUARDIAN_PROBE=0 OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_PROBE=1 pnpm test:docker:live-codex-harness`。 - 这会在子 agent 探针后退出,除非设置了 - `OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_ONLY=0`。 -- Crestodian 救援命令冒烟测试:`pnpm test:live:crestodian-rescue-channel` - - 消息渠道救援命令表面的可选双保险检查。它会执行 `/crestodian status`、排队一个持久模型变更、回复 `/crestodian yes`,并验证审计/配置写入路径。 -- Crestodian 规划器 Docker 冒烟测试:`pnpm test:docker:crestodian-planner` - - 在无配置容器中运行 Crestodian,并在 `PATH` 上放置假的 Claude CLI, - 验证模糊规划器回退会转换成经审计的类型化配置写入。 -- Crestodian 首次运行 Docker 冒烟测试:`pnpm test:docker:crestodian-first-run` - - 从空的 OpenClaw 状态目录启动,将裸 `openclaw` 路由到 - Crestodian,应用设置/模型/agent/Discord 插件 + SecretRef 写入, - 验证配置并核验审计条目。QA Lab 中也通过 - `pnpm openclaw qa suite --scenario crestodian-ring-zero-setup` 覆盖同一个 Ring 0 设置路径。 -- Moonshot/Kimi 成本冒烟测试:设置 `MOONSHOT_API_KEY` 后,运行 + 除非设置了 + `OPENCLAW_LIVE_CODEX_HARNESS_SUBAGENT_ONLY=0`,否则它会在子智能体探测后退出。 +- Crestodian 救援命令 smoke:`pnpm test:live:crestodian-rescue-channel` + - 对消息渠道救援命令表面的可选双保险检查。 + 它会执行 `/crestodian status`,排队一个持久化模型 + 变更,回复 `/crestodian yes`,并验证审计/配置写入路径。 +- Crestodian planner Docker smoke:`pnpm test:docker:crestodian-planner` + - 在无配置容器中运行 Crestodian,并在 `PATH` + 上提供假 Claude CLI,然后验证模糊 planner 回退会转译为经过审计的类型化 + 配置写入。 +- Crestodian 首次运行 Docker smoke:`pnpm test:docker:crestodian-first-run` + - 从空 OpenClaw 状态目录开始,将裸 `openclaw` 路由到 + Crestodian,应用设置/模型/智能体/Discord 插件 + SecretRef 写入, + 验证配置,并验证审计条目。同一个 Ring 0 设置路径也在 QA Lab 中由 + `pnpm openclaw qa suite --scenario crestodian-ring-zero-setup` 覆盖。 +- Moonshot/Kimi 成本 smoke:设置 `MOONSHOT_API_KEY` 后,运行 `openclaw models list --provider moonshot --json`,然后针对 - `moonshot/kimi-k2.6` 运行隔离的 + `moonshot/kimi-k2.6` 运行一个隔离的 `openclaw agent --local --session-id live-kimi-cost --message 'Reply exactly: KIMI_LIVE_OK' --thinking off --json`。 - 验证 JSON 报告 Moonshot/K2.6,并且助手转录保存了规范化的 `usage.cost`。 + 验证 JSON 报告 Moonshot/K2.6,并且助手转录存储规范化的 `usage.cost`。 -当你只需要一个失败用例时,优先通过下面描述的 allowlist 环境变量缩小 live 测试范围。 +当你只需要一个失败用例时,优先通过下文所述的 allowlist 环境变量来缩小 live 测试范围。 -## QA 专用运行器 +## QA 专用 runner -当你需要 QA-lab 真实度时,这些命令位于主测试套件旁边: +当你需要 QA-lab 真实感时,这些命令位于主测试套件旁边: CI 在专用工作流中运行 QA Lab。Agentic parity 嵌套在 -`QA-Lab - All Lanes` 和发布验证之下,而不是独立的 PR 工作流。 +`QA-Lab - All Lanes` 和发布验证下,而不是独立的 PR 工作流。 广泛验证应使用 `Full Release Validation`,并设置 -`rerun_group=qa-parity`,或使用 release-checks QA 组。稳定/默认发布检查会将详尽的 live/Docker 浸泡测试保留在 `run_release_soak=true` 之后; -`full` 配置会强制开启浸泡测试。`QA-Lab - All Lanes` -会在 `main` 上夜间运行,也可通过手动分派运行,并将 mock parity 通道、live +`rerun_group=qa-parity`,或使用 release-checks QA 组。稳定/默认发布 +检查会将详尽的 live/Docker soak 放在 `run_release_soak=true` 之后;`full` +profile 会强制开启 soak。`QA-Lab - All Lanes` +每晚在 `main` 上运行,也可通过手动分发运行,其中 mock parity 通道、live Matrix 通道、Convex 管理的 live Telegram 通道,以及 Convex 管理的 live Discord -通道作为并行作业。定时 QA 和发布检查会显式传递 Matrix -`--profile fast`,而 Matrix CLI 和手动工作流输入默认仍为 `all`;手动分派可将 `all` 分片为 `transport`、 -`media`、`e2ee-smoke`、`e2ee-deep` 和 `e2ee-cli` 作业。`OpenClaw Release -Checks` 会在发布批准前运行 parity 加 fast Matrix 和 Telegram 通道,发布传输检查使用 `mock-openai/gpt-5.5`,以保持确定性并避免正常提供商插件启动。这些 live 传输 -Gateway 网关会禁用记忆搜索;记忆行为仍由 QA parity 套件覆盖。 +通道会作为并行任务运行。定时 QA 和发布检查会显式传递 Matrix +`--profile fast`,而 Matrix CLI 和手动工作流输入 +默认仍为 `all`;手动分发可将 `all` 分片为 `transport`、 +`media`、`e2ee-smoke`、`e2ee-deep` 和 `e2ee-cli` 任务。`OpenClaw Release +Checks` 会在发布批准前运行 parity,以及 fast Matrix 和 Telegram 通道, +并使用 `mock-openai/gpt-5.5` 进行发布传输检查,使其保持 +确定性并避免普通提供商插件启动。这些 live 传输 +Gateway 网关会禁用记忆搜索;记忆行为仍由 QA parity +套件覆盖。 完整发布 live 媒体分片使用 -`ghcr.io/openclaw/openclaw-live-media-runner:ubuntu-24.04`,其中已经包含 +`ghcr.io/openclaw/openclaw-live-media-runner:ubuntu-24.04`,其中已包含 `ffmpeg` 和 `ffprobe`。Docker live 模型/后端分片使用共享的 -`ghcr.io/openclaw/openclaw-live-test:` 镜像,该镜像会针对选定 -commit 构建一次,然后使用 `OPENCLAW_SKIP_DOCKER_BUILD=1` 拉取它,而不是在每个分片内重新构建。 +`ghcr.io/openclaw/openclaw-live-test:` 镜像,该镜像会为每个选定 +提交构建一次,然后通过 `OPENCLAW_SKIP_DOCKER_BUILD=1` 拉取它,而不是在每个分片 +内部重新构建。 - `pnpm openclaw qa suite` - - 直接在主机上运行基于仓库的 QA 场景。 - - 默认使用隔离的 Gateway 网关 worker 并行运行多个选定场景。`qa-channel` 默认并发数为 4(受选定场景数量限制)。使用 `--concurrency ` 调整 worker 数量,或使用 `--concurrency 1` 运行较旧的串行测试线。 - - 任何场景失败时都会以非零状态退出。如果你想要产物但不想要失败退出码,请使用 `--allow-failures`。 - - 支持提供商模式 `live-frontier`、`mock-openai` 和 `aimock`。`aimock` 会启动一个由本地 AIMock 支持的提供商服务器,用于实验性 fixture 和协议模拟覆盖,同时不会替代感知场景的 `mock-openai` 测试线。 + - 直接在主机上运行由仓库支持的 QA 场景。 + - 默认使用隔离的 Gateway 网关工作进程并行运行多个选定场景。`qa-channel` 默认并发数为 4(受所选场景数量限制)。使用 `--concurrency ` 调整工作进程数量,或使用 `--concurrency 1` 运行较旧的串行通道。 + - 当任一场景失败时以非零状态退出。当你想要产物但不希望退出码失败时,使用 `--allow-failures`。 + - 支持提供商模式 `live-frontier`、`mock-openai` 和 `aimock`。`aimock` 会启动一个本地 AIMock 支持的提供商服务器,用于实验性的 fixture 和协议 mock 覆盖,而不替换感知场景的 `mock-openai` 通道。 - `pnpm test:plugins:kitchen-sink-live` - - 通过 QA Lab 运行实时 OpenAI Kitchen Sink 插件测试矩阵。它会安装外部 Kitchen Sink 包,验证插件 SDK 接口清单,探测 `/healthz` 和 `/readyz`,记录 Gateway 网关 CPU/RSS 证据,运行一次实时 OpenAI 轮次,并检查对抗性诊断。需要实时 OpenAI 凭证,例如 `OPENAI_API_KEY`。在已预置的 Testbox 会话中,如果存在 `openclaw-testbox-env` helper,它会自动加载 Testbox 实时凭证 profile。 + - 通过 QA Lab 运行实时 OpenAI Kitchen Sink 插件综合测试。它会安装外部 Kitchen Sink 包,验证插件 SDK 表面清单,探测 `/healthz` 和 `/readyz`,记录 Gateway 网关 CPU/RSS 证据,运行一次实时 OpenAI 回合,并检查对抗性诊断。需要实时 OpenAI 凭证,例如 `OPENAI_API_KEY`。在已初始化的 Testbox 会话中,当存在 `openclaw-testbox-env` 辅助工具时,它会自动加载 Testbox 实时凭证配置文件。 - `pnpm test:gateway:cpu-scenarios` - - 运行 Gateway 网关启动基准测试以及一小组模拟 QA Lab 场景包(`channel-chat-baseline`、`memory-failure-fallback`、`gateway-restart-inflight-run`),并在 `.artifacts/gateway-cpu-scenarios/` 下写入合并后的 CPU 观测摘要。 - - 默认只标记持续的高 CPU 观测(`--cpu-core-warn` 加 `--hot-wall-warn-ms`),因此短暂的启动突增会记录为指标,而不会看起来像持续数分钟的 Gateway 网关占满回归。 - - 使用已构建的 `dist` 产物;如果当前 checkout 还没有新的运行时输出,请先运行构建。 + - 运行 Gateway 网关启动基准测试以及一小组 mock QA Lab 场景包(`channel-chat-baseline`、`memory-failure-fallback`、`gateway-restart-inflight-run`),并在 `.artifacts/gateway-cpu-scenarios/` 下写入合并的 CPU 观测摘要。 + - 默认只标记持续的高 CPU 观测(`--cpu-core-warn` 加 `--hot-wall-warn-ms`),因此短暂的启动峰值会记录为指标,而不会看起来像持续数分钟的 Gateway 网关占满 CPU 回归。 + - 使用已构建的 `dist` 产物;当检出目录中还没有新的运行时输出时,请先运行构建。 - `pnpm openclaw qa suite --runner multipass` - - 在一次性 Multipass Linux VM 中运行相同的 QA 套件。 + - 在一次性 Multipass Linux VM 中运行同一套 QA 套件。 - 保持与主机上 `qa suite` 相同的场景选择行为。 - 复用与 `qa suite` 相同的提供商/模型选择标志。 - - 实时运行会转发对 guest 实用的受支持 QA 凭证输入:基于环境变量的提供商 key、QA 实时提供商配置路径,以及存在时的 `CODEX_HOME`。 - - 输出目录必须保持在仓库根目录下,以便 guest 能通过挂载的工作区写回。 + - 实时运行会转发对来宾环境可行的受支持 QA 凭证输入:基于环境变量的提供商密钥、QA 实时提供商配置路径,以及存在时的 `CODEX_HOME`。 + - 输出目录必须位于仓库根目录下,这样来宾环境才能通过挂载的工作区写回。 - 在 `.artifacts/qa-e2e/...` 下写入常规 QA 报告和摘要,以及 Multipass 日志。 - `pnpm qa:lab:up` - 启动由 Docker 支持的 QA 站点,用于操作员风格的 QA 工作。 - `pnpm test:docker:npm-onboard-channel-agent` - - 从当前 checkout 构建 npm tarball,在 Docker 中全局安装它,运行非交互式 OpenAI API key 新手引导,默认配置 Telegram,验证打包的插件运行时可以在没有启动依赖修复的情况下加载,运行 Doctor,并对模拟的 OpenAI 端点运行一次本地智能体轮次。 - - 使用 `OPENCLAW_NPM_ONBOARD_CHANNEL=discord` 以 Discord 运行相同的打包安装测试线。 + - 从当前检出构建 npm tarball,在 Docker 中全局安装它,运行非交互式 OpenAI API 密钥新手引导,默认配置 Telegram,验证打包的插件运行时在没有启动依赖修复的情况下加载,运行 Doctor,并针对 mock 的 OpenAI 端点运行一次本地智能体回合。 + - 使用 `OPENCLAW_NPM_ONBOARD_CHANNEL=discord` 通过 Discord 运行同一条打包安装通道。 - `pnpm test:docker:session-runtime-context` - - 为嵌入式运行时上下文 transcript 运行确定性的已构建应用 Docker smoke。它会验证隐藏的 OpenClaw 运行时上下文被持久化为非显示的自定义消息,而不是泄漏到可见用户轮次中,然后播种一个受影响的损坏会话 JSONL,并验证 `openclaw doctor --fix` 会将其重写到当前分支并创建备份。 + - 为嵌入式运行时上下文 transcript 运行一个确定性的已构建应用 Docker smoke。它验证隐藏的 OpenClaw 运行时上下文会作为非展示自定义消息持久化,而不是泄露到可见用户回合中,然后注入一个受影响的损坏会话 JSONL,并验证 `openclaw doctor --fix` 会带备份地将其重写到活动分支。 - `pnpm test:docker:npm-telegram-live` - - 在 Docker 中安装 OpenClaw 候选包,运行已安装包的新手引导,通过已安装的 CLI 配置 Telegram,然后复用实时 Telegram QA 测试线,并将该已安装包作为 SUT Gateway 网关。 - - 默认值为 `OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC=openclaw@beta`;设置 `OPENCLAW_NPM_TELEGRAM_PACKAGE_TGZ=/path/to/openclaw-current.tgz` 或 `OPENCLAW_CURRENT_PACKAGE_TGZ` 可测试已解析的本地 tarball,而不是从 registry 安装。 - - 使用与 `pnpm openclaw qa telegram` 相同的 Telegram 环境变量凭据或 Convex 凭据来源。对于 CI/发布自动化,设置 `OPENCLAW_NPM_TELEGRAM_CREDENTIAL_SOURCE=convex`,再加上 `OPENCLAW_QA_CONVEX_SITE_URL` 和角色 secret。如果 CI 中存在 `OPENCLAW_QA_CONVEX_SITE_URL` 和 Convex 角色 secret,Docker wrapper 会自动选择 Convex。 - - wrapper 会在 Docker 构建/安装工作之前在主机上验证 Telegram 或 Convex 凭据环境变量。仅在有意调试凭据前置设置时,才设置 `OPENCLAW_NPM_TELEGRAM_SKIP_CREDENTIAL_PREFLIGHT=1`。 - - `OPENCLAW_NPM_TELEGRAM_CREDENTIAL_ROLE=ci|maintainer` 仅为此测试线覆盖共享的 `OPENCLAW_QA_CREDENTIAL_ROLE`。 - - GitHub Actions 将此测试线公开为手动维护者 workflow `NPM Telegram Beta E2E`。它不会在合并时运行。该 workflow 使用 `qa-live-shared` 环境和 Convex CI 凭据租约。 -- GitHub Actions 还公开了 `Package Acceptance`,用于针对一个候选包进行旁路运行的产品证明。它接受受信任的 ref、已发布 npm spec、HTTPS tarball URL 加 SHA-256,或来自另一次运行的 tarball artifact,将规范化后的 `openclaw-current.tgz` 上传为 `package-under-test`,然后使用 smoke、package、product、full 或自定义测试线 profile 运行现有 Docker E2E 调度器。设置 `telegram_mode=mock-openai` 或 `live-frontier` 可让 Telegram QA workflow 针对同一个 `package-under-test` artifact 运行。 + - 在 Docker 中安装一个 OpenClaw 包候选版本,运行已安装包的新手引导,通过已安装的 CLI 配置 Telegram,然后复用实时 Telegram QA 通道,并将该已安装包作为 SUT Gateway 网关。 + - 默认值为 `OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC=openclaw@beta`;设置 `OPENCLAW_NPM_TELEGRAM_PACKAGE_TGZ=/path/to/openclaw-current.tgz` 或 `OPENCLAW_CURRENT_PACKAGE_TGZ`,可测试已解析的本地 tarball,而不是从 registry 安装。 + - 使用与 `pnpm openclaw qa telegram` 相同的 Telegram 环境变量凭证或 Convex 凭证来源。对于 CI/发布自动化,设置 `OPENCLAW_NPM_TELEGRAM_CREDENTIAL_SOURCE=convex`,并提供 `OPENCLAW_QA_CONVEX_SITE_URL` 和角色密钥。如果 CI 中存在 `OPENCLAW_QA_CONVEX_SITE_URL` 和 Convex 角色密钥,Docker 包装器会自动选择 Convex。 + - 包装器会在 Docker 构建/安装工作前,在主机上验证 Telegram 或 Convex 凭证环境变量。仅在有意调试凭证前置设置时,才设置 `OPENCLAW_NPM_TELEGRAM_SKIP_CREDENTIAL_PREFLIGHT=1`。 + - `OPENCLAW_NPM_TELEGRAM_CREDENTIAL_ROLE=ci|maintainer` 仅为此通道覆盖共享的 `OPENCLAW_QA_CREDENTIAL_ROLE`。 + - GitHub Actions 将此通道公开为手动维护者工作流 `NPM Telegram Beta E2E`。它不会在合并时运行。该工作流使用 `qa-live-shared` 环境和 Convex CI 凭证租约。 +- GitHub Actions 还公开了 `Package Acceptance`,用于针对一个候选包进行旁路产品证明。它接受受信任的 ref、已发布的 npm spec、HTTPS tarball URL 加 SHA-256,或来自另一次运行的 tarball artifact,将标准化后的 `openclaw-current.tgz` 上传为 `package-under-test`,然后使用 smoke、package、product、full 或 custom 通道配置运行现有 Docker E2E 调度器。设置 `telegram_mode=mock-openai` 或 `live-frontier`,可针对同一个 `package-under-test` 产物运行 Telegram QA 工作流。 - 最新 beta 产品证明: ```bash @@ -191,58 +203,58 @@ gh workflow run package-acceptance.yml --ref main \ ``` - `pnpm test:docker:plugins` - - 在 Docker 中打包并安装当前 OpenClaw 构建,启动配置了 OpenAI 的 Gateway 网关,然后通过配置编辑启用内置渠道/插件。 - - 验证设置发现会让未配置的可下载插件保持缺失,第一次配置后的 Doctor 修复会显式安装每个缺失的可下载插件,而第二次重启不会运行隐藏的依赖修复。 - - 还会安装一个已知的较旧 npm baseline,在运行 `openclaw update --tag ` 前启用 Telegram,并验证候选版本的更新后 Doctor 会清理旧版插件依赖残留,而不需要 harness 侧的 postinstall 修复。 + - 在 Docker 中打包并安装当前 OpenClaw 构建,启动已配置 OpenAI 的 Gateway 网关,然后通过配置编辑启用内置渠道/插件。 + - 验证设置发现会让未配置的可下载插件保持缺失状态,第一次配置后的 Doctor 修复会显式安装每个缺失的可下载插件,并且第二次重启不会运行隐藏的依赖修复。 + - 还会安装一个已知的较旧 npm 基线,在运行 `openclaw update --tag ` 前启用 Telegram,并验证候选版本的更新后 Doctor 会清理旧版插件依赖残留,而不需要 harness 侧的 postinstall 修复。 - `pnpm test:parallels:npm-update` - - 在 Parallels guest 中运行原生打包安装更新 smoke。每个选定平台会先安装请求的 baseline 包,然后在同一 guest 中运行已安装的 `openclaw update` 命令,并验证已安装版本、更新状态、Gateway 网关就绪状态,以及一次本地智能体轮次。 - - 迭代单个 guest 时使用 `--platform macos`、`--platform windows` 或 `--platform linux`。使用 `--json` 获取摘要 artifact 路径和每条测试线状态。 - - OpenAI 测试线默认使用 `openai/gpt-5.5` 进行实时智能体轮次证明。仅在有意验证另一个 OpenAI 模型时,传入 `--model ` 或设置 `OPENCLAW_PARALLELS_OPENAI_MODEL`。 - - 将长时间本地运行包在主机 timeout 中,以免 Parallels 传输停滞耗尽剩余测试窗口: + - 跨 Parallels 来宾环境运行原生打包安装更新 smoke。每个选定平台会先安装请求的基线包,然后在同一来宾环境中运行已安装的 `openclaw update` 命令,并验证已安装版本、更新状态、Gateway 网关就绪状态以及一次本地智能体回合。 + - 在迭代单个来宾环境时使用 `--platform macos`、`--platform windows` 或 `--platform linux`。使用 `--json` 获取摘要产物路径和每条通道的状态。 + - OpenAI 通道默认使用 `openai/gpt-5.5` 作为实时智能体回合证明。仅在有意验证另一个 OpenAI 模型时,传入 `--model ` 或设置 `OPENCLAW_PARALLELS_OPENAI_MODEL`。 + - 为较长的本地运行包装主机 timeout,避免 Parallels 传输停滞消耗剩余测试窗口: ```bash timeout --foreground 150m pnpm test:parallels:npm-update -- --json timeout --foreground 90m pnpm test:parallels:npm-update -- --platform windows --json ``` - - 脚本会在 `/tmp/openclaw-parallels-npm-update.*` 下写入嵌套测试线日志。在假设外层 wrapper 卡住之前,先检查 `windows-update.log`、`macos-update.log` 或 `linux-update.log`。 - - Windows 更新在冷 guest 上可能会花 10 到 15 分钟执行更新后 Doctor 和包更新工作;只要嵌套 npm debug 日志仍在前进,这仍然是健康状态。 - - 不要将此聚合 wrapper 与单独的 Parallels macOS、Windows 或 Linux smoke 测试线并行运行。它们共享 VM 状态,可能在快照恢复、包服务或 guest Gateway 网关状态上发生冲突。 - - 更新后证明会运行常规内置插件接口,因为语音、图像生成和媒体理解等能力 facade 会通过内置运行时 API 加载,即使智能体轮次本身只检查简单文本响应。 + - 该脚本会在 `/tmp/openclaw-parallels-npm-update.*` 下写入嵌套通道日志。在假定外层包装器挂起之前,请检查 `windows-update.log`、`macos-update.log` 或 `linux-update.log`。 + - 在冷启动来宾环境上,Windows 更新可能会在更新后 Doctor 和包更新工作中花费 10 到 15 分钟;只要嵌套 npm debug 日志仍在推进,这仍然是正常状态。 + - 不要将这个聚合包装器与单独的 Parallels macOS、Windows 或 Linux smoke 通道并行运行。它们共享 VM 状态,可能会在快照恢复、包服务或来宾环境 Gateway 网关状态上发生冲突。 + - 更新后证明会运行常规内置插件表面,因为 speech、image generation 和 media understanding 等能力 facade 会通过内置运行时 API 加载,即使智能体回合本身只检查简单文本响应。 - `pnpm openclaw qa aimock` - 仅启动本地 AIMock 提供商服务器,用于直接协议 smoke 测试。 - `pnpm openclaw qa matrix` - - 针对由 Docker 支持的一次性 Tuwunel homeserver 运行 Matrix 实时 QA 测试线。仅限源代码 checkout,打包安装不会随附 `qa-lab`。 - - 完整 CLI、profile/场景目录、环境变量和 artifact 布局:[Matrix QA](/zh-CN/concepts/qa-matrix)。 + - 针对一个一次性 Docker 支持的 Tuwunel homeserver 运行 Matrix 实时 QA 通道。仅支持源码检出,打包安装不包含 `qa-lab`。 + - 完整 CLI、配置文件/场景目录、环境变量和产物布局:[Matrix QA](/zh-CN/concepts/qa-matrix)。 - `pnpm openclaw qa telegram` - - 使用来自环境变量的 driver 和 SUT bot token,针对真实私有群组运行 Telegram 实时 QA 测试线。 - - 需要 `OPENCLAW_QA_TELEGRAM_GROUP_ID`、`OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKEN` 和 `OPENCLAW_QA_TELEGRAM_SUT_BOT_TOKEN`。群组 id 必须是数字 Telegram chat id。 - - 支持 `--credential-source convex` 以使用共享池化凭据。默认使用环境变量模式,或设置 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex` 以选择加入池化租约。 - - 任何场景失败时都会以非零状态退出。如果你想要产物但不想要失败退出码,请使用 `--allow-failures`。 - - 需要同一个私有群组中的两个不同 bot,且 SUT bot 需要公开 Telegram username。 - - 为获得稳定的 bot 到 bot 观测,请在 `@BotFather` 中为两个 bot 启用 Bot-to-Bot Communication Mode,并确保 driver bot 可以观测群组 bot 流量。 - - 在 `.artifacts/qa-e2e/...` 下写入 Telegram QA 报告、摘要和 observed-messages artifact。回复场景包含从 driver 发送请求到观测到 SUT 回复的 RTT。 + - 使用来自环境变量的 driver 和 SUT bot token,针对真实私有群组运行 Telegram 实时 QA 通道。 + - 需要 `OPENCLAW_QA_TELEGRAM_GROUP_ID`、`OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKEN` 和 `OPENCLAW_QA_TELEGRAM_SUT_BOT_TOKEN`。群组 ID 必须是数字形式的 Telegram chat id。 + - 支持 `--credential-source convex` 来使用共享池化凭证。默认使用环境变量模式,或设置 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex` 选择池化租约。 + - 当任一场景失败时以非零状态退出。当你想要产物但不希望退出码失败时,使用 `--allow-failures`。 + - 需要同一私有群组中的两个不同 bot,且 SUT bot 需公开 Telegram username。 + - 为获得稳定的 bot 到 bot 观测,请在 `@BotFather` 中为两个 bot 启用 Bot-to-Bot Communication Mode,并确保 driver bot 能观测群组 bot 流量。 + - 在 `.artifacts/qa-e2e/...` 下写入 Telegram QA 报告、摘要和 observed-messages 产物。回复场景包含从 driver 发送请求到观测到 SUT 回复的 RTT。 -实时传输测试线共享一个标准契约,以避免新传输发生漂移;每条测试线的覆盖矩阵位于 [QA overview → 实时传输覆盖](/zh-CN/concepts/qa-e2e-automation#live-transport-coverage)。`qa-channel` 是广泛的合成套件,不属于该矩阵。 +实时传输通道共享一份标准合约,因此新的传输协议不会漂移;每通道覆盖矩阵位于 [QA overview → 实时传输覆盖范围](/zh-CN/concepts/qa-e2e-automation#live-transport-coverage)。`qa-channel` 是广泛的合成套件,不属于该矩阵。 -### 通过 Convex 共享 Telegram 凭据(v1) +### 通过 Convex 共享 Telegram 凭证(v1) -当为 `openclaw qa telegram` 启用 `--credential-source convex`(或 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`)时,QA Lab 会从 Convex 支持的池中获取独占租约,在测试线运行期间为该租约发送 Heartbeat,并在关闭时释放租约。 +当为 `openclaw qa telegram` 启用 `--credential-source convex`(或 `OPENCLAW_QA_CREDENTIAL_SOURCE=convex`)时,QA Lab 会从 Convex 支持的池中获取一个独占租约,在该通道运行期间对租约执行 Heartbeat,并在关闭时释放租约。 -参考 Convex 项目 scaffold: +参考 Convex 项目脚手架: - `qa/convex-credential-broker/` 必需环境变量: - `OPENCLAW_QA_CONVEX_SITE_URL`(例如 `https://your-deployment.convex.site`) -- 所选角色的一个 secret: +- 所选角色的一个密钥: - `OPENCLAW_QA_CONVEX_SECRET_MAINTAINER` 用于 `maintainer` - `OPENCLAW_QA_CONVEX_SECRET_CI` 用于 `ci` -- 凭据角色选择: +- 凭证角色选择: - CLI:`--credential-role maintainer|ci` - - 环境变量默认值:`OPENCLAW_QA_CREDENTIAL_ROLE`(在 CI 中默认为 `ci`,否则为 `maintainer`) + - 环境变量默认值:`OPENCLAW_QA_CREDENTIAL_ROLE`(在 CI 中默认为 `ci`,否则默认为 `maintainer`) 可选环境变量: @@ -252,14 +264,14 @@ gh workflow run package-acceptance.yml --ref main \ - `OPENCLAW_QA_CREDENTIAL_HTTP_TIMEOUT_MS`(默认 `15000`) - `OPENCLAW_QA_CONVEX_ENDPOINT_PREFIX`(默认 `/qa-credentials/v1`) - `OPENCLAW_QA_CREDENTIAL_OWNER_ID`(可选 trace id) -- `OPENCLAW_QA_ALLOW_INSECURE_HTTP=1` 允许 local-only 开发使用 loopback `http://` Convex URL。 +- `OPENCLAW_QA_ALLOW_INSECURE_HTTP=1` 允许仅用于本地开发的 loopback `http://` Convex URL。 -`OPENCLAW_QA_CONVEX_SITE_URL` 在正常运行中应使用 `https://`。 +`OPENCLAW_QA_CONVEX_SITE_URL` 在正常运行时应使用 `https://`。 -维护者管理命令(pool add/remove/list)明确需要 +维护者管理员命令(池 add/remove/list)需要专门使用 `OPENCLAW_QA_CONVEX_SECRET_MAINTAINER`。 -面向维护者的 CLI 辅助命令: +供维护者使用的 CLI 辅助命令: ```bash pnpm openclaw qa credentials doctor @@ -268,121 +280,159 @@ pnpm openclaw qa credentials list --kind telegram pnpm openclaw qa credentials remove --credential-id ``` -在真实运行前使用 `doctor` 检查 Convex 站点 URL、代理密钥、端点前缀、HTTP 超时以及 admin/list 可达性,且不会打印密钥值。在脚本和 CI 工具中使用 `--json` 获取机器可读输出。 +在实时运行前使用 `doctor` 检查 Convex 站点 URL、broker 密钥、 +端点前缀、HTTP 超时以及 admin/list 可达性,且不会打印 +密钥值。在脚本和 CI 工具中使用 `--json` 获取机器可读输出。 默认端点契约(`OPENCLAW_QA_CONVEX_SITE_URL` + `/qa-credentials/v1`): - `POST /acquire` - 请求:`{ kind, ownerId, actorRole, leaseTtlMs, heartbeatIntervalMs }` - 成功:`{ status: "ok", credentialId, leaseToken, payload, leaseTtlMs?, heartbeatIntervalMs? }` - - 耗尽/可重试:`{ status: "error", code: "POOL_EXHAUSTED" | "NO_CREDENTIAL_AVAILABLE", ... }` + - 已耗尽/可重试:`{ status: "error", code: "POOL_EXHAUSTED" | "NO_CREDENTIAL_AVAILABLE", ... }` - `POST /heartbeat` - 请求:`{ kind, ownerId, actorRole, credentialId, leaseToken, leaseTtlMs }` - - 成功:`{ status: "ok" }`(或空 `2xx`) + - 成功:`{ status: "ok" }`(或空的 `2xx`) - `POST /release` - 请求:`{ kind, ownerId, actorRole, credentialId, leaseToken }` - - 成功:`{ status: "ok" }`(或空 `2xx`) + - 成功:`{ status: "ok" }`(或空的 `2xx`) - `POST /admin/add`(仅维护者密钥) - 请求:`{ kind, actorId, payload, note?, status? }` - 成功:`{ status: "ok", credential }` - `POST /admin/remove`(仅维护者密钥) - 请求:`{ credentialId, actorId }` - 成功:`{ status: "ok", changed, credential }` - - 活动租约保护:`{ status: "error", code: "LEASE_ACTIVE", ... }` + - 活跃租约保护:`{ status: "error", code: "LEASE_ACTIVE", ... }` - `POST /admin/list`(仅维护者密钥) - 请求:`{ kind?, status?, includePayload?, limit? }` - 成功:`{ status: "ok", credentials, count }` -Telegram 类型的 payload 形状: +Telegram 类型的载荷形状: - `{ groupId: string, driverToken: string, sutToken: string }` -- `groupId` 必须是数字 Telegram 聊天 ID 字符串。 -- `admin/add` 会针对 `kind: "telegram"` 校验此形状,并拒绝格式错误的 payload。 +- `groupId` 必须是数字形式的 Telegram 聊天 ID 字符串。 +- `admin/add` 会对 `kind: "telegram"` 校验此形状,并拒绝格式错误的载荷。 ### 向 QA 添加渠道 -新渠道适配器的架构和场景辅助程序名称位于 [QA overview → 添加渠道](/zh-CN/concepts/qa-e2e-automation#adding-a-channel)。最低要求:在共享 `qa-lab` 主机抽象层上实现传输运行器,在插件清单中声明 `qaRunners`,挂载为 `openclaw qa `,并在 `qa/scenarios/` 下编写场景。 +新渠道适配器的架构和场景辅助命名见 [QA overview → 添加渠道](/zh-CN/concepts/qa-e2e-automation#adding-a-channel)。最低要求:在共享的 `qa-lab` 主机接口上实现传输 runner,在插件清单中声明 `qaRunners`,挂载为 `openclaw qa `,并在 `qa/scenarios/` 下编写场景。 -## 测试套件(在哪里运行哪些内容) +## 测试套件(在哪里运行什么) -可以把这些套件理解为“真实度递增”(同时波动性/成本也递增): +可以把这些套件看作“真实度递增”(同时波动性/成本也递增): ### 单元 / 集成(默认) - 命令:`pnpm test` -- 配置:未指定目标的运行使用 `vitest.full-*.config.ts` 分片集合,并且可能会将多项目分片扩展为按项目配置以便并行调度 -- 文件:核心/单元清单位于 `src/**/*.test.ts`、`packages/**/*.test.ts` 和 `test/**/*.test.ts`;UI 单元测试在专用 `unit-ui` 分片中运行 +- 配置:非定向运行使用 `vitest.full-*.config.ts` 分片集合,并且可能将多项目分片展开为按项目的配置以便并行调度 +- 文件:`src/**/*.test.ts`、`packages/**/*.test.ts` 和 `test/**/*.test.ts` 下的核心/单元清单;UI 单元测试在专用的 `unit-ui` 分片中运行 - 范围: - 纯单元测试 - - 进程内集成测试(Gateway 网关身份验证、路由、工具链、解析、配置) - - 针对已知 bug 的确定性回归测试 + - 进程内集成测试(Gateway 网关认证、路由、工具、解析、配置) + - 已知 bug 的确定性回归测试 - 预期: - 在 CI 中运行 - 不需要真实密钥 - - 应快速且稳定 - - 解析器和公开接口加载器测试必须使用生成的小型插件夹具证明宽泛 `api.js` 和 `runtime-api.js` 回退行为,而不是使用真实内置插件源码 API。真实插件 API 加载属于插件自有的契约/集成套件。 + - 应当快速且稳定 + - 解析器和公共表面 loader 测试必须使用生成的微型插件 fixture 证明宽泛 `api.js` 和 + `runtime-api.js` 的 fallback 行为,而不是使用真实内置插件源 API。真实插件 API 加载应放在 + 插件自有的契约/集成套件中。 - + - - 未指定目标的 `pnpm test` 会运行十二个较小的分片配置(`core-unit-fast`、`core-unit-src`、`core-unit-security`、`core-unit-ui`、`core-unit-support`、`core-support-boundary`、`core-contracts`、`core-bundled`、`core-runtime`、`agentic`、`auto-reply`、`extensions`),而不是一个巨大的原生根项目进程。这会降低高负载机器上的峰值 RSS,并避免 auto-reply/插件工作挤占无关套件的资源。 - - `pnpm test --watch` 仍使用原生根 `vitest.config.ts` 项目图,因为多分片 watch 循环并不实际。 - - `pnpm test`、`pnpm test:watch` 和 `pnpm test:perf:imports` 会先通过限定范围的通道路由显式文件/目录目标,因此 `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` 可以避免承担完整根项目启动开销。 - - `pnpm test:changed` 默认会将已更改的 git 路径扩展到低成本的限定范围通道:直接测试编辑、同级 `*.test.ts` 文件、显式源映射以及本地导入图依赖项。除非你明确使用 `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`,否则配置/设置/package 编辑不会广泛运行测试。 - - `pnpm check:changed` 是窄范围工作的常规智能本地检查门禁。它会将 diff 分类为核心、核心测试、插件、插件测试、应用、文档、发布元数据、真实 Docker 工具和工具链,然后运行匹配的类型检查、lint 和保护命令。它不会运行 Vitest 测试;需要测试证明时调用 `pnpm test:changed` 或显式 `pnpm test `。仅发布元数据的版本号提升会运行有针对性的版本/配置/根依赖检查,并带有一个保护机制,用于拒绝顶层 version 字段以外的 package 更改。 - - 真实 Docker ACP 测试框架编辑会运行聚焦检查:真实 Docker 认证脚本的 shell 语法,以及真实 Docker 调度器 dry-run。只有当 diff 限定在 `scripts["test:docker:live-*"]` 时,才会包含 `package.json` 更改;依赖、导出、版本和其他 package 接口编辑仍使用更广泛的保护。 - - 来自智能体、命令、插件、auto-reply 辅助程序、`plugin-sdk` 以及类似纯工具区域的导入较轻单元测试会路由到 `unit-fast` 通道,该通道会跳过 `test/setup-openclaw-runtime.ts`;有状态/运行时较重的文件仍留在现有通道上。 - - 选定的 `plugin-sdk` 和 `commands` 辅助源文件也会将变更模式运行映射到这些轻量通道中的显式同级测试,因此辅助程序编辑无需重新运行该目录的完整重型套件。 - - `auto-reply` 为顶层核心辅助程序、顶层 `reply.*` 集成测试和 `src/auto-reply/reply/**` 子树设置了专用桶。CI 还会将 reply 子树拆分为 agent-runner、dispatch 和 commands/state-routing 分片,避免一个导入较重的桶占用完整 Node 尾部时间。 - - 常规 PR/main CI 会有意跳过插件批量扫描和仅发布使用的 `agentic-plugins` 分片。Full Release Validation 会为发布候选版本上的这些插件密集型套件调度单独的 `Plugin Prerelease` 子工作流。 + - 非定向 `pnpm test` 会运行十二个更小的分片配置(`core-unit-fast`、`core-unit-src`、`core-unit-security`、`core-unit-ui`、`core-unit-support`、`core-support-boundary`、`core-contracts`、`core-bundled`、`core-runtime`、`agentic`、`auto-reply`、`extensions`),而不是一个巨大的原生根项目进程。这会降低高负载机器上的峰值 RSS,并避免 auto-reply/插件工作饿死无关套件。 + - `pnpm test --watch` 仍使用原生根 `vitest.config.ts` 项目图,因为多分片 watch 循环并不实用。 + - `pnpm test`、`pnpm test:watch` 和 `pnpm test:perf:imports` 会先通过作用域 lane 路由显式文件/目录目标,因此 `pnpm test extensions/discord/src/monitor/message-handler.preflight.test.ts` 可避免付出完整根项目启动成本。 + - `pnpm test:changed` 默认会把变更的 git 路径展开为低成本的作用域 lane:直接测试编辑、同级 `*.test.ts` 文件、显式源码映射,以及本地导入图依赖方。配置/设置/package 编辑不会广泛运行测试,除非你显式使用 `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`。 + - `pnpm check:changed` 是窄范围工作的常规智能本地检查门禁。它会把 diff 分类为 core、core tests、extensions、extension tests、apps、docs、release metadata、live Docker tooling 和 tooling,然后运行匹配的类型检查、lint 和保护命令。它不会运行 Vitest 测试;需要测试证明时调用 `pnpm test:changed` 或显式 `pnpm test `。仅 release metadata 的版本号升级会运行定向版本/config/root-dependency 检查,并带有一个保护:拒绝顶层 version 字段之外的 package 变更。 + - Live Docker ACP harness 编辑会运行聚焦检查:live Docker 认证脚本的 shell 语法,以及 live Docker 调度器 dry-run。只有当 diff 限于 `scripts["test:docker:live-*"]` 时才包含 `package.json` 变更;依赖、export、版本及其他 package 表面编辑仍使用更广的保护。 + - 来自 agents、commands、plugins、auto-reply helpers、`plugin-sdk` 和类似纯工具区域的轻导入单元测试会路由到 `unit-fast` lane,该 lane 会跳过 `test/setup-openclaw-runtime.ts`;有状态/运行时较重的文件保留在现有 lane 上。 + - 选定的 `plugin-sdk` 和 `commands` 辅助源码文件也会把 changed-mode 运行映射到这些轻量 lane 中的显式同级测试,因此辅助代码编辑不必为该目录重新运行完整重型套件。 + - `auto-reply` 为顶层核心 helper、顶层 `reply.*` 集成测试和 `src/auto-reply/reply/**` 子树设有专用 bucket。CI 还会把 reply 子树进一步拆分为 agent-runner、dispatch 和 commands/state-routing 分片,避免一个导入较重的 bucket 独占整个 Node 尾部耗时。 + - 常规 PR/main CI 会有意跳过插件批量 sweep 和仅发布用的 `agentic-plugins` 分片。Full Release Validation 会为发布候选版本上的这些插件/扩展重型套件调度单独的 `Plugin Prerelease` 子 workflow。 - + - - 当你更改消息工具发现输入或压缩运行时上下文时,请保留两层覆盖。 - - 为纯路由和规范化边界添加聚焦的辅助程序回归测试。 - - 保持嵌入式运行器集成套件健康: + - 当你更改消息工具发现输入或压缩运行时 + 上下文时,请保留两个层级的覆盖。 + - 为纯路由和规范化 + 边界添加聚焦 helper 回归测试。 + - 保持嵌入式 runner 集成套件健康: `src/agents/pi-embedded-runner/compact.hooks.test.ts`、 `src/agents/pi-embedded-runner/run.overflow-compaction.test.ts` 和 `src/agents/pi-embedded-runner/run.overflow-compaction.loop.test.ts`。 - - 这些套件会验证限定范围的 ID 和压缩行为仍会流经真实 `run.ts` / `compact.ts` 路径;仅辅助程序测试不能充分替代这些集成路径。 + - 这些套件会验证作用域 ID 和压缩行为仍然流经 + 真实的 `run.ts` / `compact.ts` 路径;仅 helper 的测试 + 不能充分替代这些集成路径。 - + - 基础 Vitest 配置默认使用 `threads`。 - - 共享 Vitest 配置固定为 `isolate: false`,并在根项目、E2E 和真实运行配置中使用非隔离运行器。 - - 根 UI 通道保留其 `jsdom` 设置和优化器,但同样运行在共享非隔离运行器上。 - - 每个 `pnpm test` 分片都会从共享 Vitest 配置继承相同的 `threads` + `isolate: false` 默认值。 - - `scripts/run-vitest.mjs` 默认会为 Vitest 子 Node 进程添加 `--no-maglev`,以减少大型本地运行期间的 V8 编译抖动。设置 `OPENCLAW_VITEST_ENABLE_MAGLEV=1` 可与原生 V8 行为进行比较。 + - 共享 Vitest 配置固定 `isolate: false`,并在根项目、e2e 和实时配置中使用 + 非隔离 runner。 + - 根 UI lane 保留其 `jsdom` 设置和 optimizer,但同样运行在 + 共享的非隔离 runner 上。 + - 每个 `pnpm test` 分片都从共享 Vitest 配置继承相同的 `threads` + `isolate: false` + 默认值。 + - `scripts/run-vitest.mjs` 默认会为 Vitest 子 Node + 进程添加 `--no-maglev`,以减少大型本地运行期间的 V8 编译抖动。 + 设置 `OPENCLAW_VITEST_ENABLE_MAGLEV=1` 可与标准 V8 + 行为进行比较。 - + - - `pnpm changed:lanes` 显示 diff 会触发哪些架构通道。 - - pre-commit 钩子只负责格式化。它会重新暂存已格式化的文件,不会运行 lint、类型检查或测试。 - - 当你需要智能本地检查门禁时,请在交接或 push 前显式运行 `pnpm check:changed`。 - - `pnpm test:changed` 默认会通过低成本限定范围通道路由。仅当智能体判断测试框架、配置、包或契约编辑确实需要更广泛的 Vitest 覆盖时,才使用 `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`。 - - `pnpm test:max` 和 `pnpm test:changed:max` 保持相同的路由行为,只是使用更高的工作线程上限。 - - 本地工作线程自动伸缩有意保持保守,并会在主机负载平均值已经较高时回退,因此多个并发 Vitest 运行默认造成的影响更小。 - - 基础 Vitest 配置会将项目/配置文件标记为 `forceRerunTriggers`,因此测试编排更改时,变更模式重新运行仍保持正确。 - - 配置会在受支持的主机上保持启用 `OPENCLAW_VITEST_FS_MODULE_CACHE`;如果你想为直接性能剖析指定一个显式缓存位置,请设置 `OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=/abs/path`。 + - `pnpm changed:lanes` 会显示一个 diff 触发哪些架构 lane。 + - pre-commit hook 只做格式化。它会重新暂存已格式化文件, + 不运行 lint、类型检查或测试。 + - 在交接或 push 前,当你需要智能本地检查门禁时,显式运行 + `pnpm check:changed`。 + - `pnpm test:changed` 默认通过低成本作用域 lane 路由。仅当智能体 + 判断 harness、config、package 或契约编辑确实需要更广的 + Vitest 覆盖时,才使用 `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`。 + - `pnpm test:max` 和 `pnpm test:changed:max` 保持相同路由 + 行为,只是使用更高的 worker 上限。 + - 本地 worker 自动缩放有意保持保守,并会在主机平均负载已经很高时 + 退让,因此默认情况下多个并发 + Vitest 运行造成的影响更小。 + - 基础 Vitest 配置将 projects/config 文件标记为 + `forceRerunTriggers`,因此当测试 + wiring 变化时,changed-mode 重新运行仍保持正确。 + - 配置会在受支持 + 主机上保持启用 `OPENCLAW_VITEST_FS_MODULE_CACHE`;如果你想为直接性能分析 + 使用一个显式缓存位置,请设置 `OPENCLAW_VITEST_FS_MODULE_CACHE_PATH=/abs/path`。 - + - - `pnpm test:perf:imports` 会启用 Vitest 导入耗时报告以及导入明细输出。 - - `pnpm test:perf:imports:changed` 会将同一性能剖析视图限定到自 `origin/main` 以来更改的文件。 - - 分片计时数据会写入 `.artifacts/vitest-shard-timings.json`。整配置运行使用配置路径作为键;包含模式 CI 分片会追加分片名称,以便单独跟踪过滤后的分片。 - - 当某个热点测试仍然把大部分时间花在启动导入上时,请将重型依赖放在窄本地 `*.runtime.ts` 抽象层后面,并直接模拟该抽象层,而不是为了将运行时辅助程序传给 `vi.mock(...)` 而深度导入它们。 - - `pnpm test:perf:changed:bench -- --ref ` 会针对该已提交 diff,将路由后的 `test:changed` 与原生根项目路径进行比较,并打印墙钟时间以及 macOS 最大 RSS。 - - `pnpm test:perf:changed:bench -- --worktree` 会通过将已更改文件列表路由到 `scripts/test-projects.mjs` 和根 Vitest 配置,基准测试当前脏工作树。 - - `pnpm test:perf:profile:main` 会为 Vitest/Vite 启动和转换开销写入主线程 CPU profile。 - - `pnpm test:perf:profile:runner` 会在禁用文件并行性的情况下,为单元套件写入运行器 CPU+heap profile。 + - `pnpm test:perf:imports` 会启用 Vitest 导入耗时报告以及 + 导入明细输出。 + - `pnpm test:perf:imports:changed` 会把相同的性能分析视图限定到 + 自 `origin/main` 以来变更的文件。 + - 分片计时数据会写入 `.artifacts/vitest-shard-timings.json`。 + 整个配置运行使用配置路径作为键;include-pattern CI + 分片会追加分片名称,以便单独跟踪过滤后的分片。 + - 当某个热点测试仍把大部分时间耗在启动导入上时, + 将重型依赖放到窄本地 `*.runtime.ts` 接口之后,并 + 直接 mock 该接口,而不是仅为了通过 `vi.mock(...)` + 传递它们而深度导入运行时 helper。 + - `pnpm test:perf:changed:bench -- --ref ` 会比较已路由的 + `test:changed` 与该已提交 + diff 的原生根项目路径,并打印挂钟时间以及 macOS 最大 RSS。 + - `pnpm test:perf:changed:bench -- --worktree` 会通过把变更文件列表路由到 + `scripts/test-projects.mjs` 和根 Vitest 配置来基准测试当前 + 脏工作树。 + - `pnpm test:perf:profile:main` 会为 + Vitest/Vite 启动和转换开销写入主线程 CPU profile。 + - `pnpm test:perf:profile:runner` 会在禁用文件并行时为 + 单元套件写入 runner CPU+heap profile。 @@ -390,18 +440,18 @@ Telegram 类型的 payload 形状: ### 稳定性(Gateway 网关) - 命令:`pnpm test:stability:gateway` -- 配置:`vitest.gateway.config.ts`,强制使用一个工作线程 +- 配置:`vitest.gateway.config.ts`,强制使用一个 worker - 范围: - - 启动一个真实的回环 Gateway 网关,并默认启用诊断 - - 通过诊断事件路径驱动合成 Gateway 网关消息、内存和大载荷反复变动 + - 启动一个真实的 loopback Gateway 网关,默认启用 diagnostics + - 通过诊断事件路径驱动合成 Gateway 网关消息、内存和大载荷 churn - 通过 Gateway 网关 WS RPC 查询 `diagnostics.stability` - - 覆盖诊断稳定性包持久化辅助程序 - - 断言记录器保持有界、合成 RSS 样本保持低于压力预算,并且每个会话队列深度回落到零 + - 覆盖诊断稳定性 bundle 持久化 helper + - 断言 recorder 保持有界、合成 RSS 样本保持在压力预算以下,并且每个会话的队列深度会归零 - 预期: - - 适合 CI 且无需密钥 - - 面向稳定性回归跟进的窄通道,不能替代完整 Gateway 网关套件 + - CI 安全且无需密钥 + - 用于稳定性回归跟进的窄 lane,而不是完整 Gateway 网关套件的替代品 -### E2E(Gateway 网关冒烟) +### E2E(Gateway 网关 smoke) - 命令:`pnpm test:e2e` - 配置:`vitest.e2e.config.ts` @@ -409,56 +459,56 @@ Telegram 类型的 payload 形状: - 运行时默认值: - 使用 Vitest `threads` 和 `isolate: false`,与仓库其余部分保持一致。 - 使用自适应 worker(CI:最多 2 个,本地:默认 1 个)。 - - 默认以静默模式运行,以降低控制台 I/O 开销。 -- 常用覆盖项: - - `OPENCLAW_E2E_WORKERS=` 用于强制设置 worker 数量(上限为 16)。 + - 默认以静默模式运行,以减少控制台 I/O 开销。 +- 有用的覆盖项: + - `OPENCLAW_E2E_WORKERS=` 用于强制指定 worker 数量(上限为 16)。 - `OPENCLAW_E2E_VERBOSE=1` 用于重新启用详细控制台输出。 - 范围: - 多实例 Gateway 网关端到端行为 - - WebSocket/HTTP 表面、节点配对,以及更重的网络行为 + - WebSocket/HTTP 表面、节点配对,以及更重的网络场景 - 预期: - - 在 CI 中运行(当流水线启用时) + - 在 CI 中运行(在流水线中启用时) - 不需要真实密钥 - - 比单元测试有更多移动部件(可能更慢) + - 比单元测试包含更多移动部件(可能更慢) ### E2E:OpenShell 后端冒烟测试 - 命令:`pnpm test:e2e:openshell` - 文件:`extensions/openshell/src/backend.e2e.test.ts` - 范围: - - 通过 Docker 在主机上启动隔离的 OpenShell Gateway 网关 - - 从临时本地 Dockerfile 创建一个沙箱 - - 通过真实的 `sandbox ssh-config` + SSH exec 运行 OpenClaw 的 OpenShell 后端 + - 通过 Docker 在主机上启动一个隔离的 OpenShell Gateway 网关 + - 从一个临时本地 Dockerfile 创建沙箱 + - 通过真实的 `sandbox ssh-config` + SSH exec 演练 OpenClaw 的 OpenShell 后端 - 通过沙箱 fs 桥验证远程规范文件系统行为 - 预期: - - 仅按需启用;不属于默认 `pnpm test:e2e` 运行 - - 需要本地 `openshell` CLI 和可用的 Docker daemon + - 仅按需启用;不属于默认 `pnpm test:e2e` 运行的一部分 + - 需要本地 `openshell` CLI 和可工作的 Docker 守护进程 - 使用隔离的 `HOME` / `XDG_CONFIG_HOME`,然后销毁测试 Gateway 网关和沙箱 -- 常用覆盖项: - - `OPENCLAW_E2E_OPENSHELL=1` 用于在手动运行更广泛的 e2e 套件时启用该测试 +- 有用的覆盖项: + - `OPENCLAW_E2E_OPENSHELL=1` 用于在手动运行更广泛的 E2E 套件时启用该测试 - `OPENCLAW_E2E_OPENSHELL_COMMAND=/path/to/openshell` 用于指向非默认 CLI 二进制文件或包装脚本 -### Live(真实提供商 + 真实模型) +### 实时(真实提供商 + 真实模型) - 命令:`pnpm test:live` - 配置:`vitest.live.config.ts` -- 文件:`src/**/*.live.test.ts`、`test/**/*.live.test.ts`,以及 `extensions/` 下的内置插件 live 测试 -- 默认值:`pnpm test:live` 默认**启用**(设置 `OPENCLAW_LIVE_TEST=1`) +- 文件:`src/**/*.live.test.ts`、`test/**/*.live.test.ts`,以及 `extensions/` 下的内置插件实时测试 +- 默认值:由 `pnpm test:live` **启用**(设置 `OPENCLAW_LIVE_TEST=1`) - 范围: - - “这个提供商/模型在_今天_使用真实凭证时真的能工作吗?” - - 捕获提供商格式变更、工具调用怪异行为、凭证问题和速率限制行为 + - “这个提供商/模型在_今天_使用真实凭证时是否真的可用?” + - 捕获提供商格式变更、工具调用怪癖、凭证问题,以及速率限制行为 - 预期: - - 按设计并不保证 CI 稳定(真实网络、真实提供商策略、配额、故障) - - 会花钱 / 使用速率限制 - - 优先运行缩小范围的子集,而不是“全部” -- Live 运行会加载 `~/.profile`,以拾取缺失的 API key。 -- 默认情况下,live 运行仍会隔离 `HOME`,并将配置/认证材料复制到临时测试主目录,这样单元测试夹具就不能修改你的真实 `~/.openclaw`。 -- 仅当你明确需要 live 测试使用你的真实主目录时,才设置 `OPENCLAW_LIVE_USE_REAL_HOME=1`。 -- `pnpm test:live` 现在默认使用更安静的模式:它保留 `[live] ...` 进度输出,但抑制额外的 `~/.profile` 通知,并静音 Gateway 网关启动日志/Bonjour 噪声。如果你想恢复完整启动日志,请设置 `OPENCLAW_LIVE_TEST_QUIET=0`。 -- API key 轮换(按提供商区分):设置逗号/分号格式的 `*_API_KEYS` 或 `*_API_KEY_1`、`*_API_KEY_2`(例如 `OPENAI_API_KEYS`、`ANTHROPIC_API_KEYS`、`GEMINI_API_KEYS`),或通过 `OPENCLAW_LIVE_*_KEY` 设置每个 live 覆盖项;测试会在速率限制响应时重试。 + - 设计上并非 CI 稳定(真实网络、真实提供商策略、配额、故障) + - 会产生费用 / 使用速率限制额度 + - 优先运行缩窄后的子集,而不是“全部” +- 实时运行会 source `~/.profile` 以获取缺失的 API key。 +- 默认情况下,实时运行仍会隔离 `HOME`,并将配置/凭证材料复制到临时测试主目录中,避免单元夹具修改你真实的 `~/.openclaw`。 +- 仅当你有意需要实时测试使用你的真实主目录时,才设置 `OPENCLAW_LIVE_USE_REAL_HOME=1`。 +- `pnpm test:live` 现在默认使用更安静的模式:它保留 `[live] ...` 进度输出,但会隐藏额外的 `~/.profile` 提示,并静音 Gateway 网关启动日志/Bonjour 噪声。如果你想恢复完整启动日志,请设置 `OPENCLAW_LIVE_TEST_QUIET=0`。 +- API key 轮换(按提供商):设置带逗号/分号格式的 `*_API_KEYS`,或设置 `*_API_KEY_1`、`*_API_KEY_2`(例如 `OPENAI_API_KEYS`、`ANTHROPIC_API_KEYS`、`GEMINI_API_KEYS`),也可以通过 `OPENCLAW_LIVE_*_KEY` 为每次实时运行覆盖;测试会在收到速率限制响应时重试。 - 进度/Heartbeat 输出: - - Live 套件现在会向 stderr 发出进度行,因此即使 Vitest 控制台捕获很安静,长时间的提供商调用也能清楚显示仍在活动。 - - `vitest.live.config.ts` 禁用 Vitest 控制台拦截,因此提供商/Gateway 网关进度行会在 live 运行期间立即流式输出。 + - 实时套件现在会向 stderr 输出进度行,因此即使 Vitest 控制台捕获较安静,较长的提供商调用也能显示为活跃状态。 + - `vitest.live.config.ts` 会禁用 Vitest 控制台拦截,因此在实时运行期间,提供商/Gateway 网关进度行会立即流式输出。 - 使用 `OPENCLAW_LIVE_HEARTBEAT_MS` 调整直接模型 Heartbeat。 - 使用 `OPENCLAW_LIVE_GATEWAY_HEARTBEAT_MS` 调整 Gateway 网关/探测 Heartbeat。 @@ -466,68 +516,67 @@ Telegram 类型的 payload 形状: 使用此决策表: -- 编辑逻辑/测试:运行 `pnpm test`(如果你改了很多内容,也运行 `pnpm test:coverage`) +- 编辑逻辑/测试:运行 `pnpm test`(如果你改动较多,也运行 `pnpm test:coverage`) - 触及 Gateway 网关网络 / WS 协议 / 配对:添加 `pnpm test:e2e` -- 调试“我的机器人挂了” / 提供商特定故障 / 工具调用:运行缩小范围的 `pnpm test:live` +- 调试“我的 bot 挂了” / 提供商特定失败 / 工具调用:运行缩窄后的 `pnpm test:live` -## Live(触网)测试 +## 实时(触网)测试 -关于 live 模型矩阵、CLI 后端冒烟测试、ACP 冒烟测试、Codex app-server -harness,以及所有媒体提供商 live 测试(Deepgram、BytePlus、ComfyUI、image、 -music、video、media harness)——以及 live 运行的凭证处理——请参阅 -[测试 live 套件](/zh-CN/help/testing-live)。关于专门的更新和 -插件验证检查清单,请参阅 +对于实时模型矩阵、CLI 后端冒烟、ACP 冒烟、Codex 应用服务器 +harness,以及所有媒体提供商实时测试(Deepgram、BytePlus、ComfyUI、图像、 +音乐、视频、媒体 harness),以及实时运行的凭证处理,请参阅 +[测试实时套件](/zh-CN/help/testing-live)。如需专门的更新和 +插件验证清单,请参阅 [更新和插件测试](/zh-CN/help/testing-updates-plugins)。 -## Docker 运行器(可选的“在 Linux 中可用”检查) +## Docker runner(可选的“在 Linux 中可用”检查) -这些 Docker 运行器分为两类: +这些 Docker runner 分为两类: -- Live 模型运行器:`test:docker:live-models` 和 `test:docker:live-gateway` 只会在仓库 Docker 镜像中运行对应 profile-key live 文件(`src/agents/models.profiles.live.test.ts` 和 `src/gateway/gateway-models.profiles.live.test.ts`),挂载你的本地配置目录和工作区(如果已挂载,也会加载 `~/.profile`)。对应的本地入口点是 `test:live:models-profiles` 和 `test:live:gateway-profiles`。 -- Docker live 运行器默认使用更小的冒烟上限,因此完整 Docker 扫描仍然可行: +- 实时模型 runner:`test:docker:live-models` 和 `test:docker:live-gateway` 只会在仓库 Docker 镜像内运行各自匹配 profile-key 的实时文件(`src/agents/models.profiles.live.test.ts` 和 `src/gateway/gateway-models.profiles.live.test.ts`),挂载你的本地配置目录和工作区(如果已挂载,也会 source `~/.profile`)。对应的本地入口点是 `test:live:models-profiles` 和 `test:live:gateway-profiles`。 +- Docker 实时 runner 默认使用较小的冒烟上限,让完整 Docker 扫描保持实用: `test:docker:live-models` 默认使用 `OPENCLAW_LIVE_MAX_MODELS=12`,并且 `test:docker:live-gateway` 默认使用 `OPENCLAW_LIVE_GATEWAY_SMOKE=1`、 `OPENCLAW_LIVE_GATEWAY_MAX_MODELS=8`、 - `OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=45000`,以及 - `OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=90000`。仅当你明确想要更大的穷尽扫描时, - 才覆盖这些环境变量。 -- `test:docker:all` 先通过 `test:docker:live-build` 构建一次 live Docker 镜像,通过 `scripts/package-openclaw-for-docker.mjs` 将 OpenClaw 打包一次为 npm tarball,然后构建/复用两个 `scripts/e2e/Dockerfile` 镜像。裸镜像只是用于安装/更新/插件依赖 lane 的 Node/Git 运行器;这些 lane 会挂载预构建的 tarball。功能镜像会把同一个 tarball 安装到 `/app`,用于构建后应用功能 lane。Docker lane 定义位于 `scripts/lib/docker-e2e-scenarios.mjs`;规划器逻辑位于 `scripts/lib/docker-e2e-plan.mjs`;`scripts/test-docker-all.mjs` 执行选中的计划。聚合运行使用加权本地调度器:`OPENCLAW_DOCKER_ALL_PARALLELISM` 控制进程槽位,而资源上限会防止重型 live、npm-install 和多服务 lane 同时全部启动。如果单个 lane 比活动上限更重,调度器仍可在池为空时启动它,然后让它独占运行,直到再次有容量可用。默认值为 10 个槽位、`OPENCLAW_DOCKER_ALL_LIVE_LIMIT=9`、`OPENCLAW_DOCKER_ALL_NPM_LIMIT=10` 和 `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`;仅当 Docker 主机有更多余量时,才调整 `OPENCLAW_DOCKER_ALL_WEIGHT_LIMIT` 或 `OPENCLAW_DOCKER_ALL_DOCKER_LIMIT`。运行器默认执行 Docker 预检,移除陈旧的 OpenClaw E2E 容器,每 30 秒打印状态,将成功 lane 的耗时存储在 `.artifacts/docker-tests/lane-timings.json`,并在后续运行中使用这些耗时优先启动更长的 lane。使用 `OPENCLAW_DOCKER_ALL_DRY_RUN=1` 可在不构建或运行 Docker 的情况下打印加权 lane 清单,或使用 `node scripts/test-docker-all.mjs --plan-json` 打印所选 lane、package/image 需求和凭证的 CI 计划。 -- `Package Acceptance` 是 GitHub 原生 package gate,用于回答“这个可安装 tarball 作为产品是否可用?”它会从 `source=npm`、`source=ref`、`source=url` 或 `source=artifact` 解析一个候选 package,将其上传为 `package-under-test`,然后针对这个精确 tarball 运行可复用 Docker E2E lane,而不是重新打包所选 ref。profile 按覆盖范围排序:`smoke`、`package`、`product` 和 `full`。关于 package/update/plugin 契约、已发布升级存活矩阵、发布默认值和故障分诊,请参阅[更新和插件测试](/zh-CN/help/testing-updates-plugins)。 -- 构建和发布检查会在 tsdown 之后运行 `scripts/check-cli-bootstrap-imports.mjs`。该守卫从 `dist/entry.js` 和 `dist/cli/run-main.js` 遍历静态构建图;如果预分发启动在命令分发前导入 Commander、prompt UI、undici 或 logging 等 package 依赖,就会失败;它还会让内置 Gateway 网关运行 chunk 保持在预算内,并拒绝对已知冷 Gateway 网关路径的静态导入。打包后的 CLI 冒烟测试还覆盖根帮助、新手引导帮助、Doctor 帮助、Status、配置 schema,以及一个模型列表命令。 -- Package Acceptance 旧版兼容性截止到 `2026.4.25`(包括 `2026.4.25-beta.*`)。在该截止日期前,harness 只容忍已发布 package 的元数据缺口:省略的私有 QA inventory 条目、缺失的 `gateway install --wrapper`、tarball 派生 git fixture 中缺失的 patch 文件、缺失的持久化 `update.channel`、旧版插件安装记录位置、缺失的 marketplace 安装记录持久化,以及 `plugins update` 期间的配置元数据迁移。对于 `2026.4.25` 之后的 package,这些路径都是严格失败。 -- 容器冒烟运行器:`test:docker:openwebui`、`test:docker:onboard`、`test:docker:npm-onboard-channel-agent`、`test:docker:update-channel-switch`、`test:docker:upgrade-survivor`、`test:docker:published-upgrade-survivor`、`test:docker:session-runtime-context`、`test:docker:agents-delete-shared-workspace`、`test:docker:gateway-network`、`test:docker:browser-cdp-snapshot`、`test:docker:mcp-channels`、`test:docker:pi-bundle-mcp-tools`、`test:docker:cron-mcp-cleanup`、`test:docker:plugins`、`test:docker:plugin-update`、`test:docker:plugin-lifecycle-matrix` 和 `test:docker:config-reload` 会启动一个或多个真实容器,并验证更高层级的集成路径。 + `OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=45000` 和 + `OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=90000`。仅当你明确需要更大的穷尽式扫描时,才覆盖这些环境变量。 +- `test:docker:all` 先通过 `test:docker:live-build` 构建一次实时 Docker 镜像,通过 `scripts/package-openclaw-for-docker.mjs` 将 OpenClaw 打包一次为 npm tarball,然后构建/复用两个 `scripts/e2e/Dockerfile` 镜像。裸镜像只是用于安装/更新/插件依赖 lane 的 Node/Git runner;这些 lane 会挂载预构建 tarball。功能镜像会将同一个 tarball 安装到 `/app`,用于已构建应用功能 lane。Docker lane 定义位于 `scripts/lib/docker-e2e-scenarios.mjs`;planner 逻辑位于 `scripts/lib/docker-e2e-plan.mjs`;`scripts/test-docker-all.mjs` 执行选定的计划。聚合运行使用加权本地调度器:`OPENCLAW_DOCKER_ALL_PARALLELISM` 控制进程槽位,而资源上限会避免重型实时、npm-install 和多服务 lane 同时全部启动。如果单个 lane 比当前上限更重,调度器仍可在池为空时启动它,然后让它单独运行,直到容量再次可用。默认值是 10 个槽位、`OPENCLAW_DOCKER_ALL_LIVE_LIMIT=9`、`OPENCLAW_DOCKER_ALL_NPM_LIMIT=10` 和 `OPENCLAW_DOCKER_ALL_SERVICE_LIMIT=7`;只有在 Docker 主机有更多余量时,才调整 `OPENCLAW_DOCKER_ALL_WEIGHT_LIMIT` 或 `OPENCLAW_DOCKER_ALL_DOCKER_LIMIT`。runner 默认执行 Docker 预检,移除陈旧的 OpenClaw E2E 容器,每 30 秒打印状态,将成功 lane 的耗时存储在 `.artifacts/docker-tests/lane-timings.json`,并在后续运行中使用这些耗时优先启动较长的 lane。使用 `OPENCLAW_DOCKER_ALL_DRY_RUN=1` 打印加权 lane 清单而不构建或运行 Docker,或使用 `node scripts/test-docker-all.mjs --plan-json` 打印选定 lane、package/镜像需求和凭证的 CI 计划。 +- `Package Acceptance` 是 GitHub 原生 package gate,用于回答“这个可安装 tarball 作为产品是否可用?”它会从 `source=npm`、`source=ref`、`source=url` 或 `source=artifact` 解析一个候选 package,将其作为 `package-under-test` 上传,然后针对这个精确 tarball 运行可复用的 Docker E2E lane,而不是重新打包选定 ref。profile 按覆盖范围排序:`smoke`、`package`、`product` 和 `full`。有关 package/更新/插件契约、已发布升级幸存者矩阵、发布默认值和失败分诊,请参阅[更新和插件测试](/zh-CN/help/testing-updates-plugins)。 +- 构建和发布检查会在 tsdown 之后运行 `scripts/check-cli-bootstrap-imports.mjs`。该 guard 会从 `dist/entry.js` 和 `dist/cli/run-main.js` 遍历静态构建图,并在命令分发前的启动导入了 Commander、提示 UI、undici 或日志等 package 依赖时失败;它还会将内置 Gateway 网关运行 chunk 保持在预算内,并拒绝已知冷 Gateway 网关路径的静态导入。打包后的 CLI 冒烟还覆盖根帮助、新手引导帮助、Doctor 帮助、Status、配置 schema,以及一个模型列表命令。 +- Package Acceptance 旧版兼容性上限为 `2026.4.25`(包括 `2026.4.25-beta.*`)。在该截止点之前,harness 仅容忍已发布 package 元数据缺口:省略的私有 QA 库存条目、缺失的 `gateway install --wrapper`、tarball 派生 git 夹具中缺失的 patch 文件、缺失的持久化 `update.channel`、旧版插件安装记录位置、缺失的 marketplace 安装记录持久化,以及 `plugins update` 期间的配置元数据迁移。对于 `2026.4.25` 之后的 package,这些路径都是严格失败。 +- 容器冒烟 runner:`test:docker:openwebui`、`test:docker:onboard`、`test:docker:npm-onboard-channel-agent`、`test:docker:update-channel-switch`、`test:docker:upgrade-survivor`、`test:docker:published-upgrade-survivor`、`test:docker:session-runtime-context`、`test:docker:agents-delete-shared-workspace`、`test:docker:gateway-network`、`test:docker:browser-cdp-snapshot`、`test:docker:mcp-channels`、`test:docker:pi-bundle-mcp-tools`、`test:docker:cron-mcp-cleanup`、`test:docker:plugins`、`test:docker:plugin-update`、`test:docker:plugin-lifecycle-matrix` 和 `test:docker:config-reload` 会启动一个或多个真实容器,并验证更高层级的集成路径。 -Live 模型 Docker 运行器还只 bind-mount 所需的 CLI 认证主目录(如果运行未缩小范围,则挂载所有受支持的主目录),然后在运行前将它们复制到容器主目录中,这样外部 CLI OAuth 就可以刷新 token,而不会修改主机认证存储: +实时模型 Docker runner 还会只 bind-mount 所需的 CLI 凭证主目录(如果运行未缩窄,则挂载全部受支持的主目录),然后在运行前将它们复制到容器主目录中,这样外部 CLI OAuth 就能刷新令牌,而不会修改主机凭证存储: - 直接模型:`pnpm test:docker:live-models`(脚本:`scripts/test-live-models-docker.sh`) - ACP 绑定冒烟测试:`pnpm test:docker:live-acp-bind`(脚本:`scripts/test-live-acp-bind-docker.sh`;默认覆盖 Claude、Codex 和 Gemini,并通过 `pnpm test:docker:live-acp-bind:droid` 和 `pnpm test:docker:live-acp-bind:opencode` 严格覆盖 Droid/OpenCode) - CLI 后端冒烟测试:`pnpm test:docker:live-cli-backend`(脚本:`scripts/test-live-cli-backend-docker.sh`) - Codex app-server harness 冒烟测试:`pnpm test:docker:live-codex-harness`(脚本:`scripts/test-live-codex-harness-docker.sh`) - Gateway 网关 + 开发智能体:`pnpm test:docker:live-gateway`(脚本:`scripts/test-live-gateway-models-docker.sh`) -- 可观测性冒烟测试:`pnpm qa:otel:smoke` 是私有 QA 源码检出检查通道。它有意不属于包 Docker 发布检查通道,因为 npm tarball 会省略 QA Lab。 -- Open WebUI 实时冒烟测试:`pnpm test:docker:openwebui`(脚本:`scripts/e2e/openwebui-docker.sh`) +- 可观测性冒烟测试:`pnpm qa:otel:smoke` 是私有 QA 源码检出通道。它有意不属于 package Docker 发布通道,因为 npm tarball 会省略 QA Lab。 +- Open WebUI 现场冒烟测试:`pnpm test:docker:openwebui`(脚本:`scripts/e2e/openwebui-docker.sh`) - 新手引导向导(TTY,完整脚手架):`pnpm test:docker:onboard`(脚本:`scripts/e2e/onboard-docker.sh`) -- Npm tarball 新手引导/渠道/智能体冒烟测试:`pnpm test:docker:npm-onboard-channel-agent` 会在 Docker 中全局安装打包后的 OpenClaw tarball,通过 env-ref 新手引导配置 OpenAI,并默认配置 Telegram,运行 doctor,然后运行一次模拟的 OpenAI 智能体轮次。使用 `OPENCLAW_CURRENT_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 复用预构建的 tarball,使用 `OPENCLAW_NPM_ONBOARD_HOST_BUILD=0` 跳过主机重新构建,或使用 `OPENCLAW_NPM_ONBOARD_CHANNEL=discord` 或 `OPENCLAW_NPM_ONBOARD_CHANNEL=slack` 切换渠道。 -- 更新渠道切换冒烟测试:`pnpm test:docker:update-channel-switch` 会在 Docker 中全局安装打包后的 OpenClaw tarball,从 package `stable` 切换到 git `dev`,验证持久化的渠道和插件更新后可用,然后切回 package `stable` 并检查更新状态。 -- 升级幸存冒烟测试:`pnpm test:docker:upgrade-survivor` 会在包含智能体、渠道配置、插件允许列表、过期插件依赖状态以及现有工作区/会话文件的脏旧用户夹具上安装打包后的 OpenClaw tarball。它会在没有实时提供商或渠道密钥的情况下运行包更新和非交互式 doctor,然后启动一个 loopback Gateway 网关,并检查配置/状态保留以及启动/Status 预算。 -- 已发布版本升级幸存冒烟测试:`pnpm test:docker:published-upgrade-survivor` 默认安装 `openclaw@latest`,播种真实的现有用户文件,使用内置命令配方配置该基线,验证生成的配置,将该已发布安装更新到候选 tarball,运行非交互式 doctor,写入 `.artifacts/upgrade-survivor/summary.json`,然后启动一个 loopback Gateway 网关,并检查已配置意图、状态保留、启动、`/healthz`、`/readyz` 和 RPC Status 预算。使用 `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC` 覆盖一个基线,使用 `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPECS` 让聚合调度器展开精确基线,例如 `all-since-2026.4.23`,并使用 `OPENCLAW_UPGRADE_SURVIVOR_SCENARIOS` 展开 issue 形状的夹具,例如 `reported-issues`;reported-issues 集合包含 `configured-plugin-installs`,用于自动修复外部 OpenClaw 插件安装。Package Acceptance 将这些暴露为 `published_upgrade_survivor_baseline`、`published_upgrade_survivor_baselines` 和 `published_upgrade_survivor_scenarios`;Full Release Validation 在阻塞路径中使用默认 latest 基线,并且仅在 `run_release_soak=true` 或 `release_profile=full` 时展开到 all-since/reported-issues。 -- 会话运行时上下文冒烟测试:`pnpm test:docker:session-runtime-context` 会验证隐藏运行时上下文 transcript 持久化,以及 doctor 对受影响的重复 prompt-rewrite 分支的修复。 -- Bun 全局安装冒烟测试:`bash scripts/e2e/bun-global-install-smoke.sh` 会打包当前目录树,在隔离 home 中用 `bun install -g` 安装,并验证 `openclaw infer image providers --json` 返回内置图像提供商而不是挂起。使用 `OPENCLAW_BUN_GLOBAL_SMOKE_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 复用预构建的 tarball,使用 `OPENCLAW_BUN_GLOBAL_SMOKE_HOST_BUILD=0` 跳过主机构建,或使用 `OPENCLAW_BUN_GLOBAL_SMOKE_DIST_IMAGE=openclaw-dockerfile-smoke:local` 从已构建的 Docker 镜像复制 `dist/`。 -- Installer Docker 冒烟测试:`bash scripts/test-install-sh-docker.sh` 会在它的 root、update 和 direct-npm 容器之间共享同一个 npm 缓存。更新冒烟测试默认使用 npm `latest` 作为 stable 基线,然后升级到候选 tarball。本地使用 `OPENCLAW_INSTALL_SMOKE_UPDATE_BASELINE=2026.4.22` 覆盖,或在 GitHub 上使用 Install Smoke 工作流的 `update_baseline_version` 输入覆盖。非 root installer 检查会保留隔离的 npm 缓存,这样 root 拥有的缓存条目不会掩盖用户本地安装行为。设置 `OPENCLAW_INSTALL_SMOKE_NPM_CACHE_DIR=/path/to/cache` 可在本地重复运行时复用 root/update/direct-npm 缓存。 -- Install Smoke CI 使用 `OPENCLAW_INSTALL_SMOKE_SKIP_NPM_GLOBAL=1` 跳过重复的 direct-npm 全局更新;需要直接 `npm install -g` 覆盖时,在本地运行脚本且不要设置该环境变量。 -- 智能体删除共享工作区 CLI 冒烟测试:`pnpm test:docker:agents-delete-shared-workspace`(脚本:`scripts/e2e/agents-delete-shared-workspace-docker.sh`)默认构建根 Dockerfile 镜像,在隔离容器 home 中播种两个共享同一工作区的智能体,运行 `agents delete --json`,并验证有效 JSON 以及工作区保留行为。使用 `OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_IMAGE=openclaw-dockerfile-smoke:local OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_SKIP_BUILD=1` 复用 install-smoke 镜像。 +- npm tarball 新手引导/渠道/智能体冒烟测试:`pnpm test:docker:npm-onboard-channel-agent` 会在 Docker 中全局安装已打包的 OpenClaw tarball,通过 env-ref 新手引导配置 OpenAI 并默认配置 Telegram,运行 doctor,并运行一次模拟的 OpenAI 智能体轮次。使用 `OPENCLAW_CURRENT_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 复用预构建 tarball,使用 `OPENCLAW_NPM_ONBOARD_HOST_BUILD=0` 跳过宿主机构建,或使用 `OPENCLAW_NPM_ONBOARD_CHANNEL=discord` 或 `OPENCLAW_NPM_ONBOARD_CHANNEL=slack` 切换渠道。 +- 更新渠道切换冒烟测试:`pnpm test:docker:update-channel-switch` 会在 Docker 中全局安装已打包的 OpenClaw tarball,从 package `stable` 切换到 git `dev`,验证已持久化的渠道和插件更新后工作正常,然后切回 package `stable` 并检查更新 Status。 +- 升级幸存者冒烟测试:`pnpm test:docker:upgrade-survivor` 会把已打包的 OpenClaw tarball 安装到一个脏的旧用户夹具之上,该夹具包含智能体、渠道配置、插件 allowlist、陈旧的插件依赖状态,以及现有工作区/会话文件。它会在没有现场提供商或渠道密钥的情况下运行 package update 和非交互式 doctor,然后启动一个 loopback Gateway 网关,并检查配置/状态保留情况以及启动/Status 预算。 +- 已发布版本升级幸存者冒烟测试:`pnpm test:docker:published-upgrade-survivor` 默认安装 `openclaw@latest`,植入真实感的现有用户文件,使用内置命令配方配置该基线,验证生成的配置,将该已发布安装更新到候选 tarball,运行非交互式 doctor,写入 `.artifacts/upgrade-survivor/summary.json`,然后启动一个 loopback Gateway 网关,并检查已配置 intent、状态保留、启动、`/healthz`、`/readyz` 和 RPC Status 预算。用 `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC` 覆盖一个基线,让聚合调度器用 `OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPECS` 展开精确本地基线,例如 `openclaw@2026.5.2 openclaw@2026.4.23 openclaw@2026.4.15`,并用 `OPENCLAW_UPGRADE_SURVIVOR_SCENARIOS` 展开 issue 形态的夹具,例如 `reported-issues`;reported-issues 集合包含 `configured-plugin-installs`,用于自动修复外部 OpenClaw 插件安装。Package Acceptance 将这些暴露为 `published_upgrade_survivor_baseline`、`published_upgrade_survivor_baselines` 和 `published_upgrade_survivor_scenarios`,解析 `last-stable-4` 或 `all-since-2026.4.23` 等元基线 token,而 Full Release Validation 会把 release-soak package gate 展开为 `last-stable-4 2026.4.23 2026.5.2 2026.4.15` 加上 `reported-issues`。 +- 会话运行时上下文冒烟测试:`pnpm test:docker:session-runtime-context` 验证隐藏运行时上下文 transcript 持久化,以及 doctor 对受影响的重复 prompt-rewrite 分支的修复。 +- Bun 全局安装冒烟测试:`bash scripts/e2e/bun-global-install-smoke.sh` 会打包当前树,在隔离 home 中用 `bun install -g` 安装,并验证 `openclaw infer image providers --json` 返回内置图像提供商而不是挂起。使用 `OPENCLAW_BUN_GLOBAL_SMOKE_PACKAGE_TGZ=/path/to/openclaw-*.tgz` 复用预构建 tarball,使用 `OPENCLAW_BUN_GLOBAL_SMOKE_HOST_BUILD=0` 跳过宿主机构建,或使用 `OPENCLAW_BUN_GLOBAL_SMOKE_DIST_IMAGE=openclaw-dockerfile-smoke:local` 从已构建的 Docker 镜像复制 `dist/`。 +- 安装器 Docker 冒烟测试:`bash scripts/test-install-sh-docker.sh` 会在其 root、update 和 direct-npm 容器之间共享一个 npm 缓存。Update 冒烟测试默认使用 npm `latest` 作为稳定基线,然后升级到候选 tarball。本地可用 `OPENCLAW_INSTALL_SMOKE_UPDATE_BASELINE=2026.4.22` 覆盖,或在 GitHub 上用 Install Smoke 工作流的 `update_baseline_version` 输入覆盖。非 root 安装器检查会保留隔离的 npm 缓存,这样 root 拥有的缓存条目不会掩盖用户本地安装行为。设置 `OPENCLAW_INSTALL_SMOKE_NPM_CACHE_DIR=/path/to/cache`,即可在本地重复运行时复用 root/update/direct-npm 缓存。 +- Install Smoke CI 会用 `OPENCLAW_INSTALL_SMOKE_SKIP_NPM_GLOBAL=1` 跳过重复的 direct-npm 全局更新;需要覆盖直接 `npm install -g` 时,在本地运行脚本且不要设置该环境变量。 +- 智能体删除共享工作区 CLI 冒烟测试:`pnpm test:docker:agents-delete-shared-workspace`(脚本:`scripts/e2e/agents-delete-shared-workspace-docker.sh`)默认构建根 Dockerfile 镜像,在隔离容器 home 中植入两个智能体和一个工作区,运行 `agents delete --json`,并验证有效 JSON 以及工作区保留行为。使用 `OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_IMAGE=openclaw-dockerfile-smoke:local OPENCLAW_AGENTS_DELETE_SHARED_WORKSPACE_E2E_SKIP_BUILD=1` 复用 install-smoke 镜像。 - Gateway 网关网络(两个容器,WS 认证 + 健康检查):`pnpm test:docker:gateway-network`(脚本:`scripts/e2e/gateway-network-docker.sh`) -- Browser CDP 快照冒烟测试:`pnpm test:docker:browser-cdp-snapshot`(脚本:`scripts/e2e/browser-cdp-snapshot-docker.sh`)会构建源 E2E 镜像加 Chromium 层,用原始 CDP 启动 Chromium,运行 `browser doctor --deep`,并验证 CDP role 快照覆盖链接 URL、cursor-promoted 可点击项、iframe 引用和 frame 元数据。 -- OpenAI Responses web_search 最小推理回归:`pnpm test:docker:openai-web-search-minimal`(脚本:`scripts/e2e/openai-web-search-minimal-docker.sh`)会通过 Gateway 网关运行一个模拟的 OpenAI 服务器,验证 `web_search` 将 `reasoning.effort` 从 `minimal` 提升到 `low`,然后强制 provider schema reject 并检查原始 detail 出现在 Gateway 网关日志中。 -- MCP 渠道桥接(播种的 Gateway 网关 + stdio bridge + 原始 Claude notification-frame 冒烟测试):`pnpm test:docker:mcp-channels`(脚本:`scripts/e2e/mcp-channels-docker.sh`) -- Pi 包 MCP 工具(真实 stdio MCP server + 嵌入式 Pi profile allow/deny 冒烟测试):`pnpm test:docker:pi-bundle-mcp-tools`(脚本:`scripts/e2e/pi-bundle-mcp-tools-docker.sh`) -- Cron/subagent MCP 清理(真实 Gateway 网关 + 在隔离 cron 和一次性 subagent 运行后拆除 stdio MCP 子进程):`pnpm test:docker:cron-mcp-cleanup`(脚本:`scripts/e2e/cron-mcp-cleanup-docker.sh`) -- 插件(针对本地路径、`file:`、带提升依赖的 npm registry、git moving refs、ClawHub kitchen-sink、marketplace 更新和 Claude-bundle enable/inspect 的 install/update 冒烟测试):`pnpm test:docker:plugins`(脚本:`scripts/e2e/plugins-docker.sh`) - 设置 `OPENCLAW_PLUGINS_E2E_CLAWHUB=0` 可跳过 ClawHub 块,或使用 `OPENCLAW_PLUGINS_E2E_CLAWHUB_SPEC` 和 `OPENCLAW_PLUGINS_E2E_CLAWHUB_ID` 覆盖默认 kitchen-sink package/runtime 对。如果没有 `OPENCLAW_CLAWHUB_URL`/`CLAWHUB_URL`,该测试会使用 hermetic 本地 ClawHub 夹具服务器。 -- 插件更新未变冒烟测试:`pnpm test:docker:plugin-update`(脚本:`scripts/e2e/plugin-update-unchanged-docker.sh`) -- 插件生命周期矩阵冒烟测试:`pnpm test:docker:plugin-lifecycle-matrix` 会在裸容器中安装打包后的 OpenClaw tarball,安装一个 npm 插件,切换 enable/disable,通过本地 npm registry 对其升级和降级,删除已安装代码,然后验证卸载仍会移除过期状态,同时为每个生命周期阶段记录 RSS/CPU 指标。 +- 浏览器 CDP 快照冒烟测试:`pnpm test:docker:browser-cdp-snapshot`(脚本:`scripts/e2e/browser-cdp-snapshot-docker.sh`)构建源码 E2E 镜像和一个 Chromium 层,使用原始 CDP 启动 Chromium,运行 `browser doctor --deep`,并验证 CDP 角色快照覆盖链接 URL、由光标提升的可点击项、iframe 引用和 frame 元数据。 +- OpenAI Responses web_search minimal reasoning 回归测试:`pnpm test:docker:openai-web-search-minimal`(脚本:`scripts/e2e/openai-web-search-minimal-docker.sh`)通过 Gateway 网关运行一个模拟的 OpenAI 服务器,验证 `web_search` 将 `reasoning.effort` 从 `minimal` 提升到 `low`,然后强制提供商 schema 拒绝,并检查原始详情出现在 Gateway 网关日志中。 +- MCP 渠道桥接(已植入的 Gateway 网关 + stdio 桥接 + 原始 Claude notification-frame 冒烟测试):`pnpm test:docker:mcp-channels`(脚本:`scripts/e2e/mcp-channels-docker.sh`) +- Pi bundle MCP 工具(真实 stdio MCP 服务器 + 嵌入式 Pi profile allow/deny 冒烟测试):`pnpm test:docker:pi-bundle-mcp-tools`(脚本:`scripts/e2e/pi-bundle-mcp-tools-docker.sh`) +- Cron/subagent MCP 清理(真实 Gateway 网关 + stdio MCP 子进程在隔离 cron 和一次性 subagent 运行后的清理):`pnpm test:docker:cron-mcp-cleanup`(脚本:`scripts/e2e/cron-mcp-cleanup-docker.sh`) +- 插件(针对本地路径、`file:`、带提升依赖的 npm registry、git moving refs、ClawHub kitchen-sink、marketplace 更新,以及 Claude-bundle 启用/检查的安装/更新冒烟测试):`pnpm test:docker:plugins`(脚本:`scripts/e2e/plugins-docker.sh`) + 设置 `OPENCLAW_PLUGINS_E2E_CLAWHUB=0` 可跳过 ClawHub 块,或用 `OPENCLAW_PLUGINS_E2E_CLAWHUB_SPEC` 和 `OPENCLAW_PLUGINS_E2E_CLAWHUB_ID` 覆盖默认的 kitchen-sink package/runtime 对。如果没有 `OPENCLAW_CLAWHUB_URL`/`CLAWHUB_URL`,测试会使用 hermetic 本地 ClawHub 夹具服务器。 +- 插件更新未变更冒烟测试:`pnpm test:docker:plugin-update`(脚本:`scripts/e2e/plugin-update-unchanged-docker.sh`) +- 插件生命周期矩阵冒烟测试:`pnpm test:docker:plugin-lifecycle-matrix` 会在裸容器中安装已打包的 OpenClaw tarball,安装一个 npm 插件,切换启用/禁用,通过本地 npm registry 升级和降级它,删除已安装代码,然后验证卸载仍会移除陈旧状态,同时记录每个生命周期阶段的 RSS/CPU 指标。 - 配置重载元数据冒烟测试:`pnpm test:docker:config-reload`(脚本:`scripts/e2e/config-reload-source-docker.sh`) -- 插件:`pnpm test:docker:plugins` 覆盖针对本地路径、`file:`、带提升依赖的 npm registry、git moving refs、ClawHub 夹具、marketplace 更新和 Claude-bundle enable/inspect 的 install/update 冒烟测试。`pnpm test:docker:plugin-update` 覆盖已安装插件的未变更新行为。`pnpm test:docker:plugin-lifecycle-matrix` 覆盖带资源跟踪的 npm 插件安装、启用、禁用、升级、降级和缺失代码卸载。 +- 插件:`pnpm test:docker:plugins` 覆盖本地路径、`file:`、带提升依赖的 npm registry、git moving refs、ClawHub 夹具、marketplace 更新,以及 Claude-bundle 启用/检查的安装/更新冒烟测试。`pnpm test:docker:plugin-update` 覆盖已安装插件的未变更更新行为。`pnpm test:docker:plugin-lifecycle-matrix` 覆盖带资源跟踪的 npm 插件安装、启用、禁用、升级、降级和缺失代码卸载。 要手动预构建并复用共享功能镜像: @@ -536,69 +585,31 @@ OPENCLAW_DOCKER_E2E_IMAGE=openclaw-docker-e2e-functional:local pnpm test:docker: OPENCLAW_DOCKER_E2E_IMAGE=openclaw-docker-e2e-functional:local OPENCLAW_SKIP_DOCKER_BUILD=1 pnpm test:docker:mcp-channels ``` -设置了套件特定的镜像覆盖项(例如 `OPENCLAW_GATEWAY_NETWORK_E2E_IMAGE`)时,它们仍会优先生效。当 `OPENCLAW_SKIP_DOCKER_BUILD=1` 指向远程共享镜像时,如果脚本发现本地还没有该镜像,就会拉取它。QR 和 installer Docker 测试会保留自己的 Dockerfile,因为它们验证的是包/安装行为,而不是共享的已构建应用运行时。 +设置套件专用的镜像覆盖项(例如 `OPENCLAW_GATEWAY_NETWORK_E2E_IMAGE`)时,仍会优先使用这些覆盖项。当 `OPENCLAW_SKIP_DOCKER_BUILD=1` 指向远程共享镜像时,如果本地尚不存在,脚本会拉取它。QR 和安装器 Docker 测试保留各自的 Dockerfile,因为它们验证的是包/安装行为,而不是共享的已构建应用运行时。 -live-model Docker 运行器还会将当前检出以只读方式绑定挂载,并 -将其暂存到容器内的临时工作目录中。这样可以保持运行时 -镜像精简,同时仍然针对你确切的本地源码/配置运行 Vitest。 -暂存步骤会跳过大型仅本地缓存和应用构建输出,例如 -`.pnpm-store`、`.worktrees`、`__openclaw_vitest__`,以及应用本地 `.build` 或 -Gradle 输出目录,这样 Docker live 运行就不会花费数分钟复制 -机器特定的制品。 -它们还会设置 `OPENCLAW_SKIP_CHANNELS=1`,这样 Gateway 网关 live 探测就不会在 -容器内启动真实的 Telegram/Discord 等渠道工作进程。 -`test:docker:live-models` 仍然运行 `pnpm test:live`,因此当你需要缩小或排除该 Docker 通道中的 -Gateway 网关 live 覆盖范围时,也要传入 -`OPENCLAW_LIVE_GATEWAY_*`。 -`test:docker:openwebui` 是更高层的兼容性冒烟测试:它会启动一个 -启用了 OpenAI 兼容 HTTP 端点的 OpenClaw Gateway 网关容器, -再启动一个固定版本的 Open WebUI 容器并连接到该 Gateway 网关,通过 -Open WebUI 登录,验证 `/api/models` 暴露 `openclaw/default`,然后通过 Open WebUI 的 -`/api/chat/completions` 代理发送一个真实的聊天请求。 -首次运行可能会明显更慢,因为 Docker 可能需要拉取 -Open WebUI 镜像,而 Open WebUI 也可能需要完成自己的冷启动设置。 -这个通道需要可用的 live 模型密钥,并且 `OPENCLAW_PROFILE_FILE` -(默认是 `~/.profile`)是在 Docker 化运行中提供它的主要方式。 -成功运行会打印一个小型 JSON 载荷,例如 `{ "ok": true, "model": -"openclaw/default", ... }`。 -`test:docker:mcp-channels` 是有意保持确定性的,不需要真实的 -Telegram、Discord 或 iMessage 账号。它会启动一个已预置数据的 Gateway 网关 -容器,启动第二个容器来派生 `openclaw mcp serve`,然后 -验证路由后的对话发现、转录读取、附件元数据、 -live 事件队列行为、出站发送路由,以及通过真实 stdio MCP 桥接的 Claude 风格渠道 + -权限通知。通知检查会直接检查原始 stdio MCP 帧,因此该冒烟测试验证的是 -桥接实际发出的内容,而不只是某个特定客户端 SDK 恰好暴露的内容。 -`test:docker:pi-bundle-mcp-tools` 是确定性的,不需要 live -模型密钥。它会构建仓库 Docker 镜像,在容器内启动一个真实的 stdio MCP 探测服务器, -通过嵌入式 Pi bundle -MCP 运行时物化该服务器,执行工具,然后验证 `coding` 和 `messaging` 保留 -`bundle-mcp` 工具,而 `minimal` 和 `tools.deny: ["bundle-mcp"]` 会过滤它们。 -`test:docker:cron-mcp-cleanup` 是确定性的,不需要 live 模型 -密钥。它会启动一个已预置数据的 Gateway 网关和真实 stdio MCP 探测服务器,运行一次 -隔离的 cron 轮次和一个 `/subagents spawn` 一次性子轮次,然后验证 -MCP 子进程在每次运行后都会退出。 +实时模型 Docker 运行器还会以只读方式绑定挂载当前检出,并将其暂存到容器内的临时工作目录中。这样可以保持运行时镜像轻量,同时仍针对你的确切本地源代码/配置运行 Vitest。暂存步骤会跳过大型仅本地缓存和应用构建输出,例如 `.pnpm-store`、`.worktrees`、`__openclaw_vitest__`,以及应用本地 `.build` 或 Gradle 输出目录,因此 Docker 真实运行不会花费数分钟复制特定机器的产物。它们还会设置 `OPENCLAW_SKIP_CHANNELS=1`,这样 Gateway 网关真实探测就不会在容器内启动真实的 Telegram/Discord 等渠道工作进程。`test:docker:live-models` 仍会运行 `pnpm test:live`,因此当你需要从该 Docker lane 中缩小或排除 Gateway 网关真实覆盖范围时,也要透传 `OPENCLAW_LIVE_GATEWAY_*`。`test:docker:openwebui` 是更高层级的兼容性冒烟测试:它会启动一个启用了 OpenAI 兼容 HTTP 端点的 OpenClaw Gateway 网关容器,启动一个固定版本的 Open WebUI 容器并让其连接到该 Gateway 网关,通过 Open WebUI 登录,验证 `/api/models` 暴露了 `openclaw/default`,然后通过 Open WebUI 的 `/api/chat/completions` 代理发送一个真实聊天请求。第一次运行可能明显更慢,因为 Docker 可能需要拉取 Open WebUI 镜像,并且 Open WebUI 可能需要完成自己的冷启动设置。该 lane 需要一个可用的真实模型密钥,而 `OPENCLAW_PROFILE_FILE`(默认是 `~/.profile`)是在 Docker 化运行中提供它的主要方式。成功运行会打印一个小型 JSON 负载,例如 `{ "ok": true, "model": "openclaw/default", ... }`。`test:docker:mcp-channels` 是有意保持确定性的,不需要真实的 Telegram、Discord 或 iMessage 账号。它会启动一个带种子数据的 Gateway 网关容器,启动第二个容器来生成 `openclaw mcp serve`,然后验证路由后的对话发现、转录读取、附件元数据、实时事件队列行为、出站发送路由,以及通过真实 stdio MCP bridge 发送的 Claude 风格渠道 + 权限通知。通知检查会直接检查原始 stdio MCP 帧,因此该冒烟测试验证的是 bridge 实际发出的内容,而不只是某个特定客户端 SDK 恰好暴露的内容。`test:docker:pi-bundle-mcp-tools` 是确定性的,不需要真实模型密钥。它会构建 repo Docker 镜像,在容器内启动一个真实 stdio MCP 探测服务器,通过嵌入式 Pi bundle MCP 运行时实例化该服务器,执行该工具,然后验证 `coding` 和 `messaging` 保留 `bundle-mcp` 工具,而 `minimal` 和 `tools.deny: ["bundle-mcp"]` 会过滤它们。`test:docker:cron-mcp-cleanup` 是确定性的,不需要真实模型密钥。它会启动一个带种子数据的 Gateway 网关和真实 stdio MCP 探测服务器,运行一次隔离的 cron 回合和一次 `/subagents spawn` 一次性子回合,然后验证 MCP 子进程会在每次运行后退出。 手动 ACP 自然语言线程冒烟测试(非 CI): - `bun scripts/dev/discord-acp-plain-language-smoke.ts --channel ...` -- 保留此脚本用于回归/调试工作流。ACP 线程路由验证以后可能还会需要它,因此不要删除。 +- 保留此脚本用于回归/调试工作流。ACP 线程路由验证可能还会再次需要它,因此不要删除它。 有用的环境变量: - `OPENCLAW_CONFIG_DIR=...`(默认:`~/.openclaw`)挂载到 `/home/node/.openclaw` - `OPENCLAW_WORKSPACE_DIR=...`(默认:`~/.openclaw/workspace`)挂载到 `/home/node/.openclaw/workspace` - `OPENCLAW_PROFILE_FILE=...`(默认:`~/.profile`)挂载到 `/home/node/.profile`,并在运行测试前 source -- `OPENCLAW_DOCKER_PROFILE_ENV_ONLY=1` 用于仅验证从 `OPENCLAW_PROFILE_FILE` source 的环境变量,使用临时配置/工作区目录且不挂载外部 CLI 凭证 -- `OPENCLAW_DOCKER_CLI_TOOLS_DIR=...`(默认:`~/.cache/openclaw/docker-cli-tools`)挂载到 `/home/node/.npm-global`,用于 Docker 内缓存 CLI 安装 +- `OPENCLAW_DOCKER_PROFILE_ENV_ONLY=1` 用于仅验证从 `OPENCLAW_PROFILE_FILE` source 的环境变量,使用临时配置/工作区目录,且不挂载外部 CLI 凭证 +- `OPENCLAW_DOCKER_CLI_TOOLS_DIR=...`(默认:`~/.cache/openclaw/docker-cli-tools`)挂载到 `/home/node/.npm-global`,用于 Docker 内部缓存 CLI 安装 - `$HOME` 下的外部 CLI 凭证目录/文件会以只读方式挂载到 `/host-auth...` 下,然后在测试开始前复制到 `/home/node/...` - 默认目录:`.minimax` - 默认文件:`~/.codex/auth.json`、`~/.codex/config.toml`、`.claude.json`、`~/.claude/.credentials.json`、`~/.claude/settings.json`、`~/.claude/settings.local.json` - - 缩小范围的提供商运行只会挂载从 `OPENCLAW_LIVE_PROVIDERS` / `OPENCLAW_LIVE_GATEWAY_PROVIDERS` 推断出的所需目录/文件 - - 可使用 `OPENCLAW_DOCKER_AUTH_DIRS=all`、`OPENCLAW_DOCKER_AUTH_DIRS=none`,或类似 `OPENCLAW_DOCKER_AUTH_DIRS=.claude,.codex` 的逗号列表手动覆盖 + - 缩窄的提供商运行只会挂载从 `OPENCLAW_LIVE_PROVIDERS` / `OPENCLAW_LIVE_GATEWAY_PROVIDERS` 推断出的所需目录/文件 + - 使用 `OPENCLAW_DOCKER_AUTH_DIRS=all`、`OPENCLAW_DOCKER_AUTH_DIRS=none`,或类似 `OPENCLAW_DOCKER_AUTH_DIRS=.claude,.codex` 的逗号列表来手动覆盖 - `OPENCLAW_LIVE_GATEWAY_MODELS=...` / `OPENCLAW_LIVE_MODELS=...` 用于缩小运行范围 - `OPENCLAW_LIVE_GATEWAY_PROVIDERS=...` / `OPENCLAW_LIVE_PROVIDERS=...` 用于在容器内过滤提供商 -- `OPENCLAW_SKIP_DOCKER_BUILD=1` 用于复用现有的 `openclaw:local-live` 镜像,适合不需要重新构建的重跑 -- `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1` 用于确保凭证来自 profile 存储(而不是 env) +- `OPENCLAW_SKIP_DOCKER_BUILD=1` 用于在不需要重新构建的重跑中复用现有 `openclaw:local-live` 镜像 +- `OPENCLAW_LIVE_REQUIRE_PROFILE_KEYS=1` 用于确保凭据来自 profile store(而不是 env) - `OPENCLAW_OPENWEBUI_MODEL=...` 用于选择 Gateway 网关为 Open WebUI 冒烟测试暴露的模型 - `OPENCLAW_OPENWEBUI_PROMPT=...` 用于覆盖 Open WebUI 冒烟测试使用的 nonce 检查提示 - `OPENWEBUI_IMAGE=...` 用于覆盖固定的 Open WebUI 镜像标签 @@ -606,41 +617,37 @@ MCP 子进程在每次运行后都会退出。 ## 文档完整性检查 文档编辑后运行文档检查:`pnpm check:docs`。 -当你也需要页内标题检查时,运行完整 Mintlify 锚点验证:`pnpm docs:check-links:anchors`。 +当你还需要进行页面内标题检查时,运行完整的 Mintlify anchor 验证:`pnpm docs:check-links:anchors`。 ## 离线回归(CI 安全) -这些是在没有真实提供商的情况下执行的“真实流水线”回归: +这些是不使用真实提供商的“真实 pipeline”回归: - Gateway 网关工具调用(mock OpenAI,真实 Gateway 网关 + Agent loop):`src/gateway/gateway.test.ts`(用例:"runs a mock OpenAI tool call end-to-end via gateway agent loop") -- Gateway 网关向导(WS `wizard.start`/`wizard.next`,写入配置并强制执行 auth):`src/gateway/gateway.test.ts`(用例:"runs wizard over ws and writes auth token config") +- Gateway 网关向导(WS `wizard.start`/`wizard.next`,写入配置 + 强制执行身份验证):`src/gateway/gateway.test.ts`(用例:"runs wizard over ws and writes auth token config") ## 智能体可靠性评估(Skills) -我们已经有一些 CI 安全测试,行为类似“智能体可靠性评估”: +我们已经有几个 CI 安全测试,行为类似“智能体可靠性评估”: - 通过真实 Gateway 网关 + Agent loop 进行 mock 工具调用(`src/gateway/gateway.test.ts`)。 - 验证会话接线和配置效果的端到端向导流程(`src/gateway/gateway.test.ts`)。 -Skills 仍然缺少的内容(见 [Skills](/zh-CN/tools/skills)): +Skills 仍缺少的内容(见 [Skills](/zh-CN/tools/skills)): -- **决策:** 当提示中列出 Skills 时,智能体是否选择了正确的 Skill(或避开无关的 Skill)? -- **合规:** 智能体是否在使用前读取 `SKILL.md`,并遵循必需步骤/参数? -- **工作流契约:** 断言工具顺序、会话历史承接和沙箱边界的多轮场景。 +- **决策:** 当 prompt 中列出 Skills 时,智能体是否会选择正确的 skill(或避免选择无关的 skill)? +- **合规:** 智能体是否会在使用前读取 `SKILL.md` 并遵循必需的步骤/参数? +- **工作流契约:** 断言工具顺序、会话历史延续和沙箱边界的多回合场景。 未来评估应优先保持确定性: -- 一个使用 mock 提供商的场景运行器,用于断言工具调用 + 顺序、Skill 文件读取和会话接线。 -- 一小套聚焦 Skill 的场景(使用与避开、门控、提示注入)。 -- 可选 live 评估(选择加入、受 env 门控)仅在 CI 安全套件就位后再添加。 +- 一个使用 mock 提供商的场景运行器,用于断言工具调用 + 顺序、skill 文件读取和会话接线。 +- 一小套聚焦 skill 的场景(使用与避免、门控、prompt injection)。 +- 可选的真实评估(选择启用,通过环境变量门控)只在 CI 安全套件就位后添加。 -## 契约测试(插件和渠道形状) +## 契约测试(插件和渠道形态) -契约测试会验证每个已注册的插件和渠道都符合其 -接口契约。它们会遍历所有已发现的插件,并运行一套 -形状和行为断言。默认的 `pnpm test` 单元通道会有意跳过 -这些共享接缝和冒烟文件;当你触碰共享渠道或提供商表面时, -请显式运行契约命令。 +契约测试会验证每个已注册插件和渠道是否符合其接口契约。它们会遍历所有发现的插件,并运行一组形态和行为断言。默认的 `pnpm test` 单元 lane 会有意跳过这些共享边界和冒烟文件;当你触及共享渠道或提供商表面时,请显式运行契约命令。 ### 命令 @@ -652,59 +659,59 @@ Skills 仍然缺少的内容(见 [Skills](/zh-CN/tools/skills)): 位于 `src/channels/plugins/contracts/*.contract.test.ts`: -- **plugin** - 基本插件形状(id、name、capabilities) +- **plugin** - 基础插件形态(id、name、capabilities) - **setup** - 设置向导契约 - **session-binding** - 会话绑定行为 -- **outbound-payload** - 消息载荷结构 +- **outbound-payload** - 消息负载结构 - **inbound** - 入站消息处理 -- **actions** - 渠道操作处理器 -- **threading** - 线程 ID 处理 -- **directory** - 目录/花名册 API -- **group-policy** - 群组策略执行 +- **actions** - 渠道 action 处理器 +- **threading** - Thread ID 处理 +- **directory** - Directory/roster API +- **group-policy** - 群组策略强制执行 ### 提供商 Status 契约 位于 `src/plugins/contracts/*.contract.test.ts`。 - **status** - 渠道 Status 探测 -- **registry** - 插件注册表形状 +- **registry** - 插件 registry 形态 ### 提供商契约 位于 `src/plugins/contracts/*.contract.test.ts`: -- **auth** - Auth 流契约 -- **auth-choice** - Auth 选择/选取 -- **catalog** - 模型目录 API +- **auth** - 身份验证流程契约 +- **auth-choice** - 身份验证选择/选定 +- **catalog** - 模型 catalog API - **discovery** - 插件发现 - **loader** - 插件加载 - **runtime** - 提供商运行时 -- **shape** - 插件形状/接口 +- **shape** - 插件形态/接口 - **wizard** - 设置向导 ### 何时运行 -- 更改 plugin-sdk 导出或子路径后 +- 更改 plugin-sdk exports 或 subpaths 后 - 添加或修改渠道或提供商插件后 - 重构插件注册或发现后 -契约测试会在 CI 中运行,并且不需要真实 API key。 +契约测试会在 CI 中运行,并且不需要真实 API 密钥。 ## 添加回归(指导) -当你修复 live 中发现的提供商/模型问题时: +当你修复在真实运行中发现的提供商/模型问题时: -- 尽可能添加 CI 安全回归(mock/stub 提供商,或捕获确切的请求形状转换) -- 如果它本质上只能 live 测试(速率限制、auth 策略),保持 live 测试范围很窄,并通过环境变量选择加入 -- 优先定位到能够捕获该 bug 的最小层: - - 提供商请求转换/重放 bug → 直接模型测试 - - Gateway 网关会话/历史/工具流水线 bug → Gateway 网关 live 冒烟测试或 CI 安全 Gateway 网关 mock 测试 +- 尽可能添加一个 CI 安全回归(mock/stub 提供商,或捕获确切的请求形态转换) +- 如果它本质上只能真实运行(速率限制、身份验证策略),请保持真实测试范围狭窄,并通过环境变量选择启用 +- 优先定位到能捕获 bug 的最小层级: + - 提供商请求转换/replay bug → 直接模型测试 + - Gateway 网关会话/历史/工具 pipeline bug → Gateway 网关真实冒烟测试或 CI 安全 Gateway 网关 mock 测试 - SecretRef 遍历护栏: - - `src/secrets/exec-secret-ref-id-parity.test.ts` 会从注册表元数据(`listSecretTargetRegistryEntries()`)为每个 SecretRef 类派生一个采样目标,然后断言包含遍历段的 exec id 会被拒绝。 - - 如果你在 `src/secrets/target-registry-data.ts` 中添加新的 `includeInPlan` SecretRef 目标族,请更新该测试中的 `classifyTargetClass`。该测试会有意在未分类目标 id 上失败,确保新类不会被静默跳过。 + - `src/secrets/exec-secret-ref-id-parity.test.ts` 会从 registry 元数据(`listSecretTargetRegistryEntries()`)为每个 SecretRef class 派生一个采样目标,然后断言 traversal-segment exec id 会被拒绝。 + - 如果你在 `src/secrets/target-registry-data.ts` 中添加新的 `includeInPlan` SecretRef 目标族,请更新该测试中的 `classifyTargetClass`。该测试会有意在未分类目标 id 上失败,因此新 class 不能被静默跳过。 ## 相关 -- [Testing live](/zh-CN/help/testing-live) -- [Testing updates and plugins](/zh-CN/help/testing-updates-plugins) +- [测试真实运行](/zh-CN/help/testing-live) +- [更新和插件测试](/zh-CN/help/testing-updates-plugins) - [CI](/zh-CN/ci) diff --git a/docs/zh-CN/reference/RELEASING.md b/docs/zh-CN/reference/RELEASING.md index 558c0734e..868748bd1 100644 --- a/docs/zh-CN/reference/RELEASING.md +++ b/docs/zh-CN/reference/RELEASING.md @@ -1,15 +1,15 @@ --- read_when: - 正在查找公开发布渠道定义 - - 运行发布验证或软件包验收 + - 运行发布验证或包验收 - 查找版本命名和发布节奏 summary: 发布通道、操作员检查清单、验证环境、版本命名和发布节奏 title: 发布策略 x-i18n: - generated_at: "2026-05-05T01:33:45Z" + generated_at: "2026-05-05T04:26:58Z" model: gpt-5.5 provider: openai - source_hash: 41886d3bb2f970e6a86944e5ff207b1b29b1b64b1f234d45f626fed19cf032b3 + source_hash: e5f380b106fb304c932715d7b2ec5f92715b2572e7c582d7cfa9786a766730fd source_path: reference/RELEASING.md workflow: 16 --- @@ -17,140 +17,130 @@ x-i18n: OpenClaw 有三个公开发布通道: - stable:带标签的发布,默认发布到 npm `beta`,或在明确请求时发布到 npm `latest` -- beta:发布到 npm `beta` 的预发布标签 +- beta:预发布标签,发布到 npm `beta` - dev:`main` 的移动头部 ## 版本命名 -- 稳定版发布版本:`YYYY.M.D` +- 稳定发布版本:`YYYY.M.D` - Git 标签:`vYYYY.M.D` -- 稳定版修正发布版本:`YYYY.M.D-N` +- 稳定修正发布版本:`YYYY.M.D-N` - Git 标签:`vYYYY.M.D-N` - Beta 预发布版本:`YYYY.M.D-beta.N` - Git 标签:`vYYYY.M.D-beta.N` -- 月份或日期不要补零 -- `latest` 表示当前已提升的稳定版 npm 发布 +- 月和日不要补零 +- `latest` 表示当前已提升的稳定 npm 发布 - `beta` 表示当前 beta 安装目标 -- 稳定版和稳定版修正发布默认发布到 npm `beta`;发布操作员可以明确指定 `latest`,或稍后提升经过验证的 beta 构建 -- 每个稳定版 OpenClaw 发布都会同时交付 npm 包和 macOS 应用; - beta 发布通常会先验证并发布 npm/包路径,而 mac 应用构建/签名/公证保留给稳定版,除非明确请求 +- 稳定版和稳定修正版默认发布到 npm `beta`;发布操作员可以明确指定 `latest`,或稍后提升一个已验证的 beta 构建 +- 每个稳定 OpenClaw 发布都会同时交付 npm 包和 macOS 应用; + beta 发布通常先验证并发布 npm/包路径,Mac 应用构建/签名/公证保留给稳定版,除非明确请求 ## 发布节奏 -- 发布先进入 beta -- 只有在最新 beta 验证通过后,才会进入稳定版 -- 维护者通常从基于当前 `main` 创建的 `release/YYYY.M.D` 分支切出发布, +- 发布按 beta 优先推进 +- 只有在最新 beta 验证通过后才跟进稳定版 +- 维护者通常从当前 `main` 创建的 `release/YYYY.M.D` 分支切出发布, 这样发布验证和修复不会阻塞 `main` 上的新开发 -- 如果某个 beta 标签已经推送或发布并需要修复,维护者会切出下一个 `-beta.N` 标签,而不是删除或重新创建旧的 beta 标签 +- 如果 beta 标签已经推送或发布并需要修复,维护者会切出下一个 + `-beta.N` 标签,而不是删除或重新创建旧的 beta 标签 - 详细发布流程、审批、凭证和恢复说明仅限维护者使用 ## 发布操作员检查清单 -此检查清单是发布流程的公开形态。私有凭证、 -签名、公证、dist-tag 恢复和紧急回滚详情保留在 -仅限维护者使用的发布运行手册中。 +此检查清单是发布流程的公开形态。私有凭证、签名、公证、dist-tag 恢复和紧急回滚细节保留在仅限维护者的发布运行手册中。 1. 从当前 `main` 开始:拉取最新内容,确认目标提交已推送, - 并确认当前 `main` 的 CI 状态足够健康,可以从它创建分支。 + 并确认当前 `main` CI 足够健康,可以从它创建分支。 2. 使用 `/changelog` 根据真实提交历史重写顶部 `CHANGELOG.md` 章节, - 保持条目面向用户,提交并推送它,然后在创建分支前再次 rebase/pull。 -3. 检查 + 保持条目面向用户,提交并推送,然后在创建分支前再 rebase/pull 一次。 +3. 查看 `src/plugins/compat/registry.ts` 和 - `src/commands/doctor/shared/deprecation-compat.ts` 中的发布兼容性记录。只有当升级路径仍被覆盖时才移除过期兼容性, - 或记录为什么有意继续保留。 -4. 从当前 `main` 创建 `release/YYYY.M.D`;不要直接在 `main` 上执行常规发布工作。 -5. 为预期标签更新每个必需的版本位置,运行 - `pnpm plugins:sync`,使可发布的插件包共享发布版本和兼容性元数据,然后运行本地确定性预检: + `src/commands/doctor/shared/deprecation-compat.ts` 中的发布兼容性记录。只有在升级路径仍然被覆盖时才移除过期兼容性,否则记录为什么有意继续保留。 +4. 从当前 `main` 创建 `release/YYYY.M.D`;不要直接在 `main` 上做常规发布工作。 +5. 为目标标签更新所有必需的版本位置,运行 + `pnpm plugins:sync`,让可发布的插件包共享发布版本和兼容性元数据,然后运行本地确定性预检: `pnpm check:test-types`、`pnpm check:architecture`、 `pnpm build && pnpm ui:build`、`pnpm plugins:sync:check` 和 `pnpm release:check`。 -6. 使用 `preflight_only=true` 运行 `OpenClaw NPM Release`。在标签存在之前, - 允许使用完整 40 字符的发布分支 SHA 进行仅验证预检。保存成功的 `preflight_run_id`。 -7. 针对发布分支、标签或完整提交 SHA,使用 `Full Release Validation` 启动所有预发布测试。这是四个大型发布测试盒子的唯一手动入口点:Vitest、Docker、QA Lab 和 Package。 -8. 如果验证失败,在发布分支上修复,并重新运行能证明修复的最小失败文件、通道、工作流作业、包配置、提供商或模型允许列表。只有当变更范围使先前证据失效时,才重新运行完整总控流程。 -9. 对于 beta,标记 `vYYYY.M.D-beta.N`,然后从匹配的 `release/YYYY.M.D` 分支运行 `OpenClaw Release Publish`。它会验证 `pnpm plugins:sync:check`, - 先将所有可发布的插件包发布到 npm,再将同一组以 ClawPack npm-pack tarball 的形式发布到 ClawHub, - 然后使用匹配的 dist-tag 提升已准备好的 OpenClaw npm 预检产物。发布后,针对已发布的 `openclaw@YYYY.M.D-beta.N` 或 - `openclaw@beta` 包运行发布后包验收。如果已推送或已发布的预发布需要修复, - 切出下一个匹配的预发布编号;不要删除或重写旧的预发布。 -10. 对于稳定版,只有在已验证的 beta 或候选发布具备所需验证证据后才继续。 - 稳定版 npm 发布也通过 - `OpenClaw Release Publish`,并通过 - `preflight_run_id` 复用成功的预检产物;稳定版 macOS 发布就绪还需要 `main` 上的 - 打包 `.zip`、`.dmg`、`.dSYM.zip` 和更新后的 `appcast.xml`。 -11. 发布后,运行 npm 发布后验证器,在需要发布后渠道证明时运行可选的独立已发布 npm Telegram E2E, - 在需要时进行 dist-tag 提升,根据完整匹配的 `CHANGELOG.md` 章节生成 GitHub 发布/预发布说明, - 并执行发布公告步骤。 +6. 运行带 `preflight_only=true` 的 `OpenClaw NPM Release`。在标签存在之前, + 允许使用完整的 40 字符发布分支 SHA 进行仅验证预检。保存成功的 `preflight_run_id`。 +7. 对发布分支、标签或完整提交 SHA 运行 `Full Release Validation`,启动所有预发布测试。这是四个大型发布测试盒子的唯一手动入口点:Vitest、Docker、QA Lab 和 Package。 +8. 如果验证失败,在发布分支上修复,并重新运行能证明修复的最小失败文件、通道、工作流作业、包配置、提供商或模型 allowlist。只有当变更表面让先前证据失效时,才重新运行完整总控流程。 +9. 对 beta,标记 `vYYYY.M.D-beta.N`,然后从匹配的 `release/YYYY.M.D` 分支运行 `OpenClaw Release Publish`。它会验证 `pnpm plugins:sync:check`,先将所有可发布的插件包发布到 npm,再将同一组包作为 ClawPack npm-pack tarball 发布到 ClawHub,随后用匹配的 dist-tag 提升已准备好的 OpenClaw npm 预检制品。发布后,针对已发布的 `openclaw@YYYY.M.D-beta.N` 或 `openclaw@beta` 包运行发布后包验收。如果已推送或已发布的预发布需要修复,切出下一个匹配的预发布编号;不要删除或重写旧预发布。 +10. 对稳定版,只有在已验证的 beta 或发布候选版本具备所需验证证据后才继续。稳定版 npm 发布也通过 + `OpenClaw Release Publish` 进行,并通过 + `preflight_run_id` 复用成功的预检制品;稳定版 macOS 发布就绪还要求 `main` 上有打包后的 `.zip`、`.dmg`、`.dSYM.zip` 和更新后的 `appcast.xml`。 +11. 发布后,运行 npm 发布后验证器;在需要发布后渠道证明时,可选运行独立的已发布 npm Telegram E2E;在需要时进行 dist-tag 提升;根据完整匹配的 `CHANGELOG.md` 章节生成 GitHub 发布/预发布说明;并执行发布公告步骤。 ## 发布预检 -- 在发布预检前运行 `pnpm check:test-types`,这样测试 TypeScript 会在更快的本地 `pnpm check` 门禁之外继续被覆盖 -- 在发布预检前运行 `pnpm check:architecture`,这样更广泛的导入循环和架构边界检查会在更快的本地门禁之外保持绿色 -- 在 `pnpm release:check` 前运行 `pnpm build && pnpm ui:build`,这样预期的 `dist/*` 发布产物和 Control UI 包会存在,可供打包验证步骤使用 -- 在根版本号提升后、打标签前运行 `pnpm plugins:sync`。它会更新可发布插件包版本、OpenClaw peer/API 兼容性元数据、构建元数据和插件 changelog 存根,使其匹配核心发布版本。`pnpm plugins:sync:check` 是非变更型发布保护检查;如果忘记了此步骤,发布工作流会在任何注册表变更前失败。 -- 在发布批准前运行手动 `Full Release Validation` 工作流,从一个入口点启动所有预发布测试盒。它接受分支、标签或完整提交 SHA,分发手动 `CI`,并为安装冒烟、包验收、跨 OS 包检查、QA Lab parity、Matrix 和 Telegram lane 分发 `OpenClaw Release Checks`。稳定版/默认运行会将详尽的 live/E2E 和 Docker 发布路径 soak 保持在 `run_release_soak=true` 之后;`release_profile=full` 会强制启用 soak。使用 `release_profile=full` 和 `rerun_group=all` 时,它还会针对来自发布检查的 `release-package-under-test` 产物运行包 Telegram E2E。发布后,如果同一个 Telegram E2E 也应验证已发布的 npm 包,请提供 `npm_telegram_package_spec`。发布后,如果 Package Acceptance 应针对已发布的 npm 包而不是按 SHA 构建的产物运行其包/更新矩阵,请提供 `package_acceptance_package_spec`。当私有证据报告应证明验证匹配已发布的 npm 包但不强制运行 Telegram E2E 时,请提供 `evidence_package_spec`。示例: +- 在发布预检前运行 `pnpm check:test-types`,以便测试 TypeScript 在更快的本地 `pnpm check` 门禁之外仍保持覆盖 +- 在发布预检前运行 `pnpm check:architecture`,以便更广泛的导入循环和架构边界检查在更快的本地门禁之外保持绿色 +- 在 `pnpm release:check` 前运行 `pnpm build && pnpm ui:build`,以便打包验证步骤所需的 `dist/*` 发布产物和 Control UI 包存在 +- 在根版本提升之后、打标签之前运行 `pnpm plugins:sync`。它会更新可发布插件包版本、OpenClaw peer/API 兼容性元数据、构建元数据和插件变更日志存根,使其与核心发布版本匹配。`pnpm plugins:sync:check` 是非变更式发布守卫;如果忘记此步骤,发布工作流会在任何 registry 变更之前失败。 +- 在发布批准前运行手动 `Full Release Validation` 工作流,从一个入口点启动所有预发布测试盒。它接受分支、标签或完整提交 SHA,分发手动 `CI`,并分发 `OpenClaw Release Checks`,覆盖安装 smoke、包验收、跨 OS 包检查、QA Lab parity、Matrix 和 Telegram 通道。稳定版/默认运行会把详尽的 live/E2E 和 Docker 发布路径 soak 保留在 `run_release_soak=true` 后面;`release_profile=full` 会强制启用 soak。使用 `release_profile=full` 和 `rerun_group=all` 时,它还会针对发布检查中的 `release-package-under-test` 产物运行包 Telegram E2E。发布后提供 `npm_telegram_package_spec`,当同一个 Telegram E2E 也应验证已发布的 npm 包时使用。发布后提供 `package_acceptance_package_spec`,当 Package Acceptance 应针对已发货的 npm 包而非按 SHA 构建的产物运行其包/更新矩阵时使用。提供 `evidence_package_spec`,当私有证据报告应证明验证匹配已发布的 npm 包,而不强制运行 Telegram E2E 时使用。示例: `gh workflow run full-release-validation.yml --ref main -f ref=release/YYYY.M.D` -- 当你希望在发布工作继续进行时,为包候选版本获取旁路证明,请运行手动 `Package Acceptance` 工作流。对 `openclaw@beta`、`openclaw@latest` 或精确发布版本使用 `source=npm`;使用 `source=ref` 以当前 `workflow_ref` harness 打包可信的 `package_ref` 分支/标签/SHA;对带必需 SHA-256 的 HTTPS tarball 使用 `source=url`;或对另一个 GitHub Actions 运行上传的 tarball 使用 `source=artifact`。该工作流会将候选版本解析为 `package-under-test`,针对该 tarball 复用 Docker E2E 发布调度器,并可通过 `telegram_mode=mock-openai` 或 `telegram_mode=live-frontier` 针对同一个 tarball 运行 Telegram QA。当所选 Docker lane 包含 `published-upgrade-survivor` 时,包产物就是候选版本,`published_upgrade_survivor_baseline` 会选择已发布的基线。 +- 当你想在发布工作继续进行时为包候选项获取旁路证明,运行手动 `Package Acceptance` 工作流。对 `openclaw@beta`、`openclaw@latest` 或精确发布版本使用 `source=npm`;用 `source=ref` 通过当前 `workflow_ref` harness 打包受信任的 `package_ref` 分支/标签/SHA;对带必需 SHA-256 的 HTTPS tarball 使用 `source=url`;或对另一个 GitHub Actions 运行上传的 tarball 使用 `source=artifact`。该工作流会将候选项解析为 `package-under-test`,针对该 tarball 复用 Docker E2E 发布调度器,并且可用 `telegram_mode=mock-openai` 或 `telegram_mode=live-frontier` 针对同一 tarball 运行 Telegram QA。当选中的 Docker 通道包含 `published-upgrade-survivor` 时,包产物就是候选项,`published_upgrade_survivor_baseline` 选择已发布的基线。 示例:`gh workflow run package-acceptance.yml --ref main -f workflow_ref=main -f source=npm -f package_spec=openclaw@beta -f suite_profile=product -f published_upgrade_survivor_baseline=openclaw@2026.4.26 -f telegram_mode=mock-openai` - 常见配置档: - - `smoke`:安装/渠道/智能体、Gateway 网关网络和配置重载 lane - - `package`:无需 OpenWebUI 或 live ClawHub 的产物原生包/更新/插件 lane - - `product`:包配置档加上 MCP 渠道、cron/subagent 清理、OpenAI web search 和 OpenWebUI + 常见配置: + - `smoke`:安装/渠道/智能体、Gateway 网关网络和配置重载通道 + - `package`:产物原生的包/更新/插件通道,不含 OpenWebUI 或 live ClawHub + - `product`:包配置加上 MCP 渠道、cron/subagent 清理、OpenAI web 搜索和 OpenWebUI - `full`:带 OpenWebUI 的 Docker 发布路径分块 - `custom`:用于聚焦重跑的精确 `docker_lanes` 选择 -- 当你只需要发布候选版本的完整常规 CI 覆盖时,直接运行手动 `CI` 工作流。手动 CI 分发会绕过 changed 作用域并强制运行 Linux Node 分片、内置插件分片、渠道契约、Node 22 兼容性、`check`、`check-additional`、构建冒烟、文档检查、Python skills、Windows、macOS、Android 和 Control UI i18n lane。 +- 当你只需要发布候选项的完整常规 CI 覆盖时,直接运行手动 `CI` 工作流。手动 CI 分发会绕过变更范围限定,并强制运行 Linux Node 分片、内置插件分片、渠道契约、Node 22 兼容性、`check`、`check-additional`、构建 smoke、文档检查、Python Skills、Windows、macOS、Android 和 Control UI i18n 通道。 示例:`gh workflow run ci.yml --ref release/YYYY.M.D` -- 验证发布遥测时运行 `pnpm qa:otel:smoke`。它会通过本地 OTLP/HTTP receiver 演练 QA-lab,并验证导出的 trace span 名称、有界属性以及内容/标识符脱敏,无需 Opik、Langfuse 或其他外部 collector。 +- 验证发布 telemetry 时运行 `pnpm qa:otel:smoke`。它通过本地 OTLP/HTTP receiver 运行 QA-lab,并验证导出的 trace span 名称、有界属性以及内容/标识符脱敏,无需 Opik、Langfuse 或其他外部 collector。 - 每次打标签发布前运行 `pnpm release:check` -- 标签存在后,运行 `OpenClaw Release Publish` 执行会产生变更的发布序列。从 `release/YYYY.M.D` 分发它(或在发布 main 可达标签时从 `main` 分发),传入发布标签和成功的 OpenClaw npm `preflight_run_id`,并保留默认插件发布范围 `all-publishable`,除非你在有意执行聚焦修复。该工作流会串行化插件 npm 发布、插件 ClawHub 发布和 OpenClaw npm 发布,确保核心包不会早于其外置插件发布。 +- 标签存在后,运行 `OpenClaw Release Publish` 执行会产生变更的发布序列。从 `release/YYYY.M.D` 分发它(或在发布 main 可达标签时从 `main` 分发),传入发布标签和成功的 OpenClaw npm `preflight_run_id`,并保持默认插件发布范围 `all-publishable`,除非你是在有意运行聚焦修复。该工作流会串行化插件 npm 发布、插件 ClawHub 发布和 OpenClaw npm 发布,确保核心包不会在其外部化插件之前发布。 - 发布检查现在在单独的手动工作流中运行: `OpenClaw Release Checks` -- `OpenClaw Release Checks` 还会在发布批准前运行 QA Lab mock parity lane,以及快速 live Matrix 配置档和 Telegram QA lane。live lane 使用 `qa-live-shared` 环境;Telegram 还使用 Convex CI 凭证租约。当你希望并行获取完整 Matrix 传输、媒体和 E2EE 清单时,请使用 `matrix_profile=all` 和 `matrix_shards=true` 运行手动 `QA-Lab - All Lanes` 工作流。 +- `OpenClaw Release Checks` 还会在发布批准前运行 QA Lab mock parity 通道,以及快速 live Matrix 配置和 Telegram QA 通道。live 通道使用 `qa-live-shared` 环境;Telegram 还使用 Convex CI 凭证租约。当你想并行获取完整 Matrix 传输、媒体和 E2EE 清单时,运行手动 `QA-Lab - All Lanes` 工作流,并设置 `matrix_profile=all` 和 `matrix_shards=true`。 - 跨 OS 安装和升级运行时验证是公开 `OpenClaw Release Checks` 和 `Full Release Validation` 的一部分,它们会直接调用可复用工作流 `.github/workflows/openclaw-cross-os-release-checks-reusable.yml` -- 此拆分是有意的:保持真实 npm 发布路径简短、确定且聚焦产物,同时将较慢的 live 检查保留在自己的 lane 中,避免它们拖慢或阻塞发布 -- 带 secret 的发布检查应通过 `Full Release Validation` 分发,或从 `main`/release workflow ref 分发,这样工作流逻辑和 secret 都保持受控 -- 只要解析出的提交可从 OpenClaw 分支或发布标签到达,`OpenClaw Release Checks` 就接受分支、标签或完整提交 SHA -- `OpenClaw NPM Release` 仅验证预检也接受当前完整 40 字符 workflow-branch 提交 SHA,无需已推送标签 +- 此拆分是有意的:让真实 npm 发布路径保持短、确定且聚焦产物,同时较慢的 live 检查保留在自己的通道中,避免拖慢或阻塞发布 +- 带密钥的发布检查应通过 `Full Release Validation` 分发,或从 `main`/release 工作流 ref 分发,以便工作流逻辑和密钥保持受控 +- `OpenClaw Release Checks` 接受分支、标签或完整提交 SHA,只要解析出的提交可从 OpenClaw 分支或发布标签到达 +- `OpenClaw NPM Release` 仅验证预检也接受当前完整 40 字符工作流分支提交 SHA,无需已推送标签 - 该 SHA 路径仅用于验证,不能提升为真实发布 -- 在 SHA 模式下,工作流仅为包元数据检查合成 `v`;真实发布仍然需要真实发布标签 -- 两个工作流都会把真实发布和提升路径保留在 GitHub 托管 runner 上,而非变更型验证路径可以使用更大的 Blacksmith Linux runner -- 该工作流使用 `OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_CACHE_TEST=1 pnpm test:live:cache`,并同时使用 `OPENAI_API_KEY` 和 `ANTHROPIC_API_KEY` 工作流 secret -- npm 发布预检不再等待单独的发布检查 lane -- 在批准前运行 `RELEASE_TAG=vYYYY.M.D node --import tsx scripts/openclaw-npm-release-check.ts`(或匹配的 beta/correction 标签) -- npm 发布后,运行 `node --import tsx scripts/openclaw-npm-postpublish-verify.ts YYYY.M.D`(或匹配的 beta/correction 版本),以在全新的临时 prefix 中验证已发布注册表安装路径 -- beta 发布后,运行 `OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC=openclaw@YYYY.M.D-beta.N OPENCLAW_NPM_TELEGRAM_CREDENTIAL_SOURCE=convex OPENCLAW_NPM_TELEGRAM_CREDENTIAL_ROLE=ci pnpm test:docker:npm-telegram-live`,使用共享租约 Telegram 凭证池,针对已发布 npm 包验证已安装包新手引导、Telegram 设置和真实 Telegram E2E。本地维护者的一次性运行可以省略 Convex 变量,并直接传入三个 `OPENCLAW_QA_TELEGRAM_*` 环境变量凭证。 -- 若要从维护者机器运行完整的发布后 beta 冒烟,请使用 `pnpm release:beta-smoke -- --beta betaN`。该 helper 会运行 Parallels npm 更新/全新目标验证,分发 `NPM Telegram Beta E2E`,轮询精确工作流运行,下载产物并打印 Telegram 报告。 -- 维护者可以通过手动 `NPM Telegram Beta E2E` 工作流,在 GitHub Actions 中运行同一发布后检查。它有意仅手动运行,不会在每次 merge 时运行。 +- 在 SHA 模式下,工作流只为包元数据检查合成 `v`;真实发布仍需要真实发布标签 +- 两个工作流都把真实发布和提升路径保留在 GitHub-hosted runners 上,而非变更式验证路径可以使用更大的 Blacksmith Linux runners +- 该工作流会使用 `OPENCLAW_LIVE_TEST=1 OPENCLAW_LIVE_CACHE_TEST=1 pnpm test:live:cache`,并同时使用 `OPENAI_API_KEY` 和 `ANTHROPIC_API_KEY` 工作流密钥 +- npm 发布预检不再等待单独的发布检查通道 +- 在批准前运行 `RELEASE_TAG=vYYYY.M.D node --import tsx scripts/openclaw-npm-release-check.ts`(或匹配的 beta/修正版标签) +- npm 发布后,运行 `node --import tsx scripts/openclaw-npm-postpublish-verify.ts YYYY.M.D`(或匹配的 beta/修正版版本),以在全新的临时前缀中验证已发布 registry 安装路径 +- beta 发布后,运行 `OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC=openclaw@YYYY.M.D-beta.N OPENCLAW_NPM_TELEGRAM_CREDENTIAL_SOURCE=convex OPENCLAW_NPM_TELEGRAM_CREDENTIAL_ROLE=ci pnpm test:docker:npm-telegram-live`,使用共享租约 Telegram 凭证池,针对已发布的 npm 包验证已安装包的新手引导、Telegram 设置和真实 Telegram E2E。本地维护者临时单次运行可以省略 Convex 变量,并直接传入三个 `OPENCLAW_QA_TELEGRAM_*` 环境变量凭证。 +- 要从维护者机器运行完整的发布后 beta smoke,请使用 `pnpm release:beta-smoke -- --beta betaN`。该 helper 会运行 Parallels npm 更新/全新目标验证,分发 `NPM Telegram Beta E2E`,轮询精确工作流运行,下载产物,并打印 Telegram 报告。 +- 维护者可以通过手动 `NPM Telegram Beta E2E` 工作流,从 GitHub Actions 运行同样的发布后检查。它有意仅支持手动运行,不会在每次合并时运行。 - 维护者发布自动化现在使用先预检后提升: - 真实 npm 发布必须通过成功的 npm `preflight_run_id` - 真实 npm 发布必须从与成功预检运行相同的 `main` 或 `release/YYYY.M.D` 分支分发 - 稳定版 npm 发布默认使用 `beta` - 稳定版 npm 发布可以通过工作流输入显式指定 `latest` - - 基于 token 的 npm dist-tag 变更现在位于 `openclaw/releases-private/.github/workflows/openclaw-npm-dist-tags.yml` 以确保安全,因为 `npm dist-tag add` 仍需要 `NPM_TOKEN`,而公开仓库保持仅 OIDC 发布 - - 公开 `macOS Release` 仅用于验证;当标签仅存在于 release 分支上但工作流从 `main` 分发时,请设置 `public_release_branch=release/YYYY.M.D` + - 基于 token 的 npm dist-tag 变更现在位于 `openclaw/releases-private/.github/workflows/openclaw-npm-dist-tags.yml`,出于安全原因,因为 `npm dist-tag add` 仍需要 `NPM_TOKEN`,而公开仓库保持仅 OIDC 发布 + - 公开 `macOS Release` 仅用于验证;当标签只存在于发布分支上,但工作流从 `main` 分发时,设置 `public_release_branch=release/YYYY.M.D` - 真实私有 mac 发布必须通过成功的私有 mac `preflight_run_id` 和 `validate_run_id` - 真实发布路径会提升已准备好的产物,而不是再次重建它们 -- 对于像 `YYYY.M.D-N` 这样的稳定版修正发布,发布后验证器还会检查从 `YYYY.M.D` 到 `YYYY.M.D-N` 的同一临时 prefix 升级路径,确保发布修正不会静默地让较旧的全局安装停留在基础稳定版 payload 上 -- 除非 tarball 同时包含 `dist/control-ui/index.html` 和非空 `dist/control-ui/assets/` payload,否则 npm 发布预检会封闭失败,避免我们再次发布空的浏览器 dashboard -- 发布后验证还会检查已发布插件入口点和包元数据是否存在于已安装注册表布局中。缺少插件运行时 payload 的发布会导致 postpublish verifier 失败,且不能提升为 `latest`。 -- `pnpm test:install:smoke` 还会对候选更新 tarball 执行 npm pack `unpackedSize` 预算限制,因此安装器 e2e 会在发布发布路径前捕获意外的打包膨胀 -- 如果发布工作触及 CI planning、插件 timing manifest 或插件测试矩阵,请在批准前重新生成并审查由 planner 拥有的 `.github/workflows/plugin-prerelease.yml` 中的 `plugin-prerelease-extension-shard` 矩阵输出,确保发布说明不会描述过时的 CI 布局 -- 稳定版 macOS 发布就绪状态还包括 updater surface: - - GitHub release 最终必须包含打包后的 `.zip`、`.dmg` 和 `.dSYM.zip` +- 对于类似 `YYYY.M.D-N` 的稳定修正版发布,发布后验证器还会检查同一临时前缀下从 `YYYY.M.D` 到 `YYYY.M.D-N` 的升级路径,确保发布修正不会悄悄让旧的全局安装停留在基础稳定版 payload 上 +- npm 发布预检默认失败关闭,除非 tarball 同时包含 `dist/control-ui/index.html` 和非空 `dist/control-ui/assets/` payload,以避免再次发布空的浏览器 dashboard +- 发布后验证还会检查已发布插件入口点和包元数据是否存在于已安装的 registry 布局中。缺少插件运行时 payload 的发布会导致 postpublish 验证器失败,且不能提升到 `latest`。 +- `pnpm test:install:smoke` 还会对候选更新 tarball 强制执行 npm pack `unpackedSize` 预算,因此安装器 e2e 会在发布路径发布前捕获意外的打包膨胀 +- 如果发布工作触及 CI 规划、插件时序清单或插件测试矩阵,请在批准前重新生成并审查由规划器拥有的 `.github/workflows/plugin-prerelease.yml` 中的 `plugin-prerelease-extension-shard` 矩阵输出,确保发布说明不会描述过时的 CI 布局 +- 稳定版 macOS 发布就绪还包括 updater 表面: + - GitHub release 最终必须包含打包的 `.zip`、`.dmg` 和 `.dSYM.zip` - 发布后,`main` 上的 `appcast.xml` 必须指向新的稳定版 zip - - 打包后的 app 必须保留非 debug bundle id、非空 Sparkle feed URL,以及不低于该发布版本规范 Sparkle 构建下限的 `CFBundleVersion` + - 打包后的应用必须保持非调试 bundle id、非空 Sparkle feed URL,以及不低于该发布版本规范 Sparkle 构建下限的 `CFBundleVersion` ## 发布测试盒 -`Full Release Validation` 是操作者从一个入口点启动所有预发布测试的方式。若要在快速变动分支上获得固定提交证明,请使用 helper,让每个子工作流都从固定到目标 SHA 的临时分支运行: +`Full Release Validation` 是操作者从一个入口点启动所有预发布测试的方式。对于快速移动分支上的固定提交证明,使用该 helper,确保每个子工作流都从固定在目标 SHA 的临时分支运行: ```bash pnpm ci:full-release --sha ``` -该 helper 会推送 `release-ci/-...`,从该分支分发 `Full Release Validation` 并传入 `ref=`,验证每个子工作流的 `headSha` 都匹配目标,然后删除临时分支。这可以避免意外证明更新的 `main` 子运行。 +该 helper 会推送 `release-ci/-...`,从该分支分发 `Full Release Validation` 并传入 `ref=`,验证每个子工作流的 `headSha` 都匹配目标,然后删除临时分支。这可以避免意外证明较新的 `main` 子运行。 -对于 release 分支或标签验证,请从可信的 `main` workflow ref 运行,并将 release 分支或标签作为 `ref` 传入: +对于发布分支或标签验证,请从受信任的 `main` 工作流 ref 运行,并将发布分支或标签作为 `ref` 传入: ```bash gh workflow run full-release-validation.yml \ @@ -162,39 +152,20 @@ gh workflow run full-release-validation.yml \ -f evidence_package_spec=openclaw@YYYY.M.D-beta.N ``` -该工作流会解析目标 ref,调度手动 `CI` 并设置 -`target_ref=`,调度 `OpenClaw Release Checks`,为面向包的检查准备一个父级 `release-package-under-test` 工件,并在 `release_profile=full` 且 -`rerun_group=all` 时,或在设置了 `npm_telegram_package_spec` 时,调度独立的包 Telegram E2E。随后,`OpenClaw Release -Checks` 会展开安装冒烟、跨 OS 发布检查、启用 soak 时的 live/E2E Docker -发布路径覆盖、带有 Telegram -包 QA 的 Package Acceptance、QA Lab parity、live Matrix 和 live Telegram。只有当 -`Full Release Validation` -摘要显示 `normal_ci` 和 `release_checks` 均成功时,完整运行才可接受。在 full/all 模式下, -`npm_telegram` 子项也必须成功;在 full/all 之外,除非提供了已发布的 `npm_telegram_package_spec`,否则会跳过它。最终验证器摘要会为每个子运行包含最慢作业表,因此发布经理无需下载日志即可看到当前关键路径。 -请参阅[完整发布验证](/zh-CN/reference/full-release-validation),了解完整阶段矩阵、精确的工作流作业名称、stable 与 full profile 的差异、工件以及聚焦重跑句柄。 -子工作流会从运行 `Full Release -Validation` 的受信任 ref 调度,通常是 `--ref main`,即使目标 `ref` 指向较旧的发布分支或标签也是如此。没有单独的 Full Release Validation -workflow-ref 输入;通过选择工作流运行 ref 来选择受信任 harness。 -不要使用 `--ref main -f ref=` 为移动中的 `main` 提供精确提交证明; -原始提交 SHA 不能作为工作流调度 ref,因此请使用 -`pnpm ci:full-release --sha ` 创建固定的临时分支。 +该工作流解析目标 ref,使用 `target_ref=` 分发手动 `CI`,分发 `OpenClaw Release Checks`,为面向软件包的检查准备父级 `release-package-under-test` 工件,并在 `release_profile=full` 且 `rerun_group=all`,或设置了 `npm_telegram_package_spec` 时,分发独立的软件包 Telegram E2E。随后,`OpenClaw Release Checks` 会扩展到安装冒烟测试、跨 OS 发布检查、启用 soak 时的 live/E2E Docker 发布路径覆盖、带 Telegram 软件包 QA 的 Package Acceptance、QA Lab parity、live Matrix 和 live Telegram。只有当 `Full Release Validation` 摘要显示 `normal_ci` 和 `release_checks` 均成功时,完整运行才可接受。在 full/all 模式下,`npm_telegram` 子项也必须成功;在 full/all 之外,除非提供了已发布的 `npm_telegram_package_spec`,否则会跳过它。最终验证器摘要包含每个子运行的最慢作业表,因此发布经理无需下载日志即可看到当前关键路径。 +请参阅[完整发布验证](/zh-CN/reference/full-release-validation),了解完整阶段矩阵、精确工作流作业名称、stable 与 full profile 的差异、工件以及聚焦重跑句柄。 +子工作流从运行 `Full Release Validation` 的可信 ref 分发,通常为 `--ref main`,即使目标 `ref` 指向较旧的发布分支或标签也是如此。没有单独的 Full Release Validation workflow-ref 输入;通过选择工作流运行 ref 来选择可信 harness。 +不要在移动的 `main` 上使用 `--ref main -f ref=` 做精确提交证明;原始提交 SHA 不能作为 workflow dispatch ref,因此请使用 `pnpm ci:full-release --sha ` 创建固定的临时分支。 -使用 `release_profile` 选择 live/provider 覆盖广度: +使用 `release_profile` 选择 live/provider 覆盖范围: - `minimum`:最快的发布关键 OpenAI/core live 和 Docker 路径 -- `stable`:minimum 加上用于发布批准的稳定 provider/backend 覆盖 +- `stable`:minimum 加上用于发布批准的 stable provider/backend 覆盖 - `full`:stable 加上广泛的 advisory provider/media 覆盖 -当发布阻塞 lane 为绿色,并且你希望在推广前执行详尽的 live/E2E、Docker 发布路径以及 -all-since-2026.4.23 upgrade-survivor 扫描时,请将 `run_release_soak=true` 与 `stable` 一起使用。`full` 隐含 -`run_release_soak=true`。 +当发布阻断 lane 均为绿色,并且你希望在推广前执行详尽的 live/E2E、Docker 发布路径以及有界的已发布升级幸存者 sweep 时,请将 `stable` 与 `run_release_soak=true` 一起使用。该 sweep 覆盖最新四个 stable 软件包,加上固定的 `2026.4.23` 和 `2026.5.2` 基线以及较旧的 `2026.4.15` 覆盖,会移除重复基线,并将每个基线分片到自己的 Docker runner 作业中。`full` 隐含 `run_release_soak=true`。 -`OpenClaw Release Checks` 使用受信任 workflow ref 将目标 -ref 一次性解析为 `release-package-under-test`,并在 soak 运行时在 cross-OS、 -Package Acceptance 和 release-path Docker 检查中复用该工件。这样能让所有面向包的 box 使用相同字节,并避免重复构建包。 -当 repo/org 变量已设置时,cross-OS OpenAI 安装冒烟会使用 `OPENCLAW_CROSS_OS_OPENAI_MODEL`,否则使用 -`openai/gpt-5.4`,因为此 lane 要证明的是包安装、新手引导、Gateway 网关启动以及一次 live agent 回合,而不是对最慢的默认模型进行基准测试。更广泛的 live provider -矩阵仍然是执行模型特定覆盖的位置。 +`OpenClaw Release Checks` 使用可信工作流 ref 将目标 ref 解析一次为 `release-package-under-test`,并在运行 soak 时,在 cross-OS、Package Acceptance 和 release-path Docker 检查中复用该工件。这会让所有面向软件包的机器使用相同字节,并避免重复构建软件包。cross-OS OpenAI 安装冒烟测试在 repo/org 变量已设置时使用 `OPENCLAW_CROSS_OS_OPENAI_MODEL`,否则使用 `openai/gpt-5.4`,因为该 lane 证明的是软件包安装、新手引导、Gateway 网关启动以及一次 live agent 轮次,而不是对最慢默认模型做基准测试。更广泛的 live provider 矩阵仍然是模型特定覆盖的位置。 根据发布阶段使用这些变体: @@ -226,30 +197,22 @@ gh workflow run full-release-validation.yml \ -f npm_telegram_provider_mode=mock-openai ``` -不要把完整 umbrella 用作聚焦修复后的第一次重跑。如果某个 box 失败,请使用失败的子工作流、作业、Docker lane、包 profile、模型提供商或 QA lane 作为下一次证明。只有当修复更改了共享发布编排,或让先前的 all-box 证据过期时,才再次运行完整 umbrella。umbrella 的最终验证器会重新检查已记录的子工作流运行 ID,因此在子工作流成功重跑后,只需重跑失败的 -`Verify full validation` 父作业。 +不要把完整总括工作流用作聚焦修复后的第一次重跑。如果一个 box 失败,请使用失败的子工作流、作业、Docker lane、软件包 profile、模型提供商或 QA lane 作为下一次证明。只有当修复更改了共享发布编排,或让先前的全 box 证据过期时,才再次运行完整总括工作流。总括工作流的最终验证器会重新检查已记录的子工作流运行 ID,因此在子工作流成功重跑后,只需重跑失败的 `Verify full validation` 父作业。 -对于有界恢复,请将 `rerun_group` 传给 umbrella。`all` 是真正的发布候选运行,`ci` 只运行 normal CI 子项,`plugin-prerelease` -只运行仅发布用插件子项,`release-checks` 运行每个发布 -box,更窄的发布组为 `install-smoke`、`cross-os`、 -`live-e2e`、`package`、`qa`、`qa-parity`、`qa-live` 和 `npm-telegram`。 -聚焦 `npm-telegram` 重跑需要 `npm_telegram_package_spec`;带有 `release_profile=full` 的 full/all 运行会使用 release-checks 包工件。聚焦 -cross-OS 重跑可以添加 `cross_os_suite_filter=windows/packaged-upgrade` 或另一个 OS/suite 过滤器。QA release-check 失败属于 advisory;仅 QA 失败不会阻塞发布验证。 +对于有界恢复,请将 `rerun_group` 传给总括工作流。`all` 是真正的候选发布运行,`ci` 只运行普通 CI 子项,`plugin-prerelease` 只运行仅发布使用的插件子项,`release-checks` 运行每个发布 box,更窄的发布组包括 `install-smoke`、`cross-os`、`live-e2e`、`package`、`qa`、`qa-parity`、`qa-live` 和 `npm-telegram`。聚焦 `npm-telegram` 重跑需要 `npm_telegram_package_spec`;带 `release_profile=full` 的 full/all 运行会使用 release-checks 软件包工件。聚焦 cross-OS 重跑可以添加 `cross_os_suite_filter=windows/packaged-upgrade` 或其他 OS/suite 过滤器。QA release-check 失败是 advisory;仅 QA 失败不会阻断发布验证。 ### Vitest -Vitest box 是手动 `CI` 子工作流。手动 CI 会有意绕过 changed scoping,并为发布候选强制执行 normal 测试图:Linux Node 分片、内置插件分片、channel contracts、Node 22 -兼容性、`check`、`check-additional`、构建冒烟、文档检查、Python -Skills、Windows、macOS、Android 和 Control UI i18n。 +Vitest box 是手动 `CI` 子工作流。手动 CI 会有意绕过 changed scoping,并强制候选发布使用普通测试图:Linux Node 分片、内置插件分片、渠道合约、Node 22 兼容性、`check`、`check-additional`、构建冒烟、文档检查、Python Skills、Windows、macOS、Android 和 Control UI i18n。 -使用此 box 回答“源代码树是否通过了完整 normal 测试套件?”它不同于 release-path 产品验证。需要保留的证据: +使用此 box 回答“源代码树是否通过完整的普通测试套件?”它不同于 release-path 产品验证。需要保留的证据: -- 显示已调度 `CI` 运行 URL 的 `Full Release Validation` 摘要 +- 显示已分发 `CI` 运行 URL 的 `Full Release Validation` 摘要 - 精确目标 SHA 上绿色的 `CI` 运行 -- 调查回归时来自 CI 作业的失败或慢速分片名称 -- 当运行需要性能分析时,保留 Vitest timing 工件,例如 `.artifacts/vitest-shard-timings.json` +- 调查回归时来自 CI 作业的失败或较慢分片名称 +- 当运行需要性能分析时,保留 `.artifacts/vitest-shard-timings.json` 等 Vitest timing 工件 -仅当发布需要确定性的 normal CI,而不需要 Docker、QA Lab、live、cross-OS 或 package box 时,才直接运行手动 CI: +仅当发布需要确定性的普通 CI,但不需要 Docker、QA Lab、live、cross-OS 或 package box 时,才直接运行手动 CI: ```bash gh workflow run ci.yml --ref main -f target_ref=release/YYYY.M.D @@ -257,84 +220,58 @@ gh workflow run ci.yml --ref main -f target_ref=release/YYYY.M.D ### Docker -Docker box 位于 `OpenClaw Release Checks` 中,通过 -`openclaw-live-and-e2e-checks-reusable.yml` 以及 release-mode -`install-smoke` 工作流实现。它通过打包的 Docker 环境验证发布候选,而不只是源代码级测试。 +Docker box 位于 `OpenClaw Release Checks` 中,通过 `openclaw-live-and-e2e-checks-reusable.yml` 以及 release-mode 的 `install-smoke` 工作流运行。它通过打包的 Docker 环境验证候选发布,而不只是源代码级测试。 发布 Docker 覆盖包括: -- 启用慢速 Bun 全局安装冒烟的完整安装冒烟 -- 按目标 SHA 准备/复用根 Dockerfile 冒烟镜像,并将 QR、 - root/gateway 和 installer/Bun 冒烟作业作为独立 install-smoke - 分片运行 -- 仓库 E2E lanes -- release-path Docker 分块:`core`、`package-update-openai`、 - `package-update-anthropic`、`package-update-core`、`plugins-runtime-plugins`、 - `plugins-runtime-services`、 - `plugins-runtime-install-a`、`plugins-runtime-install-b`、 - `plugins-runtime-install-c`、`plugins-runtime-install-d`、 - `plugins-runtime-install-e`、`plugins-runtime-install-f`、 - `plugins-runtime-install-g` 和 `plugins-runtime-install-h` -- 请求时,`plugins-runtime-services` 分块中的 OpenWebUI 覆盖 -- 拆分的内置插件安装/卸载 lanes: - `bundled-plugin-install-uninstall-0` 到 - `bundled-plugin-install-uninstall-23` -- 当 release checks 包含 live suites 时,覆盖 live/E2E provider suites 和 Docker live 模型 +- 启用慢速 Bun 全局安装冒烟测试的完整安装冒烟测试 +- 按目标 SHA 准备/复用根 Dockerfile 冒烟镜像,其中 QR、root/gateway 和 installer/Bun 冒烟作业作为独立的 install-smoke 分片运行 +- 仓库 E2E lane +- release-path Docker 分块:`core`、`package-update-openai`、`package-update-anthropic`、`package-update-core`、`plugins-runtime-plugins`、`plugins-runtime-services`、`plugins-runtime-install-a`、`plugins-runtime-install-b`、`plugins-runtime-install-c`、`plugins-runtime-install-d`、`plugins-runtime-install-e`、`plugins-runtime-install-f`、`plugins-runtime-install-g` 和 `plugins-runtime-install-h` +- 请求时,`plugins-runtime-services` 分块内的 OpenWebUI 覆盖 +- 拆分的内置插件安装/卸载 lane,从 `bundled-plugin-install-uninstall-0` 到 `bundled-plugin-install-uninstall-23` +- 当 release checks 包含 live suite 时,包含 live/E2E provider suite 和 Docker live model 覆盖 -重跑前先使用 Docker 工件。release-path 调度器会上传 -`.artifacts/docker-tests/`,其中包含 lane 日志、`summary.json`、`failures.json`、 -阶段耗时、调度器计划 JSON 和重跑命令。对于聚焦恢复,请在可复用 live/E2E 工作流上使用 `docker_lanes=`,而不是重跑所有发布分块。生成的重跑命令会在可用时包含之前的 -`package_artifact_run_id` 和已准备的 Docker 镜像输入,因此失败 lane 可以复用相同的 tarball 和 GHCR 镜像。 +重跑前请先使用 Docker 工件。release-path 调度器会上传 `.artifacts/docker-tests/`,其中包含 lane 日志、`summary.json`、`failures.json`、阶段计时、scheduler plan JSON 和重跑命令。对于聚焦恢复,请在可复用 live/E2E 工作流上使用 `docker_lanes=`,而不是重跑所有发布分块。生成的重跑命令会在可用时包含先前的 `package_artifact_run_id` 和已准备的 Docker 镜像输入,因此失败的 lane 可以复用相同 tarball 和 GHCR 镜像。 ### QA Lab -QA Lab box 也是 `OpenClaw Release Checks` 的一部分。它是 agentic -行为和 channel 级发布门禁,与 Vitest 和 Docker -包机制分开。 +QA Lab box 也是 `OpenClaw Release Checks` 的一部分。它是智能体行为和渠道级发布门禁,与 Vitest 和 Docker 软件包机制分开。 发布 QA Lab 覆盖包括: -- 使用 agentic parity pack 将 OpenAI 候选 lane 与 Opus 4.6 - 基线进行比较的 mock parity lane +- mock parity lane,使用 agentic parity pack 将 OpenAI 候选 lane 与 Opus 4.6 基线比较 - 使用 `qa-live-shared` 环境的快速 live Matrix QA profile -- 使用 Convex CI 凭据租约的 live Telegram QA lane -- 当发布遥测需要明确本地证明时运行 `pnpm qa:otel:smoke` +- 使用 Convex CI 凭证租约的 live Telegram QA lane +- 当发布遥测需要显式本地证明时运行 `pnpm qa:otel:smoke` -使用此 box 回答“发布在 QA 场景和 live channel flows 中行为是否正确?”批准发布时,请保留 parity、Matrix 和 Telegram -lane 的工件 URL。完整 Matrix 覆盖仍可作为手动分片 QA-Lab 运行,而不是默认的发布关键 lane。 +使用此 box 回答“发布在 QA 场景和 live channel 流程中是否表现正确?”批准发布时,请保留 parity、Matrix 和 Telegram lane 的工件 URL。完整 Matrix 覆盖仍可作为手动分片 QA-Lab 运行使用,而不是默认发布关键 lane。 -### 包 +### 软件包 -Package box 是可安装产品门禁。它由 -`Package Acceptance` 和解析器 -`scripts/resolve-openclaw-package-candidate.mjs` 支撑。该解析器会将候选规范化为 Docker E2E 使用的 `package-under-test` tarball,验证包清单,记录包版本和 SHA-256,并让工作流 harness ref 与包源 ref 保持分离。 +Package box 是可安装产品门禁。它由 `Package Acceptance` 和解析器 `scripts/resolve-openclaw-package-candidate.mjs` 支撑。解析器会将候选项规范化为供 Docker E2E 使用的 `package-under-test` tarball,验证软件包清单,记录软件包版本和 SHA-256,并将工作流 harness ref 与软件包源 ref 分开。 支持的候选来源: - `source=npm`:`openclaw@beta`、`openclaw@latest`,或精确的 OpenClaw 发布版本 -- `source=ref`:使用所选 `workflow_ref` harness 打包受信任的 `package_ref` 分支、标签或完整提交 SHA -- `source=url`:下载需要 `package_sha256` 的 HTTPS `.tgz` -- `source=artifact`:复用由另一个 GitHub Actions 运行上传的 `.tgz` +- `source=ref`:使用选定的 `workflow_ref` harness 打包可信的 `package_ref` 分支、标签或完整提交 SHA +- `source=url`:下载一个需要 `package_sha256` 的 HTTPS `.tgz` +- `source=artifact`:复用另一个 GitHub Actions 运行上传的 `.tgz` -`OpenClaw Release Checks` 运行 Package Acceptance,并使用 `source=artifact`、已准备的发布包工件、`suite_profile=custom`、 -`docker_lanes=doctor-switch update-channel-switch upgrade-survivor published-upgrade-survivor plugins-offline plugin-update`、 -`telegram_mode=mock-openai`。Package Acceptance 会让迁移、更新、过时插件依赖清理、离线插件 fixtures、插件更新和 Telegram -包 QA 都针对同一个已解析 tarball 运行。阻塞发布检查使用默认的最新已发布包基线;`run_release_soak=true` 或 -`release_profile=full` 会扩展到从 -`2026.4.23` 到 `latest` 的每个稳定 npm 已发布基线,以及已报告问题的 fixtures。对已经发布的候选使用 -Package Acceptance 且 `source=npm`;对发布前由 SHA 支撑的本地 npm tarball 使用 `source=ref`/`source=artifact`。它是大多数此前需要 -Parallels 的 package/update 覆盖的 GitHub 原生替代方案。Cross-OS release checks 对 OS 特定新手引导、安装器和平台行为仍然重要,但 package/update 产品验证应优先使用 Package Acceptance。 +`OpenClaw Release Checks` 使用 `source=artifact`、已准备的发布软件包工件、`suite_profile=custom`、`docker_lanes=doctor-switch update-channel-switch upgrade-survivor published-upgrade-survivor plugins-offline plugin-update`、`telegram_mode=mock-openai` 运行 Package Acceptance。Package Acceptance 会让迁移、更新、过期插件依赖清理、离线插件 fixture、插件更新和 Telegram 软件包 QA 都针对同一个已解析 tarball。阻断性 release checks 使用默认的最新已发布软件包基线;`run_release_soak=true` 或 `release_profile=full` 会扩展到从 `2026.4.23` 到 `latest` 的每个 stable npm 已发布基线,以及已报告问题的 fixture。对于已经发布的候选项,请使用带 `source=npm` 的 Package Acceptance;对于发布前有 SHA 支撑的本地 npm tarball,请使用 `source=ref`/`source=artifact`。它是 GitHub 原生替代方案,可替代过去大多数需要 Parallels 的 package/update 覆盖。cross-OS release checks 对 OS 特定的新手引导、安装器和平台行为仍然重要,但 package/update 产品验证应优先使用 Package Acceptance。 -更新和插件验证的规范清单是 -[更新和插件测试](/zh-CN/help/testing-updates-plugins)。在决定哪个本地、Docker、Package Acceptance 或 release-check lane 能证明插件安装/更新、Doctor 清理或已发布包迁移变更时,请使用它。 -从每个稳定 `2026.4.23+` 包执行详尽的已发布更新迁移是一个单独的手动 `Update Migration` 工作流,不属于 Full Release CI。 +更新和插件验证的规范清单是[更新和插件测试](/zh-CN/help/testing-updates-plugins)。在决定哪个本地、Docker、Package Acceptance 或 release-check lane 可以证明插件安装/更新、Doctor 清理或已发布软件包迁移更改时,请使用它。从每个 stable `2026.4.23+` 软件包执行详尽的已发布更新迁移,是单独的手动 `Update Migration` 工作流,不属于 Full Release CI。 -旧版 package-acceptance 宽松策略有意设置了时间限制。截至 -`2026.4.25` 的包可以对已发布到 npm 的元数据缺口使用兼容路径:tarball 中缺失的私有 QA 清单条目、缺失的 -`gateway install --wrapper`、tarball 派生 git fixture 中缺失的补丁文件、缺失的持久化 `update.channel`、旧版插件 install-record -位置、缺失的 marketplace install-record 持久化,以及 `plugins update` 期间的配置元数据迁移。已发布的 `2026.4.26` 包可能会对已经发出的本地构建元数据戳文件发出警告。后续包必须满足现代包契约;这些相同缺口会导致发布验证失败。 +旧版包验收宽松规则被有意限定在一段时间内。直到 +`2026.4.25` 的包可以对已发布到 npm 的元数据缺口使用兼容路径:tarball 中缺失的私有 QA 库存条目、缺失的 +`gateway install --wrapper`、从 tarball 派生的 git +fixture 中缺失的补丁文件、缺失的持久化 `update.channel`、旧版插件安装记录 +位置、缺失的 marketplace 安装记录持久化,以及 `plugins update` 期间的配置元数据 +迁移。已发布的 `2026.4.26` 包可能会针对已经发布的本地构建元数据标记文件发出 +警告。后续包必须满足现代包契约;这些相同缺口会导致发布 +验证失败。 -当发布问题涉及实际可安装包时,请使用更广泛的 Package Acceptance profile: +当发布问题涉及实际可安装包时,请使用更广的 Package Acceptance 配置档: ```bash gh workflow run package-acceptance.yml \ @@ -346,33 +283,33 @@ gh workflow run package-acceptance.yml \ -f published_upgrade_survivor_baseline=openclaw@2026.4.26 ``` -常见包配置档案: +常用包配置档: -- `smoke`:快速包安装/渠道/智能体、Gateway 网关网络和配置 +- `smoke`:快速包安装/渠道/智能体、Gateway 网关网络,以及配置 重载通道 -- `package`:不依赖实时 ClawHub 的安装/更新/插件包契约;这是发布检查的 +- `package`:安装/更新/插件包契约,不包含 live ClawHub;这是发布检查的 默认值 -- `product`:`package` 加上 MCP 渠道、cron/子智能体清理、OpenAI Web - 搜索和 OpenWebUI -- `full`:带 OpenWebUI 的 Docker 发布路径分块 +- `product`:`package` 加上 MCP 渠道、cron/subagent 清理、OpenAI web + search,以及 OpenWebUI +- `full`:包含 OpenWebUI 的 Docker 发布路径分块 - `custom`:用于聚焦重跑的精确 `docker_lanes` 列表 -如需包候选版本的 Telegram 证明,请在 Package Acceptance 上启用 `telegram_mode=mock-openai` 或 -`telegram_mode=live-frontier`。该 workflow 会把解析出的 +对于包候选版本的 Telegram 证明,请在 Package Acceptance 上启用 `telegram_mode=mock-openai` 或 +`telegram_mode=live-frontier`。该工作流会将解析后的 `package-under-test` tarball 传入 Telegram 通道;独立的 -Telegram workflow 仍接受已发布的 npm 规格,用于发布后检查。 +Telegram 工作流仍然接受已发布的 npm spec,用于发布后检查。 ## 发布发布自动化 -`OpenClaw Release Publish` 是常规的变更型发布入口点。它会按发布所需顺序 -编排受信发布者 workflow: +`OpenClaw Release Publish` 是常规的可变更发布入口点。它会按发布所需的顺序 +编排 trusted-publisher 工作流: 1. 检出发布标签并解析其提交 SHA。 2. 验证该标签可从 `main` 或 `release/*` 到达。 3. 运行 `pnpm plugins:sync:check`。 4. 使用 `publish_scope=all-publishable` 和 `ref=` 调度 `Plugin NPM Release`。 -5. 使用相同 scope 和 SHA 调度 `Plugin ClawHub Release`。 +5. 使用相同的 scope 和 SHA 调度 `Plugin ClawHub Release`。 6. 使用发布标签、npm dist-tag 和 已保存的 `preflight_run_id` 调度 `OpenClaw NPM Release`。 @@ -406,89 +343,89 @@ gh workflow run openclaw-release-publish.yml \ -f npm_dist_tag=latest ``` -仅在聚焦修复或重新发布工作中使用更底层的 `Plugin NPM Release` 和 `Plugin ClawHub Release` workflow。对于选定插件修复,将 +仅在聚焦修复或重新发布工作中使用较底层的 `Plugin NPM Release` 和 `Plugin ClawHub Release` 工作流。对于选定插件修复,请将 `plugin_publish_scope=selected` 和 `plugins=@openclaw/name` 传给 -`OpenClaw Release Publish`;如果不得发布 OpenClaw 包,则直接调度子 workflow。 +`OpenClaw Release Publish`,或者当不得发布 OpenClaw 包时直接调度子工作流。 -## NPM workflow 输入 +## NPM 工作流输入 -`OpenClaw NPM Release` 接受以下由操作员控制的输入: +`OpenClaw NPM Release` 接受这些由操作员控制的输入: -- `tag`:必填发布标签,例如 `v2026.4.2`、`v2026.4.2-1` 或 - `v2026.4.2-beta.1`;当 `preflight_only=true` 时,它也可以是当前 - 完整 40 字符 workflow 分支提交 SHA,用于仅验证的预检 +- `tag`:必需的发布标签,例如 `v2026.4.2`、`v2026.4.2-1` 或 + `v2026.4.2-beta.1`;当 `preflight_only=true` 时,也可以是当前 + 完整 40 字符工作流分支提交 SHA,用于仅验证预检 - `preflight_only`:`true` 表示仅验证/构建/打包,`false` 表示 真实发布路径 -- `preflight_run_id`:真实发布路径必填,用于让 workflow 复用 +- `preflight_run_id`:真实发布路径必需,这样工作流会复用 成功预检运行中准备好的 tarball - `npm_dist_tag`:发布路径的 npm 目标标签;默认为 `beta` -`OpenClaw Release Publish` 接受以下由操作员控制的输入: +`OpenClaw Release Publish` 接受这些由操作员控制的输入: -- `tag`:必填发布标签;必须已经存在 -- `preflight_run_id`:成功的 `OpenClaw NPM Release` 预检运行 ID; - 当 `publish_openclaw_npm=true` 时必填 +- `tag`:必需的发布标签;必须已经存在 +- `preflight_run_id`:成功的 `OpenClaw NPM Release` 预检运行 id; + 当 `publish_openclaw_npm=true` 时必需 - `npm_dist_tag`:OpenClaw 包的 npm 目标标签 -- `plugin_publish_scope`:默认为 `all-publishable`;仅在聚焦修复工作中 - 使用 `selected` -- `plugins`:当 `plugin_publish_scope=selected` 时使用的逗号分隔 - `@openclaw/*` 包名 -- `publish_openclaw_npm`:默认为 `true`;仅当把该 workflow 用作 - 仅插件修复编排器时设置为 `false` +- `plugin_publish_scope`:默认为 `all-publishable`;仅在 + 聚焦修复工作中使用 `selected` +- `plugins`:当 `plugin_publish_scope=selected` 时,以逗号分隔的 `@openclaw/*` 包名 +- `publish_openclaw_npm`:默认为 `true`;仅在将该 + 工作流用作仅插件修复编排器时设为 `false` -`OpenClaw Release Checks` 接受以下由操作员控制的输入: +`OpenClaw Release Checks` 接受这些由操作员控制的输入: -- `ref`:要验证的分支、标签或完整提交 SHA。带有密钥的检查要求 - 解析出的提交可从 OpenClaw 分支或发布标签到达。 -- `run_release_soak`:在稳定版/默认发布检查中选择加入穷尽式实时/E2E、Docker 发布路径和 - 所有历史版本升级幸存 soak。它会被 `release_profile=full` 强制启用。 +- `ref`:要验证的分支、标签或完整提交 SHA。携带 secret 的检查 + 要求解析出的提交可从 OpenClaw 分支或 + 发布标签到达。 +- `run_release_soak`:在稳定版/默认发布检查中选择启用详尽的 live/E2E、Docker 发布路径,以及 + all-since upgrade-survivor soak。`release_profile=full` 会强制启用它。 规则: -- 稳定版和修正版标签可发布到 `beta` 或 `latest` +- 稳定版和修正版标签可以发布到 `beta` 或 `latest` - Beta 预发布标签只能发布到 `beta` -- 对于 `OpenClaw NPM Release`,仅当 `preflight_only=true` 时 - 才允许完整提交 SHA 输入 +- 对于 `OpenClaw NPM Release`,仅当 + `preflight_only=true` 时才允许输入完整提交 SHA - `OpenClaw Release Checks` 和 `Full Release Validation` 始终 - 仅用于验证 -- 真实发布路径必须使用预检期间使用的相同 `npm_dist_tag`; - workflow 会在发布继续前验证该元数据 + 仅执行验证 +- 真实发布路径必须使用与预检期间相同的 `npm_dist_tag`; + 工作流会在发布继续前验证该元数据 ## 稳定版 npm 发布顺序 -切稳定版 npm 发布时: +当发布稳定版 npm 版本时: 1. 使用 `preflight_only=true` 运行 `OpenClaw NPM Release` - - 在标签存在之前,你可以使用当前完整 workflow 分支提交 - SHA 对预检 workflow 做一次仅验证试运行 -2. 对常规先 beta 流程选择 `npm_dist_tag=beta`,或仅在你有意直接发布稳定版时 - 选择 `latest` -3. 当你希望用一个手动 workflow 获取常规 CI 加实时提示缓存、Docker、QA Lab、 - Matrix 和 Telegram 覆盖时,在发布分支、发布标签或完整 + - 在标签存在前,你可以使用当前完整的工作流分支提交 + SHA,对预检工作流执行仅验证 dry run +2. 对于常规 beta-first 流程,选择 `npm_dist_tag=beta`;仅在 + 你有意直接发布稳定版时才选择 `latest` +3. 当你希望通过一个手动工作流获得常规 CI 加上 live prompt cache、Docker、QA Lab、 + Matrix 和 Telegram 覆盖时,请在发布分支、发布标签或完整 提交 SHA 上运行 `Full Release Validation` -4. 如果你确实只需要确定性的常规测试图,请改为在发布 ref 上运行 - 手动 `CI` workflow +4. 如果你有意只需要确定性的常规测试图,请改为在发布 ref 上运行 + 手动 `CI` 工作流 5. 保存成功的 `preflight_run_id` 6. 使用相同的 `tag`、相同的 `npm_dist_tag` - 和已保存的 `preflight_run_id` 运行 `OpenClaw Release Publish`;它会先把外置插件发布到 npm + 和保存的 `preflight_run_id` 运行 `OpenClaw Release Publish`;它会先将外部化插件发布到 npm 和 ClawHub,然后再提升 OpenClaw npm 包 -7. 如果发布落在 `beta`,请使用私有 +7. 如果发布落在 `beta`,请使用私有的 `openclaw/releases-private/.github/workflows/openclaw-npm-dist-tags.yml` - workflow 将该稳定版本从 `beta` 提升到 `latest` -8. 如果发布有意直接发布到 `latest`,且 `beta` - 应立即跟随同一稳定构建,请使用同一私有 - workflow 将两个 dist-tag 都指向该稳定版本,或让其定时 + 工作流,将该稳定版本从 `beta` 提升到 `latest` +8. 如果该发布有意直接发布到 `latest`,且 `beta` + 应立即跟随同一个稳定构建,请使用同一个私有 + 工作流让两个 dist-tag 都指向该稳定版本,或让其定时 自愈同步稍后移动 `beta` dist-tag 变更位于私有仓库中是出于安全考虑,因为它仍然 需要 `NPM_TOKEN`,而公共仓库保持仅 OIDC 发布。 -这让直接发布路径和先 beta 后提升路径都保持 -有文档记录且对操作员可见。 +这样可以让直接发布路径和 beta-first 提升路径都 +有文档记录,并且对操作员可见。 -如果维护者必须回退到本地 npm 身份验证,请仅在专用 tmux 会话中运行任何 1Password -CLI (`op`) 命令。不要直接从主智能体 shell 调用 `op`;把它放在 tmux 内可以让提示、 -告警和 OTP 处理可观察,并防止重复的主机告警。 +如果维护者必须回退到本地 npm 身份验证,请只在专用 tmux 会话中运行任何 1Password +CLI (`op`) 命令。不要直接从主智能体 shell 调用 `op`;将其保持在 tmux 内可以让提示、 +警报和 OTP 处理可观察,并防止重复的主机警报。 ## 公共参考 diff --git a/docs/zh-CN/reference/test.md b/docs/zh-CN/reference/test.md index 4fe51b7b0..469ee3200 100644 --- a/docs/zh-CN/reference/test.md +++ b/docs/zh-CN/reference/test.md @@ -1,59 +1,59 @@ --- read_when: - 运行或修复测试 -summary: 如何在本地运行测试(vitest),以及何时使用强制/覆盖率模式 +summary: 如何在本地运行测试(vitest),以及何时使用 force/coverage 模式 title: 测试 x-i18n: - generated_at: "2026-05-04T20:59:42Z" + generated_at: "2026-05-05T04:26:40Z" model: gpt-5.5 provider: openai - source_hash: 7e8421518d63cade24ce8c2a08fa10538b66d2332b1eb5744e47c6d5a5e84605 + source_hash: cc31ab27a63607ec5134306a0129bd164e4235f26631da4f691f657adda70eed source_path: reference/test.md workflow: 16 --- -- 完整测试工具包(套件、实时测试、Docker):[测试](/zh-CN/help/testing) +- 完整测试工具包(测试套件、实时测试、Docker):[测试](/zh-CN/help/testing) - 更新和插件包验证:[更新和插件测试](/zh-CN/help/testing-updates-plugins) -- `pnpm test:force`:终止任何仍占用默认控制端口的残留 Gateway 网关进程,然后使用隔离的 Gateway 网关端口运行完整 Vitest 套件,避免服务器测试与正在运行的实例冲突。当前一次 Gateway 网关运行留下端口 18789 被占用时使用。 -- `pnpm test:coverage`:使用 V8 覆盖率运行单元套件(通过 `vitest.unit.config.ts`)。这是已加载文件的单元覆盖率门禁,不是整个仓库的全文件覆盖率。阈值为行/函数/语句 70%,分支 55%。因为 `coverage.all` 为 false,该门禁衡量单元覆盖率套件加载的文件,而不是把每个分片通道源文件都视为未覆盖。 -- `pnpm test:coverage:changed`:仅对自 `origin/main` 以来变更的文件运行单元覆盖率。 -- `pnpm test:changed`:低成本的智能变更测试运行。它会根据直接测试编辑、同级 `*.test.ts` 文件、显式源映射和本地导入图运行精确目标。广泛/config/package 变更会被跳过,除非它们映射到精确测试。 -- `OPENCLAW_TEST_CHANGED_BROAD=1 pnpm test:changed`:显式的广泛变更测试运行。当测试 harness/config/package 编辑应回退到 Vitest 更广泛的变更测试行为时使用。 -- `pnpm changed:lanes`:显示相对于 `origin/main` 的 diff 触发的架构通道。 -- `pnpm check:changed`:对相对于 `origin/main` 的 diff 运行智能变更检查门禁。它会为受影响的架构通道运行类型检查、lint 和守卫命令,但不会运行 Vitest 测试。使用 `pnpm test:changed` 或显式 `pnpm test ` 提供测试证明。 -- `pnpm test`:将显式文件/目录目标路由到有作用域的 Vitest 通道。无目标运行会使用固定分片组,并展开为叶级配置以进行本地并行执行;扩展组始终展开为每个扩展的分片配置,而不是一个巨大的根项目进程。 -- 测试 wrapper 运行会以简短的 `[test] passed|failed|skipped ... in ...` 摘要结束。Vitest 自己的时长行保留为每个分片的详细信息。 -- 共享 OpenClaw 测试状态:当测试需要隔离的 `HOME`、`OPENCLAW_STATE_DIR`、`OPENCLAW_CONFIG_PATH`、配置 fixture、工作区、智能体目录或 auth-profile 存储时,在 Vitest 中使用 `src/test-utils/openclaw-test-state.ts`。 -- 进程 E2E 辅助工具:当 Vitest 进程级 E2E 测试需要在一个位置管理正在运行的 Gateway 网关、CLI 环境、日志捕获和清理时,使用 `test/helpers/openclaw-test-instance.ts`。 -- Docker/Bash E2E 辅助工具:source `scripts/lib/docker-e2e-image.sh` 的通道可以将 `docker_e2e_test_state_shell_b64