Testing
QA-specific runners
QA-specific runners
These commands sit beside the main test suites when you need QA-lab realism.
CI runs QA Lab in dedicated workflows. Agentic parity is nested under
QA-Lab - All Lanes and release validation, not a standalone PR workflow.
Broad validation should use Full Release Validation with
rerun_group=qa-parity for parity or rerun_group=qa-live for live QA.
The direct OpenClaw Release Checks child alone may use rerun_group=qa as a
manual aggregate of both groups. Stable/full, soak-enabled, and explicit
qa-live release checks include the QA-live Matrix and Telegram lanes. Bounded
beta-publish all without soak runs parity but defers those live lanes to
postpublish-confidence. QA-Lab - All Lanes runs
nightly on main and from manual dispatch with the mock parity lane, live
Matrix lane, Convex-managed live Telegram lane, and Convex-managed live Discord
lane as parallel jobs. Scheduled QA and selected release checks run the
catalog-derived Matrix selection through the shared live adapter. Release
transport checks use mock-openai/gpt-5.6-luna so they stay deterministic and
avoid normal provider-plugin startup. These live transport gateways disable
memory search; memory behavior stays covered by the QA parity suites.
Full release live media shards use
ghcr.io/openclaw/openclaw-live-media-runner:ubuntu-24.04, which already has
ffmpeg and ffprobe. Docker live model/backend shards use the shared
ghcr.io/openclaw/openclaw-live-test:<sha> image built once per selected
commit, then pull it with OPENCLAW_SKIP_DOCKER_BUILD=1 instead of rebuilding
inside every shard.
pnpm openclaw qa suite- Runs repo-backed QA scenarios directly on the host.
- Writes top-level
qa-evidence.json,qa-suite-summary.json, andqa-suite-report.mdartifacts for the selected scenario set, including mixed flow, Vitest, and Playwright scenario selections. - When dispatched by
pnpm openclaw qa run --qa-profile <profile>, embeds the selected taxonomy profile scorecard in the sameqa-evidence.json.smoke-ciwrites slim evidence (evidenceMode: "slim", no per-entryexecution).releasecovers the curated release-readiness slice;allselects every active maturity category and targets explicit QA Profile Evidence workflow dispatches when a full scorecard artifact is needed. - Runs multiple selected scenarios in parallel by default with isolated
gateway workers.
qa-channeldefaults to concurrency 4 (bounded by the selected scenario count). Use--concurrency <count>to tune the worker count, or--concurrency 1for the older serial lane. - Exits non-zero when any scenario fails. Use
--allow-failuresfor artifacts without a failing exit code. - Supports provider modes
live-frontier,mock-openai, andaimock.aimockstarts a local AIMock-backed provider server for experimental fixture and protocol-mock coverage without replacing the scenario-awaremock-openailane.
pnpm openclaw qa coverage --match <query>- Searches scenario IDs, titles, surfaces, coverage IDs, docs refs, code refs, plugins, and provider requirements, then prints matching suite targets.
- Use this before a QA Lab run when you know the touched behavior or file path but not the smallest scenario. Advisory only - still choose mock, live, Multipass, Matrix, or transport proof from the behavior being changed.
pnpm test:plugins:kitchen-sink-live- Runs the live OpenAI Kitchen Sink plugin gauntlet through QA Lab.
Installs the external Kitchen Sink package, verifies the plugin SDK
surface inventory, probes
/healthzand/readyz, records gateway CPU/RSS evidence, runs a live OpenAI turn, and checks adversarial diagnostics. Requires live OpenAI auth such asOPENAI_API_KEY. In hydrated Testbox sessions it automatically sources the Testbox live-auth profile when theopenclaw-testbox-envhelper is present.
- Runs the live OpenAI Kitchen Sink plugin gauntlet through QA Lab.
Installs the external Kitchen Sink package, verifies the plugin SDK
surface inventory, probes
pnpm test:gateway:cpu-scenarios- Runs the gateway startup bench plus a small mock QA Lab scenario pack
(
channel-chat-baseline,memory-failure-fallback,gateway-restart-inflight-run) and writes a combined CPU observation summary under.artifacts/gateway-cpu-scenarios/. - Flags only sustained hot CPU observations by default (
--cpu-core-warn, default0.9;--hot-wall-warn-ms, default30000), so short startup bursts are recorded as metrics without looking like the minutes-long gateway peg regression. - Runs against built
distartifacts; run a build first when the checkout does not already have fresh runtime output.
- Runs the gateway startup bench plus a small mock QA Lab scenario pack
(
pnpm openclaw qa suite --runner multipass- Runs the same QA suite inside a disposable Multipass Linux VM, keeping
the same scenario-selection and provider/model flags as
qa suite. - Live runs forward the QA auth inputs practical for the guest:
env-based provider keys, the QA live provider config path, and
CODEX_HOMEwhen present. - Output dirs must stay under the repo root so the guest can write back through the mounted workspace.
- Writes the normal QA report + summary plus Multipass logs under
.artifacts/qa-e2e/....
- Runs the same QA suite inside a disposable Multipass Linux VM, keeping
the same scenario-selection and provider/model flags as
pnpm qa:lab:up- Starts the Docker-backed QA site for operator-style QA work.
pnpm test:docker:npm-onboard-channel-agent- Builds an npm tarball from the current checkout, installs it globally in Docker, runs non-interactive OpenAI API-key onboarding, configures Telegram by default, verifies the packaged plugin runtime loads without startup dependency repair, runs doctor, and runs one local agent turn against a mocked OpenAI endpoint.
- Use
OPENCLAW_NPM_ONBOARD_CHANNEL=discordto run the same packaged-install lane with Discord.
pnpm test:docker:session-runtime-context- Runs a deterministic built-app Docker smoke for embedded runtime context
transcripts. Verifies hidden OpenClaw runtime context persists as a
non-display custom message instead of leaking into the visible user
turn, then seeds an affected broken session JSONL and verifies
openclaw doctor --fixrewrites it to the active branch with a backup.
- Runs a deterministic built-app Docker smoke for embedded runtime context
transcripts. Verifies hidden OpenClaw runtime context persists as a
non-display custom message instead of leaking into the visible user
turn, then seeds an affected broken session JSONL and verifies
pnpm test:docker:npm-telegram-live- Installs an OpenClaw package candidate in Docker, runs installed-package onboarding, configures Telegram through the installed CLI, then reuses the live Telegram QA lane with that installed package as the SUT Gateway.
- The trusted checkout owns the QA harness source, taxonomy, scenarios, dependencies, and private SDK build. The installed package remains the absolute CLI, Gateway, and bundled-plugin runtime under test, and its CLI writes the package candidate's persisted auth state.
- Defaults to
OPENCLAW_NPM_TELEGRAM_PACKAGE_SPEC=openclaw@beta; setOPENCLAW_NPM_TELEGRAM_PACKAGE_TGZ=/path/to/openclaw-current.tgzorOPENCLAW_CURRENT_PACKAGE_TGZto test a resolved local tarball instead of installing from the registry. - Emits repeated RTT timing in
qa-evidence.jsonby default withOPENCLAW_NPM_TELEGRAM_RTT_SAMPLES=20. OverrideOPENCLAW_NPM_TELEGRAM_RTT_SAMPLES,OPENCLAW_NPM_TELEGRAM_RTT_TIMEOUT_MS, orOPENCLAW_NPM_TELEGRAM_RTT_MAX_FAILURESto tune the run.OPENCLAW_NPM_TELEGRAM_RTT_CHECKSaccepts zero or exactly one canonical Telegram QA scenario id. When omitted, the normal lane sampleschannel-canary; focused non-RTT scenario runs stay probe-free. An explicit RTT scenario is included in scenario selection automatically, so callers do not need to repeat it inOPENCLAW_NPM_TELEGRAM_SCENARIOS. Multiple ids fail immediately, while unknown or inapplicable ids fail canonical scenario validation. The package runner promotes the selected RTT scenario once to the first position before the remaining taxonomy-backed fail-fast release scenarios. - Uses the same Convex-leased Test Server userbot credentials as
pnpm openclaw qa telegram. SetOPENCLAW_QA_CONVEX_SITE_URLand the secret for the selected role. The Docker wrapper selects Convex by default. - The wrapper validates Convex credential env on the host before Docker
build/install work. Set
OPENCLAW_NPM_TELEGRAM_SKIP_CREDENTIAL_PREFLIGHT=1only when deliberately debugging pre-credential setup. OPENCLAW_NPM_TELEGRAM_CREDENTIAL_ROLE=ci|maintaineroverrides the sharedOPENCLAW_QA_CREDENTIAL_ROLEfor this lane only. With no role, the wrapper usesciin CI andmaintaineroutside CI.- GitHub Actions exposes this lane as the manual maintainer workflow
NPM Telegram Beta E2E. It does not run on merge. The workflow uses theqa-live-sharedenvironment and Convex CI credential leases. Set its optionalrtt_scenarioinput to select the repeated RTT scenario, or leave it empty for the default behavior above. Enableallow_older_binary_destructive_actionsonly for intentional historical downgrade or recovery proof; it remains false by default.
- GitHub Actions also exposes
Package Acceptancefor side-run product proof against one candidate package. It accepts a Git ref, published npm spec, HTTPS tarball URL plus SHA-256, trusted-URL policy, or tarball artifact from another run (source=ref|npm|url|trusted-url|artifact), uploads the normalizedopenclaw-current.tgzaspackage-under-test, then runs the existing Docker E2E scheduler withsmoke,package,product,full, orcustomlane profiles. Settelegram_mode=mock-openaiorlive-frontierto run the Telegram QA workflow against the samepackage-under-testartifact.- Latest beta product proof:
gh workflow run package-acceptance.yml --ref main \ -f source=npm \ -f package_spec=openclaw@beta \ -f suite_profile=product \ -f telegram_mode=mock-openai- Exact tarball URL proof requires a digest and uses the public URL safety policy:
gh workflow run package-acceptance.yml --ref main \ -f source=url \ -f package_url=https://registry.npmjs.org/openclaw/-/openclaw-VERSION.tgz \ -f package_sha256=<sha256> \ -f suite_profile=package- Enterprise/private tarball mirrors use an explicit trusted-source policy:
gh workflow run package-acceptance.yml --ref main \ -f source=trusted-url \ -f trusted_source_id=enterprise-artifactory \ -f package_url=https://packages.example.internal:8443/artifactory/openclaw/openclaw-VERSION.tgz \ -f package_sha256=<sha256> \ -f suite_profile=packagesource=trusted-url reads .github/package-trusted-sources.json from the trusted workflow ref and does not accept URL credentials or a workflow-input private-network bypass. If the named policy declares bearer auth, configure the fixed OPENCLAW_TRUSTED_PACKAGE_TOKEN secret.
- Artifact proof downloads a tarball artifact from another Actions run:
gh workflow run package-acceptance.yml --ref main \ -f source=artifact \ -f artifact_run_id=<run-id> \ -f artifact_name=<artifact-name> \ -f suite_profile=smoke-
pnpm test:docker:plugins- Packs and installs the current OpenClaw build in Docker, starts the Gateway with OpenAI configured, then enables bundled channel/plugins via config edits.
- Verifies setup discovery leaves unconfigured downloadable plugins absent, the first configured doctor repair installs each missing downloadable plugin explicitly, and a second restart does not run hidden dependency repair.
- Also installs a known older npm baseline, enables Telegram before
running
openclaw update --tag <candidate>, and verifies the candidate's post-update doctor cleans legacy plugin dependency debris without a harness-side postinstall repair.
-
pnpm test:parallels:npm-update-
Runs the native packaged-install update smoke across Parallels guests. Each selected platform first installs the requested baseline package, then runs the installed
openclaw updatecommand in the same guest and verifies the installed version, update status, gateway readiness, and one local agent turn. -
Use
--platform macos,--platform windows, or--platform linuxwhile iterating on one guest. Use--jsonfor the summary artifact path and per-lane status. -
The OpenAI lane uses
openai/gpt-5.6-lunafor the live agent-turn proof by default. Pass--model <provider/model>or setOPENCLAW_PARALLELS_OPENAI_MODELto validate another OpenAI model. -
Wrap long local runs in a host timeout so Parallels transport stalls cannot consume the rest of the testing window:
bash timeout --foreground 150m pnpm test:parallels:npm-update -- --jsontimeout --foreground 90m pnpm test:parallels:npm-update -- --platform windows --json -
The script writes nested lane logs under
/tmp/openclaw-parallels-npm-update.*. Inspectwindows-update.log,macos-update.log, orlinux-update.logbefore assuming the outer wrapper is hung. -
Windows update can spend 10 to 15 minutes in post-update doctor and package update work on a cold guest; that is still healthy when the nested npm debug log is advancing.
-
Do not run this aggregate wrapper in parallel with individual Parallels macOS, Windows, or Linux smoke lanes. They share VM state and can collide on snapshot restore, package serving, or guest gateway state.
-
The post-update proof runs the normal bundled plugin surface because capability facades such as speech, image generation, and media understanding load through bundled runtime APIs even when the agent turn itself only checks a simple text response.
-
-
pnpm openclaw qa aimock- Starts only the local AIMock provider server for direct protocol smoke testing.
-
pnpm openclaw qa buzz- Runs the Buzz live QA lane against a real relay room using dedicated driver and SUT identities.
- Local runs use
--credential-file <path>withrelayUrl,roomId,driverPrivateKey, andsutPrivateKey. Closed relays may also needdriverAuthTagandsutAuthTag. Hosted relays requirewss://;ws://is accepted only for loopback development relays. - Defaults to
mock-openaiand runs canary and mention-gating scenarios through the real Buzz plugin path. - Supports
--credential-source convexwith a pooledkind: "buzz"row. Both public keys must be relay/room members, and the SUT must have the Bot room role. Never use a human owner or admin private key.
-
pnpm openclaw qa matrix- Runs the Matrix live QA lane against a disposable Docker-backed Tuwunel
homeserver. Source-checkout only - packaged installs do not ship
qa-lab. - Full CLI, profile/scenario catalog, env vars, and artifact layout: Matrix smoke lanes.
- Runs the Matrix live QA lane against a disposable Docker-backed Tuwunel
homeserver. Source-checkout only - packaged installs do not ship
-
pnpm openclaw qa telegram- Runs the Telegram live QA lane on Telegram's Test Server with one Convex-leased SUT bot and one independent TDLib user session.
- Uses
--credential-source convexby default and rejectsenv. ProvideOPENCLAW_QA_CONVEX_SITE_URLand the secret for the selected--credential-role. - Defaults cover canary, mention gating, command addressing,
/status, bot-to-bot mentioned replies, and core native command replies.mock-openaidefaults also cover deterministic reply-chain and Telegram final-message streaming regressions. Use--list-scenariosfor optional probes such assession_status. - Exits non-zero when any scenario fails. Use
--allow-failuresfor artifacts without a failing exit code. - The leased user drives and observes the shared Test Server group. No production Telegram account or bot-to-bot observer is used.
- Writes a Telegram QA report, summary, and
qa-evidence.jsonunder.artifacts/qa-e2e/.... Replying scenarios include RTT from driver send request to observed SUT reply.
Live transport lanes share one standard contract so new transports do not
drift; the per-lane coverage matrix lives in
QA overview - Live transport coverage.
qa-channel is the broad synthetic suite and is not part of that matrix.
Shared Telegram credentials via Convex (v1)
When --credential-source convex (or OPENCLAW_QA_CREDENTIAL_SOURCE=convex)
is enabled for live transport QA, QA lab acquires an exclusive lease from a
Convex-backed pool, heartbeats that lease while the lane is running, and
releases the lease on shutdown. Telegram always uses this source. The section
name predates Buzz, Discord, Slack, and WhatsApp support; the lease contract is
shared across kinds.
Reference Convex project scaffold: qa/convex-credential-broker/
Required env vars:
OPENCLAW_QA_CONVEX_SITE_URL(for examplehttps://your-deployment.convex.site)- One secret for the selected role:
OPENCLAW_QA_CONVEX_SECRET_MAINTAINERformaintainerOPENCLAW_QA_CONVEX_SECRET_CIforci
- Credential role selection:
- CLI:
--credential-role maintainer|ci - Env default:
OPENCLAW_QA_CREDENTIAL_ROLE(defaults tociin CI,maintainerotherwise)
- CLI:
Optional env vars:
OPENCLAW_QA_CREDENTIAL_LEASE_TTL_MS(default1200000)OPENCLAW_QA_CREDENTIAL_HEARTBEAT_INTERVAL_MS(default30000)OPENCLAW_QA_CREDENTIAL_ACQUIRE_TIMEOUT_MS(default90000)OPENCLAW_QA_CREDENTIAL_HTTP_TIMEOUT_MS(default15000)OPENCLAW_QA_CONVEX_ENDPOINT_PREFIX(default/qa-credentials/v1)OPENCLAW_QA_CREDENTIAL_OWNER_ID(optional trace id)OPENCLAW_QA_ALLOW_INSECURE_HTTP=1allows loopbackhttp://Convex URLs for local-only development.
OPENCLAW_QA_CONVEX_SITE_URL should use https:// in normal operation.
Maintainer admin commands (pool add/remove/list) require
OPENCLAW_QA_CONVEX_SECRET_MAINTAINER specifically.
CLI helpers for maintainers:
pnpm openclaw qa credentials doctorpnpm openclaw qa credentials add --kind telegram --payload-file qa/telegram-credential.jsonpnpm openclaw qa credentials list --kind telegrampnpm openclaw qa credentials remove --credential-id <credential-id>Use doctor before live runs to check the Convex site URL, broker secrets,
endpoint prefix, HTTP timeout, and admin/list reachability without printing
secret values. Use --json for machine-readable output in scripts and CI
utilities.
Default endpoint contract (OPENCLAW_QA_CONVEX_SITE_URL + /qa-credentials/v1).
Requests authenticate with an Authorization: Bearer <role secret> header;
bodies below omit that header:
POST /acquire- Request:
{ kind, ownerId, actorRole, leaseTtlMs, heartbeatIntervalMs } - Success:
{ status: "ok", credentialId, leaseToken, payload, leaseTtlMs?, heartbeatIntervalMs? } - Exhausted/retryable:
{ status: "error", code: "POOL_EXHAUSTED" | "NO_CREDENTIAL_AVAILABLE", ... }
- Request:
POST /payload-chunk- Request:
{ kind, ownerId, actorRole, credentialId, leaseToken, index } - Success:
{ status: "ok", index, data }
- Request:
POST /heartbeat- Request:
{ kind, ownerId, actorRole, credentialId, leaseToken, leaseTtlMs } - Success:
{ status: "ok" }(or empty2xx)
- Request:
POST /release- Request:
{ kind, ownerId, actorRole, credentialId, leaseToken } - Success:
{ status: "ok" }(or empty2xx)
- Request:
POST /admin/add(maintainer secret only)- Request:
{ kind, actorId, payload, note?, status? } - Success:
{ status: "ok", credential }
- Request:
POST /admin/remove(maintainer secret only)- Request:
{ credentialId, actorId } - Success:
{ status: "ok", changed, credential } - Active lease guard:
{ status: "error", code: "LEASE_ACTIVE", ... }
- Request:
POST /admin/list(maintainer secret only)- Request:
{ kind?, status?, includePayload?, limit? } - Success:
{ status: "ok", credentials, count }
- Request:
Payload shape for Telegram kind:
{ groupId: string, driverToken: string, sutToken: string }groupIdmust be a numeric Telegram chat id string.admin/addvalidates this shape forkind: "telegram"and rejects malformed payloads.
Broker-validated multi-channel payloads:
- Buzz:
{ relayUrl: string, roomId: string, driverPrivateKey: string, sutPrivateKey: string, driverAuthTag?: string, sutAuthTag?: string } - Discord:
{ guildId: string, channelId: string, driverBotToken: string, sutBotToken: string, sutApplicationId: string, voiceChannelId?: string } - WhatsApp:
{ driverPhoneE164: string, sutPhoneE164: string, driverAuthArchiveBase64: string, sutAuthArchiveBase64: string, groupJid?: string }
Slack lanes can also lease from the pool, but Slack payload validation
currently lives in the Slack QA runner rather than the broker. Use
{ channelId: string, driverBotToken: string, sutBotToken: string, sutAppToken: string }
for Slack rows.
Adding a channel to QA
The architecture and scenario-helper names for new channel adapters live in
QA overview - Adding a channel.
The minimum bar: implement the transport runner on the shared qa-lab host
seam, add an adapterFactory for shared scenarios, declare qaRunners in the
plugin manifest, mount as openclaw qa <runner>, and author scenarios under
qa/scenarios/.