Fundamentals
Descripción general del aseguramiento de calidad
La pila privada de QA está pensada para ejercitar OpenClaw de una forma más realista y con forma de canal de lo que puede hacerlo una sola prueba unitaria.
Componentes actuales:
extensions/qa-channel: canal de mensajes sintético con superficies de DM, canal, hilo, reacción, edición y eliminación.extensions/qa-lab: interfaz de depuración y bus de QA para observar la transcripción, inyectar mensajes entrantes y exportar un informe en Markdown.extensions/qa-matrix, futuros plugins de ejecución: adaptadores de transporte en vivo que manejan un canal real dentro de un gateway de QA secundario.qa/: recursos semilla respaldados por el repositorio para la tarea inicial y los escenarios base de QA.- Mantis: verificación en vivo antes y después para errores que necesitan transportes reales, capturas de pantalla del navegador, estado de VM y evidencia de PR.
Superficie de comandos
Cada flujo de QA se ejecuta bajo pnpm openclaw qa <subcommand>. Muchos tienen alias de script pnpm qa:*;
ambas formas son compatibles.
| Comando | Propósito |
|---|---|
qa run |
Autocomprobación de QA incluida; escribe un informe en Markdown. |
qa suite |
Ejecuta escenarios respaldados por el repositorio contra el carril del Gateway de QA. Alias: pnpm openclaw qa suite --runner multipass para una VM Linux desechable. |
qa coverage |
Imprime el inventario de cobertura de escenarios en Markdown (--json para salida de máquina). |
qa parity-report |
Compara dos archivos qa-suite-summary.json y escribe el informe de paridad agéntica. |
qa character-eval |
Ejecuta el escenario de QA de carácter en varios modelos en vivo con un informe evaluado. Consulta Informes. |
qa manual |
Ejecuta un prompt puntual contra el carril de proveedor/modelo seleccionado. |
qa ui |
Inicia la interfaz de depuración de QA y el bus local de QA (alias: pnpm qa:lab:ui). |
qa docker-build-image |
Construye la imagen Docker de QA prehorneada. |
qa docker-scaffold |
Escribe una plantilla docker-compose para el panel de QA + el carril de Gateway. |
qa up |
Construye el sitio de QA, inicia la pila respaldada por Docker, imprime la URL (alias: pnpm qa:lab:up; la variante :fast añade --use-prebuilt-image --bind-ui-dist --skip-ui-build). |
qa aimock |
Inicia solo el servidor del proveedor AIMock. |
qa mock-openai |
Inicia solo el servidor del proveedor mock-openai consciente de escenarios. |
qa credentials doctor / add / list / remove |
Administra el conjunto compartido de credenciales de Convex. |
qa matrix |
Carril de transporte en vivo contra un homeserver Tuwunel desechable. Consulta QA de Matrix. |
qa telegram |
Carril de transporte en vivo contra un grupo privado real de Telegram. |
qa discord |
Carril de transporte en vivo contra un canal real de un guild privado de Discord. |
qa slack |
Carril de transporte en vivo contra un canal privado real de Slack. |
qa mantis |
Ejecutor de verificación antes y después para errores de transporte en vivo, con evidencia de reacciones de estado en Discord, smoke de escritorio/navegador de Crabbox y smoke de Slack en VNC. Consulta Mantis y Manual operativo de escritorio de Slack para Mantis. |
Flujo del operador
El flujo actual del operador de QA es un sitio de QA de dos paneles:
- Izquierda: panel del Gateway (interfaz de control) con el agente.
- Derecha: QA Lab, que muestra la transcripción estilo Slack y el plan de escenario.
Ejecútalo con:
pnpm qa:lab:up
Eso construye el sitio de QA, inicia el carril de Gateway respaldado por Docker y expone la página de QA Lab, donde un operador o un bucle de automatización puede dar al agente una misión de QA, observar el comportamiento real del canal y registrar lo que funcionó, falló o quedó bloqueado.
Para iterar más rápido en la interfaz de QA Lab sin reconstruir la imagen Docker cada vez, inicia la pila con un paquete de QA Lab montado por enlace:
pnpm openclaw qa docker-build-image
pnpm qa:lab:build
pnpm qa:lab:up:fast
pnpm qa:lab:watch
qa:lab:up:fast mantiene los servicios Docker sobre una imagen preconstruida y monta por enlace
extensions/qa-lab/web/dist en el contenedor qa-lab. qa:lab:watch
reconstruye ese paquete al cambiar, y el navegador se recarga automáticamente cuando cambia el hash de recursos de QA Lab.
Para un smoke local de trazas de OpenTelemetry, ejecuta:
pnpm qa:otel:smoke
Ese script inicia un receptor local de trazas OTLP/HTTP, ejecuta el escenario de QA
otel-trace-smoke con el Plugin diagnostics-otel habilitado, luego
decodifica los spans protobuf exportados y afirma la forma crítica para la versión:
openclaw.run, openclaw.harness.run, openclaw.model.call,
openclaw.context.assembled y openclaw.message.delivery deben estar presentes;
las llamadas al modelo no deben exportar StreamAbandoned en turnos correctos; los ID de diagnóstico sin procesar y los
atributos openclaw.content.* deben permanecer fuera de la traza. Escribe
otel-smoke-summary.json junto a los artefactos de la suite de QA.
La QA de observabilidad se mantiene solo para checkouts de código fuente. El tarball de npm omite intencionalmente
QA Lab, por lo que los carriles de lanzamiento Docker de paquete no ejecutan comandos qa. Usa
pnpm qa:otel:smoke desde un checkout de código fuente construido cuando cambies la instrumentación
de diagnósticos.
Para un carril smoke de Matrix con transporte real, ejecuta:
pnpm openclaw qa matrix --profile fast --fail-fast
La referencia completa de CLI, el catálogo de perfiles/escenarios, las variables de entorno y el diseño de artefactos de este carril están en QA de Matrix. En resumen: aprovisiona un homeserver Tuwunel desechable en Docker, registra usuarios temporales de controlador/SUT/observador, ejecuta el Plugin real de Matrix dentro de un Gateway de QA secundario limitado a ese transporte (sin qa-channel) y luego escribe un informe en Markdown, un resumen JSON, un artefacto de eventos observados y un registro de salida combinado bajo .artifacts/qa-e2e/matrix-<timestamp>/.
Los escenarios cubren comportamientos de transporte que las pruebas unitarias no pueden demostrar de extremo a extremo: compuerta de menciones, políticas allow-bot, listas de permitidos, respuestas de nivel superior y en hilos, enrutamiento de DM, manejo de reacciones, supresión de ediciones entrantes, deduplicación de repetición tras reinicio, recuperación ante interrupción del homeserver, entrega de metadatos de aprobación, manejo de medios y flujos de arranque/recuperación/verificación de E2EE de Matrix. El perfil CLI de E2EE también ejecuta openclaw matrix encryption setup y comandos de verificación a través del mismo homeserver desechable antes de comprobar las respuestas del Gateway.
Discord también tiene escenarios opcionales solo de Mantis para reproducción de errores. Usa
--scenario discord-status-reactions-tool-only para la línea temporal explícita de reacciones de estado,
o --scenario discord-thread-reply-filepath-attachment para crear un
hilo real de Discord y verificar que message.thread-reply preserve un adjunto
filePath. Estos escenarios quedan fuera del carril Discord en vivo predeterminado
porque son sondas de reproducción antes/después, no cobertura smoke amplia.
El flujo de trabajo de Mantis para adjuntos de hilo también puede añadir un video testigo de Discord Web
con sesión iniciada cuando MANTIS_DISCORD_VIEWER_CHROME_PROFILE_DIR o
MANTIS_DISCORD_VIEWER_CHROME_PROFILE_TGZ_B64 está configurado en el entorno de QA.
Ese perfil de visor es solo para captura visual; la decisión de aprobación/fallo
sigue viniendo del oráculo REST de Discord.
CI usa la misma superficie de comandos en .github/workflows/qa-live-transports-convex.yml. Las ejecuciones programadas y manuales predeterminadas ejecutan el perfil rápido de Matrix con credenciales frontier en vivo, --fast y OPENCLAW_QA_MATRIX_NO_REPLY_WINDOW_MS=3000. El matrix_profile=all manual se abre en abanico en los cinco fragmentos de perfil para que el catálogo exhaustivo pueda ejecutarse en paralelo manteniendo un directorio de artefactos por fragmento.
Para carriles smoke de Telegram, Discord y Slack con transporte real:
pnpm openclaw qa telegram
pnpm openclaw qa discord
pnpm openclaw qa slack
Apuntan a un canal real preexistente con dos bots (controlador + SUT). Las variables de entorno requeridas, las listas de escenarios, los artefactos de salida y el conjunto de credenciales de Convex están documentados en la referencia de QA de Telegram, Discord y Slack a continuación.
Para una ejecución completa de una VM de escritorio de Slack con rescate por VNC, ejecuta:
pnpm openclaw qa mantis slack-desktop-smoke \
--gateway-setup \
--scenario slack-canary \
--keep-lease
Ese comando alquila una máquina de escritorio/navegador de Crabbox, ejecuta el carril en vivo de Slack dentro de la VM, abre Slack Web en el navegador VNC, captura el escritorio y copia slack-qa/, slack-desktop-smoke.png y slack-desktop-smoke.mp4, cuando la captura de video está disponible, de vuelta al directorio de artefactos de Mantis. Los alquileres de escritorio/navegador de Crabbox proporcionan por adelantado las herramientas de captura y los paquetes auxiliares de navegador/compilación nativa, así que el escenario solo debería instalar alternativas en alquileres más antiguos. Mantis informa los tiempos totales y por fase en mantis-slack-desktop-smoke-report.md, de modo que las ejecuciones lentas muestran si el tiempo se dedicó al calentamiento del alquiler, la obtención de credenciales, la configuración remota o la copia de artefactos. Reutiliza --lease-id <cbx_...> después de iniciar sesión manualmente en Slack Web mediante VNC; los alquileres reutilizados también mantienen caliente la caché del almacén pnpm de Crabbox. El valor predeterminado --hydrate-mode source verifica desde un checkout de código fuente y ejecuta la instalación/compilación dentro de la VM. Usa --hydrate-mode prehydrated solo cuando el espacio de trabajo remoto reutilizado ya tenga node_modules y un dist/ compilado; ese modo omite el costoso paso de instalación/compilación y falla de forma cerrada cuando el espacio de trabajo no está listo. Con --gateway-setup, Mantis deja un Gateway persistente de OpenClaw Slack ejecutándose dentro de la VM en el puerto 38973; sin esa opción, el comando ejecuta el carril normal de QA de Slack bot a bot y sale después de capturar los artefactos.
La lista de verificación del operador, el comando de despacho del flujo de trabajo de GitHub, el contrato de comentario de evidencia, la tabla de decisión de modo de hidratación, la interpretación de tiempos y los pasos de gestión de fallos están en Runbook de escritorio Slack de Mantis.
Para una tarea de escritorio de estilo agente/CV, ejecuta:
pnpm openclaw qa mantis visual-task \
--browser-url https://example.net \
--expect-text "Example Domain" \
--vision-model openai/gpt-5.4
visual-task alquila o reutiliza una máquina de escritorio/navegador de Crabbox, inicia crabbox record --while, controla el navegador visible mediante un visual-driver anidado, captura visual-task.png, ejecuta openclaw infer image describe contra la captura de pantalla cuando se selecciona --vision-mode image-describe, y escribe visual-task.mp4, mantis-visual-task-summary.json, mantis-visual-task-driver-result.json y mantis-visual-task-report.md. Cuando --expect-text está definido, el prompt de visión pide un veredicto JSON estructurado y solo aprueba cuando el modelo informa evidencia visible positiva; una respuesta negativa que solo cite el texto objetivo falla la aserción. Usa --vision-mode metadata para un smoke sin modelo que demuestre la infraestructura de escritorio, navegador, captura de pantalla y video sin llamar a un proveedor de comprensión de imágenes. La grabación es un artefacto requerido para visual-task; si Crabbox no graba ningún visual-task.mp4 no vacío, la tarea falla aunque el controlador visual haya aprobado. En caso de fallo, Mantis conserva el alquiler para VNC salvo que la tarea ya hubiera aprobado y --keep-lease no estuviera definido.
Antes de usar credenciales en vivo agrupadas, ejecuta:
pnpm openclaw qa credentials doctor
El doctor comprueba el entorno del broker Convex, valida la configuración de endpoints y verifica la accesibilidad de admin/list cuando el secreto del mantenedor está presente. Solo informa el estado definido/ausente de los secretos.
Cobertura de transporte en vivo
Los carriles de transporte en vivo comparten un único contrato en lugar de que cada uno invente su propia forma de lista de escenarios. qa-channel es la suite sintética amplia de comportamiento de producto y no forma parte de la matriz de cobertura de transporte en vivo.
| Carril | Canary | Control de menciones | Bot a bot | Bloqueo por lista permitida | Respuesta de nivel superior | Reanudación tras reinicio | Seguimiento en hilo | Aislamiento de hilo | Observación de reacción | Comando de ayuda | Registro de comando nativo |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Matrix | x | x | x | x | x | x | x | x | x | ||
| Telegram | x | x | x | x | |||||||
| Discord | x | x | x | x | |||||||
| Slack | x | x | x | x | x | x | x | x |
Esto mantiene qa-channel como la suite amplia de comportamiento de producto, mientras Matrix, Telegram y los futuros transportes en vivo comparten una lista de verificación explícita de contrato de transporte.
Para un carril de VM Linux descartable sin introducir Docker en la ruta de QA, ejecuta:
pnpm openclaw qa suite --runner multipass --scenario channel-chat-baseline
Esto arranca un invitado Multipass nuevo, instala dependencias, compila OpenClaw dentro del invitado, ejecuta qa suite y luego copia el informe y el resumen normales de QA de vuelta a .artifacts/qa-e2e/... en el host.
Reutiliza el mismo comportamiento de selección de escenarios que qa suite en el host.
Las ejecuciones de suite en host y Multipass ejecutan de forma predeterminada varios escenarios seleccionados en paralelo con trabajadores de Gateway aislados. qa-channel usa por defecto una concurrencia de 4, limitada por el número de escenarios seleccionados. Usa --concurrency <count> para ajustar el número de trabajadores, o --concurrency 1 para la ejecución en serie.
El comando sale con estado distinto de cero cuando falla cualquier escenario. Usa --allow-failures cuando quieras artefactos sin un código de salida fallido.
Las ejecuciones en vivo reenvían las entradas de autenticación de QA compatibles que son prácticas para el invitado: claves de proveedor basadas en entorno, la ruta de configuración del proveedor en vivo de QA y CODEX_HOME cuando está presente. Mantén --output-dir bajo la raíz del repositorio para que el invitado pueda escribir de vuelta mediante el espacio de trabajo montado.
Referencia de QA de Telegram, Discord y Slack
Matrix tiene una página dedicada debido a su cantidad de escenarios y al aprovisionamiento de homeserver respaldado por Docker. Telegram, Discord y Slack son más pequeños: un puñado de escenarios cada uno, sin sistema de perfiles, contra canales reales preexistentes, así que su referencia vive aquí.
Flags de CLI compartidos
Estos carriles se registran mediante extensions/qa-lab/src/live-transports/shared/live-transport-cli.ts y aceptan los mismos flags:
| Flag | Predeterminado | Descripción |
|---|---|---|
--scenario <id> |
- | Ejecuta solo este escenario. Repetible. |
--output-dir <path> |
<repo>/.artifacts/qa-e2e/{telegram,discord,slack}-<timestamp> |
Donde se escriben los informes/resumen/mensajes observados y el registro de salida. Las rutas relativas se resuelven contra --repo-root. |
--repo-root <path> |
process.cwd() |
Raíz del repositorio al invocar desde un cwd neutral. |
--sut-account <id> |
sut |
Id de cuenta temporal dentro de la configuración del Gateway de QA. |
--provider-mode <mode> |
live-frontier |
mock-openai o live-frontier (live-openai heredado todavía funciona). |
--model <ref> / --alt-model <ref> |
valor predeterminado del proveedor | Referencias de modelo principal/alternativo. |
--fast |
desactivado | Modo rápido del proveedor cuando es compatible. |
--credential-source <env|convex> |
env |
Consulta pool de credenciales Convex. |
--credential-role <maintainer|ci> |
ci en CI, maintainer en caso contrario |
Rol usado cuando --credential-source convex. |
Cada carril sale con estado distinto de cero ante cualquier escenario fallido. --allow-failures escribe artefactos sin establecer un código de salida fallido.
QA de Telegram
pnpm openclaw qa telegram
Apunta a un grupo privado real de Telegram con dos bots distintos (controlador + SUT). El bot SUT debe tener un nombre de usuario de Telegram; la observación bot a bot funciona mejor cuando ambos bots tienen habilitado Bot-to-Bot Communication Mode en @BotFather.
Entorno requerido cuando --credential-source env:
OPENCLAW_QA_TELEGRAM_GROUP_ID- id numérico de chat (cadena).OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKENOPENCLAW_QA_TELEGRAM_SUT_BOT_TOKEN
Opcional:
OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT=1conserva los cuerpos de mensaje en los artefactos de mensajes observados (por defecto los redacta).
Escenarios (extensions/qa-lab/src/live-transports/telegram/telegram-live.runtime.ts:44):
telegram-canarytelegram-mention-gatingtelegram-mentioned-message-replytelegram-help-commandtelegram-commands-commandtelegram-tools-compact-commandtelegram-whoami-commandtelegram-context-commandtelegram-long-final-reuses-previewtelegram-long-final-three-chunks
Artefactos de salida:
telegram-qa-report.mdtelegram-qa-summary.json- incluye RTT por respuesta (envío del controlador → respuesta SUT observada) empezando por el canary.telegram-qa-observed-messages.json- cuerpos redactados salvo queOPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT=1.
QA de Discord
pnpm openclaw qa discord
Apunta a un canal de guild privado real de Discord con dos bots: un bot controlador controlado por el arnés y un bot SUT iniciado por el Gateway hijo de OpenClaw mediante el Plugin de Discord incluido. Verifica el manejo de menciones en el canal, que el bot SUT haya registrado el comando nativo /help con Discord, y escenarios de evidencia Mantis con opt-in.
Entorno requerido cuando --credential-source env:
OPENCLAW_QA_DISCORD_GUILD_IDOPENCLAW_QA_DISCORD_CHANNEL_IDOPENCLAW_QA_DISCORD_DRIVER_BOT_TOKENOPENCLAW_QA_DISCORD_SUT_BOT_TOKENOPENCLAW_QA_DISCORD_SUT_APPLICATION_ID- debe coincidir con el id de usuario del bot SUT devuelto por Discord (si no, el carril falla rápido).
Opcional:
OPENCLAW_QA_DISCORD_CAPTURE_CONTENT=1conserva los cuerpos de mensaje en los artefactos de mensajes observados.OPENCLAW_QA_DISCORD_VOICE_CHANNEL_IDselecciona el canal de voz/escenario paradiscord-voice-autojoin; sin él, el escenario elige el primer canal de voz/escenario visible para el bot SUT.
Escenarios (extensions/qa-lab/src/live-transports/discord/discord-live.runtime.ts:36):
discord-canarydiscord-mention-gatingdiscord-native-help-command-registrationdiscord-voice-autojoin- escenario de voz opcional. Se ejecuta por sí solo, habilitachannels.discord.voice.autoJoiny verifica que el estado de voz actual de Discord del bot SUT sea el canal de voz/escenario de destino. Las credenciales de Discord de Convex pueden incluirvoiceChannelIdopcional; de lo contrario, el ejecutor descubre el primer canal de voz/escenario visible en el servidor.discord-status-reactions-tool-only- escenario Mantis opcional. Se ejecuta por sí solo porque cambia el SUT a respuestas de servidor siempre activas y solo con herramientas conmessages.statusReactions.enabled=true; luego captura una línea de tiempo de reacciones REST y artefactos visuales HTML/PNG. Los informes antes/después de Mantis también conservan los artefactos MP4 proporcionados por el escenario comobaseline.mp4ycandidate.mp4.
Ejecuta explícitamente el escenario de auto-unión de voz de Discord:
pnpm openclaw qa discord \
--scenario discord-voice-autojoin \
--provider-mode mock-openai
Ejecuta explícitamente el escenario de reacciones de estado de Mantis:
pnpm openclaw qa discord \
--scenario discord-status-reactions-tool-only \
--provider-mode live-frontier \
--model openai/gpt-5.4 \
--alt-model openai/gpt-5.4 \
--fast
Artefactos de salida:
discord-qa-report.mddiscord-qa-summary.jsondiscord-qa-observed-messages.json- cuerpos redactados salvo queOPENCLAW_QA_DISCORD_CAPTURE_CONTENT=1.discord-qa-reaction-timelines.jsonydiscord-status-reactions-tool-only-timeline.pngcuando se ejecuta el escenario de reacciones de estado.
QA de Slack
pnpm openclaw qa slack
Apunta a un canal privado real de Slack con dos bots distintos: un bot controlador manejado por el arnés y un bot SUT iniciado por el Gateway hijo de OpenClaw mediante el Plugin de Slack incluido.
Entorno requerido cuando --credential-source env:
OPENCLAW_QA_SLACK_CHANNEL_IDOPENCLAW_QA_SLACK_DRIVER_BOT_TOKENOPENCLAW_QA_SLACK_SUT_BOT_TOKENOPENCLAW_QA_SLACK_SUT_APP_TOKEN
Opcional:
OPENCLAW_QA_SLACK_CAPTURE_CONTENT=1conserva los cuerpos de los mensajes en los artefactos de mensajes observados.
Escenarios (extensions/qa-lab/src/live-transports/slack/slack-live.runtime.ts:39):
slack-canaryslack-mention-gatingslack-allowlist-blockslack-top-level-reply-shapeslack-restart-resumeslack-thread-follow-upslack-thread-isolation
Artefactos de salida:
slack-qa-report.mdslack-qa-summary.jsonslack-qa-observed-messages.json- cuerpos redactados salvo queOPENCLAW_QA_SLACK_CAPTURE_CONTENT=1.
Configurar el espacio de trabajo de Slack
La vía necesita dos apps de Slack distintas en un espacio de trabajo, además de un canal del que ambos bots sean miembros:
channelId- el idCxxxxxxxxxxde un canal al que ambos bots hayan sido invitados. Usa un canal dedicado; la vía publica en cada ejecución.driverBotToken- token de bot (xoxb-...) de la app Driver.sutBotToken- token de bot (xoxb-...) de la app SUT, que debe ser una app de Slack separada del controlador para que su id de usuario de bot sea distinto.sutAppToken- token de nivel de app (xapp-...) de la app SUT conconnections:write, usado por Socket Mode para que la app SUT pueda recibir eventos.
Prefiere un espacio de trabajo de Slack dedicado a QA antes que reutilizar un espacio de trabajo de producción.
El manifiesto SUT siguiente reduce intencionadamente la instalación de producción del Plugin de Slack incluido (extensions/slack/src/setup-shared.ts:10) a los permisos y eventos cubiertos por el conjunto de QA en vivo de Slack. Para la configuración del canal de producción tal como la ven los usuarios, consulta Configuración rápida del canal de Slack; el par QA Driver/SUT está separado intencionadamente porque la vía necesita dos ids de usuario de bot distintos en un espacio de trabajo.
1. Crea la app Driver
Ve a api.slack.com/apps → Create New App → From a manifest → elige el espacio de trabajo de QA, pega el siguiente manifiesto y luego Install to Workspace:
{
"display_information": {
"name": "OpenClaw QA Driver",
"description": "Test driver bot for OpenClaw QA Slack live lane"
},
"features": {
"bot_user": {
"display_name": "OpenClaw QA Driver",
"always_online": true
}
},
"oauth_config": {
"scopes": {
"bot": ["chat:write", "channels:history", "groups:history", "users:read"]
}
},
"settings": {
"socket_mode_enabled": false
}
}
Copia el Bot User OAuth Token (xoxb-...): ese se convierte en driverBotToken. El controlador solo necesita publicar mensajes e identificarse; sin eventos, sin Socket Mode.
2. Crea la app SUT
Repite Create New App → From a manifest en el mismo espacio de trabajo. Esta app de QA usa intencionadamente una versión más restringida del manifiesto de producción del Plugin de Slack incluido (extensions/slack/src/setup-shared.ts:10): se omiten los ámbitos y eventos de reacciones porque el conjunto de QA en vivo de Slack aún no cubre el manejo de reacciones.
{
"display_information": {
"name": "OpenClaw QA SUT",
"description": "OpenClaw QA SUT connector for OpenClaw"
},
"features": {
"bot_user": {
"display_name": "OpenClaw QA SUT",
"always_online": true
},
"app_home": {
"home_tab_enabled": true,
"messages_tab_enabled": true,
"messages_tab_read_only_enabled": false
}
},
"oauth_config": {
"scopes": {
"bot": [
"app_mentions:read",
"assistant:write",
"channels:history",
"channels:read",
"chat:write",
"commands",
"emoji:read",
"files:read",
"files:write",
"groups:history",
"groups:read",
"im:history",
"im:read",
"im:write",
"mpim:history",
"mpim:read",
"mpim:write",
"pins:read",
"pins:write",
"usergroups:read",
"users:read"
]
}
},
"settings": {
"socket_mode_enabled": true,
"event_subscriptions": {
"bot_events": [
"app_home_opened",
"app_mention",
"channel_rename",
"member_joined_channel",
"member_left_channel",
"message.channels",
"message.groups",
"message.im",
"message.mpim",
"pin_added",
"pin_removed"
]
}
}
}
Después de que Slack cree la app, haz dos cosas en su página de configuración:
- Install to Workspace → copia el Bot User OAuth Token → ese se convierte en
sutBotToken. - Basic Information → App-Level Tokens → Generate Token and Scopes → añade el ámbito
connections:write→ guarda → copia el valorxapp-...→ ese se convierte ensutAppToken.
Verifica que los dos bots tengan ids de usuario distintos llamando a auth.test con cada token. El runtime distingue entre el controlador y el SUT por id de usuario; reutilizar una app para ambos hará que la restricción de menciones falle inmediatamente.
3. Crea el canal
En el espacio de trabajo de QA, crea un canal (p. ej., #openclaw-qa) e invita a ambos bots desde dentro del canal:
/invite @OpenClaw QA Driver
/invite @OpenClaw QA SUT
Copia el id Cxxxxxxxxxx desde channel info → About → Channel ID: ese se convierte en channelId. Un canal público funciona; si usas un canal privado, ambas apps ya tienen groups:history, así que las lecturas del historial del arnés seguirán funcionando.
4. Registra las credenciales
Dos opciones. Usa variables de entorno para depuración en una sola máquina (define las cuatro variables OPENCLAW_QA_SLACK_* y pasa --credential-source env), o inicializa el pool compartido de Convex para que CI y otros mantenedores puedan arrendarlas.
Para el pool de Convex, escribe los cuatro campos en un archivo JSON:
{
"channelId": "Cxxxxxxxxxx",
"driverBotToken": "xoxb-...",
"sutBotToken": "xoxb-...",
"sutAppToken": "xapp-..."
}
Con OPENCLAW_QA_CONVEX_SITE_URL y OPENCLAW_QA_CONVEX_SECRET_MAINTAINER exportados en tu shell, registra y verifica:
pnpm openclaw qa credentials add \
--kind slack \
--payload-file slack-creds.json \
--note "QA Slack pool seed"
pnpm openclaw qa credentials list --kind slack --status all --json
Espera count: 1, status: "active", sin campo lease.
5. Verifica de extremo a extremo
Ejecuta la vía localmente para confirmar que ambos bots puedan hablar entre sí a través del broker:
pnpm openclaw qa slack \
--credential-source convex \
--credential-role maintainer \
--output-dir .artifacts/qa-e2e/slack-local
Una ejecución verde se completa en bastante menos de 30 segundos y slack-qa-report.md muestra tanto slack-canary como slack-mention-gating con estado pass. Si la vía se queda colgada durante unos 90 segundos y sale con Convex credential pool exhausted for kind "slack", o el pool está vacío o todas las filas están arrendadas: qa credentials list --kind slack --status all --json te indicará cuál caso es.
Pool de credenciales de Convex
Las vías de Telegram, Discord y Slack pueden arrendar credenciales de un pool compartido de Convex en lugar de leer las variables de entorno anteriores. Pasa --credential-source convex (o define OPENCLAW_QA_CREDENTIAL_SOURCE=convex); QA Lab adquiere un arrendamiento exclusivo, le envía Heartbeat durante la ejecución y lo libera al apagarse. Los tipos de pool son "telegram", "discord" y "slack".
Formas de payload que el broker valida en admin/add:
- Telegram (
kind: "telegram"):{ groupId: string, driverToken: string, sutToken: string }-groupIddebe ser una cadena numérica de id de chat. - Discord (
kind: "discord"):{ guildId: string, channelId: string, driverBotToken: string, sutBotToken: string, sutApplicationId: string }. - Slack (
kind: "slack"):{ channelId: string, driverBotToken: string, sutBotToken: string, sutAppToken: string }-channelIddebe coincidir con^[A-Z][A-Z0-9]+$(un id de Slack comoCxxxxxxxxxx). Consulta Configurar el espacio de trabajo de Slack para el aprovisionamiento de apps y ámbitos.
Las variables de entorno operativas y el contrato del endpoint del broker de Convex están en Pruebas → Credenciales compartidas de Telegram mediante Convex (el nombre de la sección es anterior al soporte de Discord; la semántica del broker es idéntica para ambos tipos).
Semillas respaldadas por el repo
Los recursos semilla están en qa/:
qa/scenarios/index.mdqa/scenarios/<theme>/*.md
Estos están intencionadamente en git para que el plan de QA sea visible tanto para humanos como para el agente.
qa-lab debe seguir siendo un ejecutor genérico de markdown. Cada archivo markdown de escenario es la fuente de verdad de una ejecución de prueba y debe definir:
- metadatos del escenario
- metadatos opcionales de categoría, capacidad, vía y riesgo
- referencias de documentación y código
- requisitos opcionales de Plugin
- parche opcional de configuración del Gateway
- el
qa-flowejecutable
La superficie de runtime reutilizable que respalda qa-flow puede seguir siendo genérica y transversal. Por ejemplo, los escenarios markdown pueden combinar helpers del lado de transporte con helpers del lado del navegador que controlan la Control UI embebida mediante la interfaz browser.request del Gateway sin añadir un ejecutor de caso especial.
Los archivos de escenario deben agruparse por capacidad de producto en lugar de por carpeta del árbol de código fuente. Mantén estables los IDs de escenario cuando se muevan archivos; usa docsRefs y codeRefs para la trazabilidad de implementación.
La lista base debe seguir siendo lo bastante amplia para cubrir:
- chat por DM y canal
- comportamiento de hilos
- ciclo de vida de acciones de mensaje
- callbacks de Cron
- recuperación de memoria
- cambio de modelo
- traspaso a subagente
- lectura de repos y lectura de documentación
- una pequeña tarea de compilación, como Lobster Invaders
Vías simuladas de proveedor
qa suite tiene dos vías locales simuladas de proveedor:
mock-openaies el simulador de OpenClaw consciente de escenarios. Sigue siendo la vía simulada determinista predeterminada para QA respaldado por el repo y puertas de paridad.aimockinicia un servidor de proveedor respaldado por AIMock para cobertura experimental de protocolo, fixtures, grabación/reproducción y caos. Es aditivo y no reemplaza el despachador de escenariosmock-openai.
La implementación de vías de proveedor está en extensions/qa-lab/src/providers/. Cada proveedor posee sus valores predeterminados, arranque de servidor local, configuración de modelo de Gateway, necesidades de preparación de perfiles de autenticación y flags de capacidad en vivo/simulada. El código compartido del conjunto y del Gateway debe enrutar mediante el registro de proveedores en lugar de ramificar por nombres de proveedor.
Adaptadores de transporte
qa-lab es propietario de una costura de transporte genérica para escenarios de QA en markdown. qa-channel es el primer adaptador sobre esa costura, pero el objetivo de diseño es más amplio: los canales reales o sintéticos futuros deberían conectarse al mismo runner de suites en lugar de añadir un runner de QA específico del transporte.
En el nivel de arquitectura, la división es:
qa-labes propietario de la ejecución genérica de escenarios, la concurrencia de workers, la escritura de artefactos y los informes.- El adaptador de transporte es propietario de la configuración del Gateway, la preparación, la observación de entrada y salida, las acciones de transporte y el estado de transporte normalizado.
- Los archivos de escenarios en markdown bajo
qa/scenarios/definen la ejecución de prueba;qa-labproporciona la superficie de runtime reutilizable que los ejecuta.
Añadir un canal
Añadir un canal al sistema de QA en markdown requiere exactamente dos cosas:
- Un adaptador de transporte para el canal.
- Un paquete de escenarios que ejercite el contrato del canal.
No añadas una nueva raíz de comando de QA de nivel superior cuando el host compartido qa-lab puede ser propietario del flujo.
qa-lab es propietario de la mecánica compartida del host:
- la raíz de comando
openclaw qa - inicio y cierre de suites
- concurrencia de workers
- escritura de artefactos
- generación de informes
- ejecución de escenarios
- alias de compatibilidad para escenarios antiguos de
qa-channel
Los plugins de runner son propietarios del contrato de transporte:
- cómo se monta
openclaw qa <runner>debajo de la raíz compartidaqa - cómo se configura el Gateway para ese transporte
- cómo se comprueba la preparación
- cómo se inyectan los eventos entrantes
- cómo se observan los mensajes salientes
- cómo se exponen las transcripciones y el estado de transporte normalizado
- cómo se ejecutan las acciones respaldadas por transporte
- cómo se gestiona el restablecimiento o la limpieza específicos del transporte
El nivel mínimo de adopción para un canal nuevo:
- Mantén
qa-labcomo propietario de la raíz compartidaqa. - Implementa el runner de transporte sobre la costura del host compartido
qa-lab. - Mantén la mecánica específica del transporte dentro del plugin de runner o del arnés del canal.
- Monta el runner como
openclaw qa <runner>en lugar de registrar un comando raíz competidor. Los plugins de runner deben declararqaRunnersenopenclaw.plugin.jsony exportar un arrayqaRunnerCliRegistrationscoincidente desderuntime-api.ts. Manténruntime-api.tsligero; la CLI diferida y la ejecución del runner deben permanecer detrás de entrypoints separados. - Crea o adapta escenarios en markdown bajo los directorios temáticos
qa/scenarios/. - Usa los helpers genéricos de escenarios para escenarios nuevos.
- Mantén funcionando los alias de compatibilidad existentes salvo que el repo esté haciendo una migración intencional.
La regla de decisión es estricta:
- Si el comportamiento puede expresarse una vez en
qa-lab, ponlo enqa-lab. - Si el comportamiento depende de un transporte de canal, mantenlo en ese plugin de runner o arnés del plugin.
- Si un escenario necesita una capacidad que más de un canal puede usar, añade un helper genérico en lugar de una rama específica del canal en
suite.ts. - Si un comportamiento solo tiene sentido para un transporte, mantén el escenario específico del transporte y hazlo explícito en el contrato del escenario.
Nombres de helpers de escenarios
Helpers genéricos preferidos para escenarios nuevos:
waitForTransportReadywaitForChannelReadyinjectInboundMessageinjectOutboundMessagewaitForTransportOutboundMessagewaitForChannelOutboundMessagewaitForNoTransportOutboundgetTransportSnapshotreadTransportMessagereadTransportTranscriptformatTransportTranscriptresetTransport
Los alias de compatibilidad siguen disponibles para escenarios existentes: waitForQaChannelReady, waitForOutboundMessage, waitForNoOutbound, formatConversationTranscript, resetBus; pero la creación de escenarios nuevos debería usar los nombres genéricos. Los alias existen para evitar una migración de día señalado, no como el modelo a futuro.
Informes
qa-lab exporta un informe de protocolo en Markdown a partir de la línea temporal del bus observada.
El informe debe responder:
- Qué funcionó
- Qué falló
- Qué siguió bloqueado
- Qué escenarios de seguimiento vale la pena añadir
Para el inventario de escenarios disponibles, útil al dimensionar trabajo de seguimiento o cablear un transporte nuevo, ejecuta pnpm openclaw qa coverage (añade --json para salida legible por máquinas).
Para comprobaciones de carácter y estilo, ejecuta el mismo escenario con varias refs de modelos en vivo y escribe un informe en Markdown evaluado:
pnpm openclaw qa character-eval \
--model openai/gpt-5.5,thinking=medium,fast \
--model openai/gpt-5.2,thinking=xhigh \
--model openai/gpt-5,thinking=xhigh \
--model anthropic/claude-opus-4-6,thinking=high \
--model anthropic/claude-sonnet-4-6,thinking=high \
--model zai/glm-5.1,thinking=high \
--model moonshot/kimi-k2.5,thinking=high \
--model google/gemini-3.1-pro-preview,thinking=high \
--judge-model openai/gpt-5.5,thinking=xhigh,fast \
--judge-model anthropic/claude-opus-4-6,thinking=high \
--blind-judge-models \
--concurrency 16 \
--judge-concurrency 16
El comando ejecuta procesos secundarios locales del Gateway de QA, no Docker. Los escenarios de evaluación de carácter deben establecer la persona mediante SOUL.md y luego ejecutar turnos de usuario ordinarios, como chat, ayuda de workspace y tareas pequeñas de archivos. No se debe decir al modelo candidato que está siendo evaluado. El comando preserva cada transcripción completa, registra estadísticas básicas de ejecución y luego pide a los modelos jueces en modo rápido con razonamiento xhigh, donde se admita, que clasifiquen las ejecuciones por naturalidad, tono y humor.
Usa --blind-judge-models al comparar proveedores: el prompt del juez sigue recibiendo cada transcripción y estado de ejecución, pero las refs candidatas se sustituyen por etiquetas neutrales como candidate-01; el informe asigna de nuevo las clasificaciones a las refs reales después del análisis.
Las ejecuciones candidatas usan por defecto razonamiento high, con medium para GPT-5.5 y xhigh para refs de evaluación antiguas de OpenAI que lo admiten. Sobrescribe un candidato específico inline con --model provider/model,thinking=<level>. --thinking <level> sigue definiendo un fallback global, y la forma anterior --model-thinking <provider/model=level> se conserva por compatibilidad.
Las refs candidatas de OpenAI usan por defecto el modo rápido para que se use el procesamiento prioritario donde el proveedor lo admita. Añade ,fast, ,no-fast o ,fast=false inline cuando un único candidato o juez necesite una sobrescritura. Pasa --fast solo cuando quieras forzar el modo rápido para todos los modelos candidatos. Las duraciones de candidatos y jueces se registran en el informe para análisis de benchmark, pero los prompts de juez dicen explícitamente que no clasifiquen por velocidad.
Las ejecuciones de modelos candidatos y jueces usan ambas concurrencia 16 por defecto. Baja --concurrency o --judge-concurrency cuando los límites del proveedor o la presión del Gateway local hagan que una ejecución sea demasiado ruidosa.
Cuando no se pasa ningún --model candidato, la evaluación de carácter usa por defecto 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 y google/gemini-3.1-pro-preview cuando no se pasa ningún --model.
Cuando no se pasa ningún --judge-model, los jueces usan por defecto openai/gpt-5.5,thinking=xhigh,fast y anthropic/claude-opus-4-6,thinking=high.