docs/concepts/qa-matrix.md
The Matrix QA lane runs the bundled @openclaw/matrix plugin against a disposable Tuwunel homeserver in Docker, with temporary driver, SUT, and observer accounts plus seeded rooms. It is the live transport-real coverage for Matrix.
This is maintainer-only tooling. Packaged OpenClaw releases intentionally omit qa-lab, so openclaw qa is only available from a source checkout. Source checkouts load the bundled runner directly — no plugin install step is needed.
For broader QA framework context, see QA overview.
pnpm openclaw qa matrix --profile fast --fail-fast
Plain pnpm openclaw qa matrix runs --profile all and does not stop on first failure. Use --profile fast --fail-fast for a release gate; shard the catalog with --profile transport|media|e2ee-smoke|e2ee-deep|e2ee-cli when running the full inventory in parallel.
ghcr.io/matrix-construct/tuwunel:v1.5.1, server name matrix-qa.test, port 28008).driver (sends inbound traffic), sut (the OpenClaw Matrix account under test), observer (third-party traffic capture).qa-channel is not loaded in the child.pnpm openclaw qa matrix [options]
| Flag | Default | Description |
|---|---|---|
--profile <profile> | all | Scenario profile. See Profiles. |
--fail-fast | off | Stop after the first failed check or scenario. |
--scenario <id> | — | Run only this scenario. Repeatable. See Scenarios. |
--output-dir <path> | <repo>/.artifacts/qa-e2e/matrix-<timestamp> | Where reports, summary, observed events, and the output log are written. Relative paths resolve against --repo-root. |
--repo-root <path> | process.cwd() | Repository root when invoking from a neutral working directory. |
--sut-account <id> | sut | Matrix account id inside the QA gateway config. |
The lane uses a real Matrix transport but the model provider is configurable:
| Flag | Default | Description |
|---|---|---|
--provider-mode <mode> | live-frontier | mock-openai for deterministic mock dispatch or live-frontier for live frontier providers. The legacy alias live-openai still works. |
--model <ref> | provider default | Primary provider/model ref. |
--alt-model <ref> | provider default | Alternate provider/model ref where scenarios switch mid-run. |
--fast | off | Enable provider fast mode where supported. |
Matrix QA does not accept --credential-source or --credential-role. The lane provisions disposable users locally; there is no shared credential pool to lease against.
The selected profile decides which scenarios run.
| Profile | Use it for |
|---|---|
all (default) | Full catalog. Slow but exhaustive. |
fast | Release-gate subset that exercises the live transport contract: canary, mention gating, allowlist block, reply shape, restart resume, thread follow-up, thread isolation, reaction observation, and exec approval metadata delivery. |
transport | Transport-level threading, DM, room, autojoin, mention/allowlist, approval, and reaction scenarios. |
media | Image, audio, video, PDF, EPUB attachment coverage. |
e2ee-smoke | Minimum E2EE coverage — basic encrypted reply, thread follow-up, bootstrap success. |
e2ee-deep | Exhaustive E2EE state-loss, backup, key, and recovery scenarios. |
e2ee-cli | openclaw matrix encryption setup and verify * CLI scenarios driven through the QA harness. |
The exact mapping lives in extensions/qa-matrix/src/runners/contract/scenario-catalog.ts.
The full scenario id list is the MatrixQaScenarioId union in extensions/qa-matrix/src/runners/contract/scenario-catalog.ts:15. Categories include:
matrix-thread-*, matrix-subagent-thread-spawnmatrix-top-level-reply-shape, matrix-room-*, matrix-dm-*matrix-room-partial-streaming-preview, matrix-room-quiet-streaming-preview, matrix-room-tool-progress-*, matrix-room-block-streamingmatrix-media-type-coverage, matrix-room-image-understanding-attachment, matrix-attachment-only-ignored, matrix-unsupported-media-safematrix-room-autojoin-invite, matrix-secondary-room-*matrix-reaction-*matrix-approval-* (exec/plugin metadata, chunked fallback, deny reactions, threads, and target: "both" routing)matrix-restart-*, matrix-stale-sync-replay-dedupe, matrix-room-membership-loss, matrix-homeserver-restart-resume, matrix-initial-catchup-then-incrementalmatrix-mention-*, matrix-allowbots-*, matrix-allowlist-*, matrix-multi-actor-ordering, matrix-inbound-edit-*, matrix-mxid-prefixed-command-block, matrix-observer-allowlist-overridematrix-e2ee-* (basic reply, thread follow-up, bootstrap, recovery key lifecycle, state-loss variants, server backup behavior, device hygiene, SAS / QR / DM verification, restart, artifact redaction)matrix-e2ee-cli-* (encryption setup, idempotent setup, bootstrap failure, recovery-key lifecycle, multi-account, gateway-reply round-trip, self-verification)Pass --scenario <id> (repeatable) to run a hand-picked set; combine with --profile all to ignore profile gating.
| Variable | Default | Effect |
|---|---|---|
OPENCLAW_QA_MATRIX_TIMEOUT_MS | 1800000 (30 min) | Hard upper bound on the entire run. |
OPENCLAW_QA_MATRIX_CANARY_TIMEOUT_MS | 45000 | Bound for the initial canary reply. Release CI raises this on shared runners so a slow first gateway turn does not fail before scenario coverage starts. |
OPENCLAW_QA_MATRIX_NO_REPLY_WINDOW_MS | 8000 | Quiet window for negative no-reply assertions. Clamped to ≤ the run timeout. |
OPENCLAW_QA_MATRIX_CLEANUP_TIMEOUT_MS | 90000 | Bound for Docker teardown. Failure surfaces include the recovery docker compose ... down --remove-orphans command. |
OPENCLAW_QA_MATRIX_TUWUNEL_IMAGE | ghcr.io/matrix-construct/tuwunel:v1.5.1 | Override the homeserver image when validating against a different Tuwunel version. |
OPENCLAW_QA_MATRIX_PROGRESS | on | 0 silences [matrix-qa] ... progress lines on stderr. 1 forces them on. |
OPENCLAW_QA_MATRIX_CAPTURE_CONTENT | redacted | 1 keeps message body and formatted_body in matrix-qa-observed-events.json. Default redacts to keep CI artifacts safe. |
OPENCLAW_QA_MATRIX_DISABLE_FORCE_EXIT | off | 1 skips the deterministic process.exit after artifact write. The default forces exit because matrix-js-sdk's native crypto handles can keep the event loop alive past artifact completion. |
OPENCLAW_RUN_NODE_OUTPUT_LOG | unset | When set by an outer launcher (e.g. scripts/run-node.mjs), Matrix QA reuses that log path instead of starting its own tee. |
Written to --output-dir:
matrix-qa-report.md — Markdown protocol report (what passed, failed, was skipped, and why).matrix-qa-summary.json — Structured summary suitable for CI parsing and dashboards.matrix-qa-observed-events.json — Observed Matrix events from the driver and observer clients. Bodies are redacted unless OPENCLAW_QA_MATRIX_CAPTURE_CONTENT=1; approval metadata is summarized with selected safe fields and truncated command preview.matrix-qa-output.log — Combined stdout/stderr from the run. If OPENCLAW_RUN_NODE_OUTPUT_LOG is set, the outer launcher's log is reused instead.The default output dir is <repo>/.artifacts/qa-e2e/matrix-<timestamp> so successive runs do not overwrite each other.
matrix-js-sdk native crypto handles can outlive the harness. The default forces a clean process.exit after artifact write; if you have unset OPENCLAW_QA_MATRIX_DISABLE_FORCE_EXIT=1, expect the process to linger.docker compose ... down --remove-orphans invocation) and run it manually to release the homeserver port.OPENCLAW_QA_MATRIX_NO_REPLY_WINDOW_MS (default 8 s) when CI is fast; raise it on slow shared runners.OPENCLAW_QA_MATRIX_CAPTURE_CONTENT=1 and attach matrix-qa-observed-events.json. Treat the resulting artifact as sensitive.OPENCLAW_QA_MATRIX_TUWUNEL_IMAGE at the version under test. The lane checks in only the pinned default image.Matrix is one of three live transport lanes (Matrix, Telegram, Discord) that share a single contract checklist defined in QA overview → Live transport coverage. qa-channel remains the broad synthetic suite and is intentionally not part of that matrix.