扩展 QA 技术栈
基于仓库的种子数据¶
种子资产位于 qa/ 中:
qa/scenarios/index.yamlqa/scenarios/<theme>/*.yaml
涉及身份敏感的频道变更使用隔离的 channel-participant-identity-inspection QA Channel 流程。它驱动一个真实的临时 Gateway 和 mock provider,然后使用操作员所用的同一套 openclaw audit --run ... --explain JSON 及人工界面来检查被准入的运行。该流程包括由生命周期管理的重启,以及对被拒绝的 pre-run 入口进行行数检查。
这些内容有意放在 git 中,以便 QA 计划对人和 agent 都可见。
qa-lab 仍然是一个通用的 YAML 场景运行器。每个场景 YAML 文件是单次测试运行的唯一事实来源,应定义:
- 顶层
title scenario元数据scenario中可选的 category、capability、lane 和 risk 元数据scenario中的文档和代码引用scenario中可选的插件要求scenario中可选的 gateway 配置补丁- 对于 flow 场景,提供可执行的顶层
flow;对于 Vitest 和 Playwright 场景,提供scenario.execution.kind/scenario.execution.path
支撑 flow 的可复用运行时层面保持通用且具有横切性。例如,YAML 场景可以将传输侧助手与浏览器侧助手结合,通过 Gateway 的 browser.request 接缝驱动内嵌的 Control UI,而无需添加特例 runner。
场景文件应按产品能力分组,而不是按源代码树目录分组。文件移动时应保持场景 ID 稳定;使用 docsRefs 和 codeRefs 实现实现可追溯性。
基线列表应保持足够广泛,以覆盖:
- DM 和频道聊天
- 线程行为
- 消息操作生命周期
- cron 回调
- 记忆召回
- 模型切换
- subagent 交接
- 仓库读取和文档读取
- 一个小型构建任务,例如 Lobster Invaders
Provider 模拟通道¶
qa suite 有两条本地 provider 模拟通道:
mock-openai是感知场景的 OpenClaw mock。它仍然是基于仓库的 QA 和一致性门禁的默认确定性 mock 通道。aimock启动一个由 AIMock 支撑的 provider 服务器,用于实验性协议、fixture、录制/回放和混沌覆盖。它是增量式的,不会取代mock-openai场景调度器。
感知场景的 mock 会单独响应 Activity recap 请求,而不与 agent 回合混在一起。Recap 将对话文本作为数据引用,因此它们不会触发场景工具,也不会进入由 /debug/requests 返回的场景请求证据。
对于 IPv6 回环服务器,运行 pnpm openclaw qa mock-openai --host ::1。打印出的 URL 包含方括号,例如 http://[::1]:<port>;配置客户端时请使用该 URL。QA Lab 也会在其监听和对外公布的 URL 中用方括号括起 IPv6 主机。请将裸地址传给 --host。
Provider 通道的实现位于 extensions/qa-lab/src/providers/ 下。每个 provider 自行管理其默认值、本地服务器启动、gateway 模型配置、auth-profile 暂存需求,以及 live/mock 能力标志。共享的 suite 和 gateway 代码通过 provider 注册表进行路由,而不是按 provider 名称分支。
传输适配器¶
qa-lab 为 YAML QA 场景提供一个通用的传输接缝。qa-channel 是默认的合成实现。crabline 会启动独立的本地 provider 服务器,并让 OpenClaw 的正常 channel 插件面向这些 provider 形态的 REST 和流式边界运行;它不使用 Crabline 的 fixture 级本地 mock provider。live 保留给真实的 provider 凭据和外部渠道。
在架构层面,职责划分如下:
qa-lab负责通用场景执行、worker 并发、artifact 写入和报告生成。- 传输适配器负责 gateway 配置、就绪性、入站和出站观察、传输操作,以及规范化传输状态。
qa/scenarios/下的 YAML 场景文件定义测试运行;qa-lab提供执行这些文件的可复用运行时层面。
适配器关闭与失败钩子¶
可选的 QA runner 钩子遵循由宿主控制的单一 teardown 顺序:
cleanup()停止新的 fixture 操作,同时保留凭据权威性以及对未完成写入的所有权。最终回执所需的观察者可以保持活动直到 Gateway 关闭。已绑定的传输请求本身不受影响;场景截止时间不会了结已经派发的请求。- 宿主停止 Gateway 并确认进程已关闭。
captureBeforeGatewayCleanup()在临时 Gateway 状态被移除之前,对最终的原生回执进行快照。成功的捕获在每次 Gateway 生命周期内运行一次。抛出的错误会保留运行时证据并使 teardown 失败;但不会阻止停止后的 fixture 清理。cleanupAfterGatewayStop()了结未完成的写入和所拥有的 fixture 清理,然后释放凭据租约。如果 Gateway 关闭未得到确认,宿主将不调用此钩子。应报告失败,而不是声称清理成功。
省略的钩子不执行任何适配器特定工作;正常的宿主 teardown 仍会运行。错误会在各个清理阶段中累积。对于未知的远程写入结果,应保持明确,而不是推断所有权或重放写入。
可选的 whenUnhealthy promise 会resolve(而不是 reject)一个终止错误。宿主会中止正在进行的 flow 准入;适配器在清理期间仍负责了结。省略该钩子的适配器保留其显式健康检查和场景截止时间。
添加频道¶
向 YAML QA 系统添加一个频道,需要该频道的实现,以及一个覆盖频道契约的场景包。为了 smoke CI 覆盖,请添加匹配的 Crabline 本地 provider 服务器,并通过 crabline 驱动暴露它。
当共享的 qa-lab 宿主能够负责该流程时,不要添加新的顶层 QA 命令根。
qa-lab 负责共享宿主机制:
openclaw qa命令根- suite 启动与 teardown
- worker 并发
- artifact 写入
- 报告生成
- 场景执行
- 旧版
qa-channel场景的兼容别名
Runner 插件负责传输契约:
- 如何在共享的
qa根下挂载openclaw qa <runner> - 如何为该传输配置 Gateway
- 如何检查就绪状态
- 如何注入入站事件
- 如何观察出站消息
- 如何暴露转录和规范化传输状态
- 如何执行由传输支撑的操作
- Gateway 运行时需要哪些受信任模块预加载
- 如何处理特定传输的重置或清理
新渠道的最低采用门槛:
- 保持
qa-lab作为共享qa根的拥有者。 - 在共享的
qa-lab宿主接缝上实现传输 Runner。 - 将特定传输的机制保留在 Runner 插件或渠道测试框架中。
- 将 Runner 挂载为
openclaw qa <runner>,而不是注册一个竞争性的根命令。Runner 插件应在openclaw.plugin.json中声明qaRunners,并从轻量级的qa-runner-api.ts接口导出匹配的qaRunnerCliRegistrations数组。使用随附runtime-api.ts契约的已安装插件在作者迁移期间将继续获得支持,直至 2026-10-01。将 Runner 执行保留在惰性入口点之后。可选的adapterFactory可将传输暴露给共享场景,而不改变命令现有的场景目录。同一渠道的分区是串行的,除非工厂声明每个实例都拥有隔离的凭据或一次性服务器、Gateway 状态以及产物路径。由模块支撑的流程场景还要求adapterFactory.supportsModuleFlows: true;这些工厂必须返回实现prepareFlow的适配器。 - 在按主题划分的
qa/scenarios/目录下创建或适配 YAML 场景。 - 对新场景使用通用场景辅助函数。
- 除非仓库正在进行有意迁移,否则保持现有兼容性别名可用。
决策规则严格如下:
- 如果行为可以在
qa-lab中一次性表达,就将其放入qa-lab。 - 如果行为依赖于某个渠道传输,就将其保留在该 Runner 插件或插件测试框架中。
- 如果某个场景需要一个多个渠道都可使用的新能力,请添加通用辅助函数,而不是在
suite.ts中添加渠道特定分支。 - 如果某个行为仅对一个传输有意义,请保持场景为传输特定,并在场景契约中明确说明。
场景辅助函数名称¶
新场景推荐的通用辅助函数:
waitForTransportReadywaitForChannelReadyinjectInboundMessageinjectOutboundMessagewaitForOutboundMessagewaitForNoTransportOutboundgetTransportSnapshotreadTransportMessagereadTransportTranscriptformatTransportTranscriptresetTransport
兼容性别名对现有场景仍然可用 - waitForQaChannelReady、waitForNoOutbound、formatConversationTranscript 和 resetBus - 但新场景编写应使用通用名称。对于出站检查,请使用规范的 waitForOutboundMessage,而不是添加传输特定或渠道特定的出站等待别名。
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 cl/openclaw