Fundamentals
نمای کلی تضمین کیفیت
پشتهٔ QA خصوصی برای آن است که OpenClaw را به روشی واقعیتر و شبیهتر به کانال نسبت به یک آزمون واحد اجرا کند.
اجزای فعلی:
extensions/qa-channel: کانال پیام مصنوعی با سطوح DM، کانال، رشته، واکنش، ویرایش، و حذف.extensions/qa-lab: رابط کاربری اشکالزدا و گذرگاه QA برای مشاهدهٔ رونوشت، تزریق پیامهای ورودی، و برونبری گزارش Markdown.extensions/qa-matrix، Pluginهای اجراگر آینده: آداپتورهای انتقال زنده که یک کانال واقعی را داخل یک Gateway فرزند QA هدایت میکنند.qa/: داراییهای seed مبتنی بر repo برای وظیفهٔ آغازین و سناریوهای پایهٔ QA.- Mantis: راستیآزمایی زندهٔ پیش و پس از اشکالهایی که به انتقالهای واقعی، نماگرفتهای مرورگر، وضعیت VM، و شواهد PR نیاز دارند.
سطح فرمان
هر جریان QA زیر pnpm openclaw qa <subcommand> اجرا میشود. بسیاری از آنها
نامهای مستعار اسکریپتی pnpm qa:* دارند؛ هر دو شکل پشتیبانی میشوند.
| فرمان | هدف |
|---|---|
qa run |
خودآزمایی QA بستهشده؛ یک گزارش Markdown مینویسد. |
qa suite |
سناریوهای مبتنی بر repo را در برابر مسیر Gateway مربوط به QA اجرا میکند. نامهای مستعار: pnpm openclaw qa suite --runner multipass برای یک VM لینوکسی موقتی. |
qa coverage |
فهرست پوشش سناریو به صورت markdown را چاپ میکند (--json برای خروجی ماشینی). |
qa parity-report |
دو فایل qa-suite-summary.json را مقایسه میکند و گزارش برابری agentic را مینویسد. |
qa character-eval |
سناریوی QA شخصیت را روی چند مدل زنده با یک گزارش داوریشده اجرا میکند. گزارشدهی را ببینید. |
qa manual |
یک پرامپت یکباره را در برابر مسیر ارائهدهنده/مدل انتخابشده اجرا میکند. |
qa ui |
رابط کاربری اشکالزدای QA و گذرگاه QA محلی را شروع میکند (نام مستعار: pnpm qa:lab:ui). |
qa docker-build-image |
تصویر Docker ازپیشساختهٔ QA را میسازد. |
qa docker-scaffold |
یک داربست docker-compose برای داشبورد QA + مسیر Gateway مینویسد. |
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 |
مسیر انتقال زنده در برابر یک homeserver موقتی Tuwunel. Matrix QA را ببینید. |
qa telegram |
مسیر انتقال زنده در برابر یک گروه خصوصی واقعی Telegram. |
qa discord |
مسیر انتقال زنده در برابر یک کانال guild خصوصی واقعی Discord. |
qa slack |
مسیر انتقال زنده در برابر یک کانال خصوصی واقعی Slack. |
qa mantis |
اجراگر راستیآزمایی پیش و پس از اشکالهای انتقال زنده، با شواهد واکنشهای وضعیت Discord، smoke دسکتاپ/مرورگر Crabbox، و smoke مربوط به Slack در VNC. Mantis و راهنمای اجرای دسکتاپ Slack در Mantis را ببینید. |
جریان اپراتور
جریان فعلی اپراتور QA یک سایت QA دوپنجرهای است:
- چپ: داشبورد Gateway (Control UI) همراه با عامل.
- راست: QA Lab، که رونوشت شبیه Slack و برنامهٔ سناریو را نشان میدهد.
آن را با این دستور اجرا کنید:
pnpm qa:lab:up
این کار سایت QA را میسازد، مسیر Gateway مبتنی بر Docker را شروع میکند، و صفحهٔ QA Lab را در دسترس میگذارد؛ جایی که اپراتور یا حلقهٔ خودکارسازی میتواند به عامل یک مأموریت QA بدهد، رفتار واقعی کانال را مشاهده کند، و ثبت کند چه چیزی کار کرد، شکست خورد، یا همچنان مسدود ماند.
برای تکرار سریعتر روی رابط کاربری QA Lab بدون بازسازی تصویر Docker در هر بار، پشته را با یک بستهٔ QA Lab که به صورت bind mount متصل شده شروع کنید:
pnpm openclaw qa docker-build-image
pnpm qa:lab:build
pnpm qa:lab:up:fast
pnpm qa:lab:watch
qa:lab:up:fast سرویسهای Docker را روی یک تصویر ازپیشساخته نگه میدارد و
extensions/qa-lab/web/dist را داخل کانتینر qa-lab به صورت bind-mount متصل
میکند. qa:lab:watch آن بسته را هنگام تغییر دوباره میسازد، و مرورگر وقتی hash
دارایی QA Lab تغییر کند، خودکار بارگذاری مجدد میشود.
برای یک smoke محلی ردگیری OpenTelemetry، اجرا کنید:
pnpm qa:otel:smoke
این اسکریپت یک دریافتکنندهٔ ردگیری OTLP/HTTP محلی را شروع میکند، سناریوی QA
otel-trace-smoke را با Plugin فعال diagnostics-otel اجرا میکند، سپس spanهای
protobuf برونبریشده را رمزگشایی میکند و شکل حیاتی برای انتشار را assert میکند:
openclaw.run، openclaw.harness.run، openclaw.model.call،
openclaw.context.assembled، و openclaw.message.delivery باید حاضر باشند؛
فراخوانیهای مدل نباید در گردشهای موفق StreamAbandoned را برونبری کنند؛ شناسههای خام تشخیصی و
ویژگیهای openclaw.content.* باید بیرون از ردگیری بمانند. این اسکریپت
otel-smoke-summary.json را کنار artifactهای مجموعهٔ QA مینویسد.
QA مشاهدهپذیری فقط برای checkout کد منبع است. tarball مربوط به npm عمداً
QA Lab را حذف میکند، بنابراین مسیرهای انتشار Docker بسته دستورهای qa را اجرا
نمیکنند. هنگام تغییر instrumention تشخیصی، از یک checkout ساختهشدهٔ منبع
pnpm qa:otel:smoke را اجرا کنید.
برای یک مسیر smoke واقعی از نظر انتقال برای Matrix، اجرا کنید:
pnpm openclaw qa matrix --profile fast --fail-fast
مرجع کامل CLI، کاتالوگ profile/سناریو، env varها، و چیدمان artifact برای این مسیر در Matrix QA قرار دارد. خلاصه: این مسیر یک homeserver موقتی Tuwunel را در Docker آماده میکند، کاربرهای موقت driver/SUT/observer را ثبت میکند، Plugin واقعی Matrix را داخل یک Gateway فرزند QA محدود به همان انتقال اجرا میکند (بدون qa-channel)، سپس یک گزارش Markdown، خلاصهٔ JSON، artifact رویدادهای مشاهدهشده، و لاگ خروجی ترکیبی را زیر .artifacts/qa-e2e/matrix-<timestamp>/ مینویسد.
سناریوها رفتار انتقالی را پوشش میدهند که آزمونهای واحد نمیتوانند به صورت end to end اثبات کنند: mention gating، سیاستهای allow-bot، allowlistها، پاسخهای سطح بالا و رشتهای، مسیریابی DM، مدیریت واکنش، سرکوب ویرایش ورودی، dedupe بازپخش پس از راهاندازی مجدد، بازیابی از وقفهٔ homeserver، تحویل فرادادهٔ تأیید، مدیریت رسانه، و جریانهای bootstrap/recovery/verification مربوط به Matrix E2EE. profile مربوط به E2EE در CLI همچنین openclaw matrix encryption setup و دستورهای verification را از طریق همان homeserver موقتی پیش از بررسی پاسخهای Gateway اجرا میکند.
Discord همچنین سناریوهای opt-in فقط مخصوص Mantis برای بازتولید اشکال دارد. از
--scenario discord-status-reactions-tool-only برای timeline صریح واکنش وضعیت
استفاده کنید، یا از --scenario discord-thread-reply-filepath-attachment برای
ساخت یک رشتهٔ واقعی Discord و راستیآزمایی اینکه message.thread-reply یک
پیوست filePath را حفظ میکند. این سناریوها بیرون از مسیر پیشفرض زندهٔ Discord
میمانند، چون probeهای بازتولید پیش/پس هستند نه پوشش smoke گسترده.
گردش کار Mantis مربوط به پیوست رشته میتواند وقتی
MANTIS_DISCORD_VIEWER_CHROME_PROFILE_DIR یا
MANTIS_DISCORD_VIEWER_CHROME_PROFILE_TGZ_B64 در محیط QA پیکربندی شده باشد، یک
ویدیوی شاهد Discord Web با نشست واردشده نیز اضافه کند. آن profile بیننده فقط
برای ضبط بصری است؛ تصمیم pass/fail همچنان از oracle مربوط به Discord REST میآید.
CI از همان سطح فرمان در .github/workflows/qa-live-transports-convex.yml استفاده میکند. اجراهای زمانبندیشده و دستی پیشفرض، profile سریع Matrix را با اعتبارنامههای frontier زنده، --fast، و OPENCLAW_QA_MATRIX_NO_REPLY_WINDOW_MS=3000 اجرا میکنند. اجرای دستی matrix_profile=all به پنج shard مربوط به profileها منشعب میشود تا کاتالوگ جامع بتواند بهصورت موازی اجرا شود و در عین حال برای هر shard یک دایرکتوری artifact جدا نگه دارد.
برای مسیرهای smoke واقعی از نظر انتقال برای Telegram، Discord، و Slack:
pnpm openclaw qa telegram
pnpm openclaw qa discord
pnpm openclaw qa slack
آنها یک کانال واقعی از پیش موجود را با دو bot هدف میگیرند (driver + SUT). env varهای لازم، فهرست سناریوها، artifactهای خروجی، و مجموعهٔ اعتبارنامهٔ Convex در مرجع QA برای Telegram، Discord، و Slack در ادامه مستند شدهاند.
برای اجرای کامل VM دسکتاپ Slack با نجات VNC، اجرا کنید:
pnpm openclaw qa mantis slack-desktop-smoke \
--gateway-setup \
--scenario slack-canary \
--keep-lease
این دستور یک ماشین دسکتاپ/مرورگر Crabbox اجاره میکند، مسیر زنده Slack را داخل VM اجرا میکند، Slack Web را در مرورگر VNC باز میکند، از دسکتاپ تصویر میگیرد و وقتی ضبط ویدئو در دسترس باشد slack-qa/، slack-desktop-smoke.png و slack-desktop-smoke.mp4 را به دایرکتوری artifact مربوط به Mantis برمیگرداند. اجارههای دسکتاپ/مرورگر Crabbox ابزارهای capture و بستههای کمکی مرورگر/native-build را از قبل فراهم میکنند، بنابراین سناریو فقط باید روی اجارههای قدیمیتر fallbackها را نصب کند. Mantis زمانبندیهای کلی و هر فاز را در mantis-slack-desktop-smoke-report.md گزارش میکند تا اجراهای کند نشان دهند زمان صرف warmup اجاره، دریافت اعتبارنامه، راهاندازی remote یا کپی artifact شده است. پس از ورود دستی به Slack Web از طریق VNC، از --lease-id <cbx_...> دوباره استفاده کنید؛ اجارههای استفادهشده دوباره cache فروشگاه pnpm مربوط به Crabbox را هم گرم نگه میدارند. مقدار پیشفرض --hydrate-mode source از checkout سورس صحتسنجی میکند و install/build را داخل VM اجرا میکند. فقط وقتی از --hydrate-mode prehydrated استفاده کنید که workspace remote استفادهشده دوباره از قبل node_modules و dist/ ساختهشده داشته باشد؛ آن حالت مرحله پرهزینه install/build را رد میکند و وقتی workspace آماده نباشد بهصورت بسته fail میشود. با --gateway-setup، Mantis یک OpenClaw Slack gateway پایدار را داخل VM روی پورت 38973 در حال اجرا باقی میگذارد؛ بدون آن، دستور مسیر معمول QA Slack باتبهبات را اجرا میکند و پس از capture artifact خارج میشود.
چکلیست اپراتور، دستور dispatch گردشکار GitHub، قرارداد evidence-comment، جدول تصمیم hydrate-mode، تفسیر زمانبندی و گامهای مدیریت شکست در Runbook دسکتاپ Mantis Slack قرار دارند.
برای یک وظیفه دسکتاپ به سبک عامل/CV، اجرا کنید:
pnpm openclaw qa mantis visual-task \
--browser-url https://example.net \
--expect-text "Example Domain" \
--vision-model openai/gpt-5.4
visual-task یک ماشین دسکتاپ/مرورگر Crabbox را اجاره میکند یا دوباره استفاده میکند، crabbox record --while را شروع میکند، مرورگر قابلمشاهده را از طریق یک visual-driver تو در تو هدایت میکند، visual-task.png را capture میکند، وقتی --vision-mode image-describe انتخاب شده باشد openclaw infer image describe را روی screenshot اجرا میکند و visual-task.mp4، mantis-visual-task-summary.json، mantis-visual-task-driver-result.json و mantis-visual-task-report.md را مینویسد. وقتی --expect-text تنظیم شده باشد، prompt بینایی یک verdict ساختیافته JSON درخواست میکند و فقط وقتی pass میشود که مدل شواهد قابلمشاهده مثبت گزارش کند؛ پاسخ منفی که صرفا متن هدف را نقلقول کند assertion را fail میکند. برای یک smoke بدون مدل که دسکتاپ، مرورگر، screenshot و لولهکشی ویدئو را بدون فراخوانی provider فهم تصویر اثبات میکند، از --vision-mode metadata استفاده کنید. Recording یک artifact الزامی برای visual-task است؛ اگر Crabbox هیچ visual-task.mp4 غیرخالیای ضبط نکند، حتی اگر visual driver pass شده باشد، وظیفه fail میشود. هنگام شکست، Mantis اجاره را برای VNC نگه میدارد مگر اینکه وظیفه قبلا pass شده باشد و --keep-lease تنظیم نشده باشد.
پیش از استفاده از اعتبارنامههای زنده pooled، اجرا کنید:
pnpm openclaw qa credentials doctor
doctor محیط broker مربوط به Convex را بررسی میکند، تنظیمات endpoint را اعتبارسنجی میکند و وقتی secret نگهدارنده حاضر باشد دسترسی admin/list را صحتسنجی میکند. برای secretها فقط وضعیت تنظیمشده/مفقود را گزارش میکند.
پوشش transport زنده
مسیرهای transport زنده بهجای اینکه هرکدام شکل فهرست سناریوی خود را بسازند، یک قرارداد مشترک دارند. qa-channel مجموعه گسترده رفتار محصول synthetic است و بخشی از ماتریس پوشش transport زنده نیست.
| مسیر | Canary | gating اشاره | باتبهبات | مسدودسازی allowlist | پاسخ سطح بالا | ادامه پس از restart | پیگیری thread | جداسازی thread | مشاهده reaction | دستور help | ثبت دستور native |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 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 |
این کار qa-channel را بهعنوان مجموعه گسترده رفتار محصول نگه میدارد، در حالی که Matrix، Telegram و transportهای زنده آینده یک چکلیست صریح قرارداد transport مشترک دارند.
برای یک مسیر VM یکبارمصرف Linux بدون وارد کردن Docker به مسیر QA، اجرا کنید:
pnpm openclaw qa suite --runner multipass --scenario channel-chat-baseline
این دستور یک مهمان تازه Multipass بوت میکند، وابستگیها را نصب میکند، OpenClaw را داخل مهمان build میکند، qa suite را اجرا میکند، سپس گزارش و summary معمول QA را به .artifacts/qa-e2e/... روی host برمیگرداند.
این همان رفتار انتخاب سناریوی qa suite روی host را دوباره استفاده میکند.
اجراهای مجموعه روی host و Multipass بهطور پیشفرض چند سناریوی انتخابشده را بهصورت موازی با gateway workerهای جداشده اجرا میکنند. qa-channel بهطور پیشفرض concurrency 4 دارد که با تعداد سناریوهای انتخابشده محدود میشود. برای تنظیم تعداد workerها از --concurrency <count>، یا برای اجرای سریالی از --concurrency 1 استفاده کنید.
وقتی هر سناریویی fail شود، دستور با کد غیرصفر خارج میشود. وقتی artifactها را بدون exit code شکستخورده میخواهید، از --allow-failures استفاده کنید.
اجراهای زنده ورودیهای auth پشتیبانیشده QA را که برای مهمان عملی هستند forward میکنند: کلیدهای provider مبتنی بر env، مسیر config provider زنده QA و CODEX_HOME وقتی حاضر باشد. --output-dir را زیر root مخزن نگه دارید تا مهمان بتواند از طریق workspace mountشده بنویسد.
مرجع QA برای Telegram، Discord و Slack
Matrix بهدلیل تعداد سناریوها و آمادهسازی homeserver مبتنی بر Docker یک صفحه اختصاصی دارد. Telegram، Discord و Slack کوچکترند - هرکدام چند سناریو، بدون سیستم profile، در برابر کانالهای واقعی از پیش موجود - بنابراین مرجع آنها اینجا قرار دارد.
flagهای مشترک CLI
این مسیرها از طریق extensions/qa-lab/src/live-transports/shared/live-transport-cli.ts ثبت میشوند و flagهای یکسانی را میپذیرند:
| Flag | پیشفرض | توضیح |
|---|---|---|
--scenario <id> |
- | فقط این سناریو را اجرا کنید. قابل تکرار. |
--output-dir <path> |
<repo>/.artifacts/qa-e2e/{telegram,discord,slack}-<timestamp> |
محل نوشتن reports/summary/پیامهای مشاهدهشده و output log. مسیرهای نسبی نسبت به --repo-root resolve میشوند. |
--repo-root <path> |
process.cwd() |
root مخزن هنگام فراخوانی از یک cwd خنثی. |
--sut-account <id> |
sut |
شناسه موقت account داخل config مربوط به QA gateway. |
--provider-mode <mode> |
live-frontier |
mock-openai یا live-frontier؛ مقدار legacy live-openai هنوز کار میکند. |
--model <ref> / --alt-model <ref> |
پیشفرض provider | refهای مدل اصلی/جایگزین. |
--fast |
خاموش | حالت سریع provider در موارد پشتیبانیشده. |
--credential-source <env|convex> |
env |
pool اعتبارنامه Convex را ببینید. |
--credential-role <maintainer|ci> |
ci در CI، در غیر این صورت maintainer |
نقشی که هنگام --credential-source convex استفاده میشود. |
هر مسیر در صورت شکست هر سناریو با کد غیرصفر خارج میشود. --allow-failures artifactها را بدون تنظیم exit code شکستخورده مینویسد.
QA Telegram
pnpm openclaw qa telegram
یک گروه خصوصی واقعی Telegram را با دو بات متمایز هدف میگیرد: driver + SUT. بات SUT باید username در Telegram داشته باشد؛ مشاهده باتبهبات زمانی بهترین نتیجه را دارد که هر دو بات Bot-to-Bot Communication Mode را در @BotFather فعال کرده باشند.
envهای لازم هنگام --credential-source env:
OPENCLAW_QA_TELEGRAM_GROUP_ID- شناسه عددی chat (رشته).OPENCLAW_QA_TELEGRAM_DRIVER_BOT_TOKENOPENCLAW_QA_TELEGRAM_SUT_BOT_TOKEN
اختیاری:
OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT=1بدنه پیامها را در artifactهای observed-message نگه میدارد؛ پیشفرض redacts است.
سناریوها (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
artifactهای خروجی:
telegram-qa-report.mdtelegram-qa-summary.json- شامل RTT هر reply (ارسال driver → reply مشاهدهشده SUT) از canary به بعد.telegram-qa-observed-messages.json- بدنهها redacted هستند مگر اینکهOPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT=1باشد.
QA Discord
pnpm openclaw qa discord
یک کانال guild خصوصی واقعی Discord را با دو بات هدف میگیرد: یک بات driver که توسط harness کنترل میشود و یک بات SUT که توسط OpenClaw gateway فرزند از طریق Plugin bundled Discord شروع میشود. مدیریت اشاره کانال، اینکه بات SUT دستور native /help را در Discord ثبت کرده است، و سناریوهای opt-in شواهد Mantis را صحتسنجی میکند.
envهای لازم هنگام --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- باید با user id بات SUT که Discord برمیگرداند مطابقت داشته باشد؛ در غیر این صورت مسیر سریع fail میشود.
اختیاری:
OPENCLAW_QA_DISCORD_CAPTURE_CONTENT=1بدنه پیامها را در artifactهای observed-message نگه میدارد.OPENCLAW_QA_DISCORD_VOICE_CHANNEL_IDکانال voice/stage را برایdiscord-voice-autojoinانتخاب میکند؛ بدون آن، سناریو نخستین کانال voice/stage قابلمشاهده برای بات SUT را انتخاب میکند.
سناریوها (extensions/qa-lab/src/live-transports/discord/discord-live.runtime.ts:36):
discord-canarydiscord-mention-gatingdiscord-native-help-command-registrationdiscord-voice-autojoin- سناریوی صوتی اختیاری. بهتنهایی اجرا میشود،channels.discord.voice.autoJoinرا فعال میکند، و تأیید میکند که وضعیت صوتی فعلی بات SUT در Discord همان کانال صوتی/استیج هدف است. اعتبارنامههای Convex برای Discord میتوانند شاملvoiceChannelIdاختیاری باشند؛ در غیر این صورت اجراکننده نخستین کانال صوتی/استیج قابلمشاهده را در guild کشف میکند.discord-status-reactions-tool-only- سناریوی Mantis اختیاری. بهتنهایی اجرا میشود، زیرا SUT را به پاسخهای همیشهفعال و فقطابزاری guild باmessages.statusReactions.enabled=trueتغییر میدهد، سپس یک خط زمانی واکنش REST بههمراه آرتیفکتهای بصری HTML/PNG ضبط میکند. گزارشهای قبل/بعد Mantis همچنین آرتیفکتهای MP4 ارائهشده توسط سناریو را بهترتیب بهصورتbaseline.mp4وcandidate.mp4حفظ میکنند.
سناریوی پیوستن خودکار صوتی Discord را صراحتاً اجرا کنید:
pnpm openclaw qa discord \
--scenario discord-voice-autojoin \
--provider-mode mock-openai
سناریوی واکنش وضعیت 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
آرتیفکتهای خروجی:
discord-qa-report.mddiscord-qa-summary.jsondiscord-qa-observed-messages.json- بدنهها بازنویسی محرمانه میشوند مگر اینکهOPENCLAW_QA_DISCORD_CAPTURE_CONTENT=1باشد.discord-qa-reaction-timelines.jsonوdiscord-status-reactions-tool-only-timeline.pngهنگامی که سناریوی واکنش وضعیت اجرا شود.
QA برای Slack
pnpm openclaw qa slack
یک کانال خصوصی واقعی Slack را با دو بات متمایز هدف میگیرد: یک بات راهانداز که توسط سازوکار آزمون کنترل میشود و یک بات SUT که توسط Gateway فرزند OpenClaw از طریق Plugin بستهبندیشده Slack شروع میشود.
env لازم هنگام استفاده از --credential-source env:
OPENCLAW_QA_SLACK_CHANNEL_IDOPENCLAW_QA_SLACK_DRIVER_BOT_TOKENOPENCLAW_QA_SLACK_SUT_BOT_TOKENOPENCLAW_QA_SLACK_SUT_APP_TOKEN
اختیاری:
OPENCLAW_QA_SLACK_CAPTURE_CONTENT=1بدنه پیامها را در آرتیفکتهای پیام مشاهدهشده نگه میدارد.
سناریوها (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
آرتیفکتهای خروجی:
slack-qa-report.mdslack-qa-summary.jsonslack-qa-observed-messages.json- بدنهها بازنویسی محرمانه میشوند مگر اینکهOPENCLAW_QA_SLACK_CAPTURE_CONTENT=1باشد.
راهاندازی فضای کاری Slack
این lane به دو اپ Slack متمایز در یک فضای کاری، بهعلاوه کانالی که هر دو بات عضو آن باشند نیاز دارد:
channelId- شناسهCxxxxxxxxxxکانالی که هر دو بات به آن دعوت شدهاند. از یک کانال اختصاصی استفاده کنید؛ این lane در هر اجرا پیام ارسال میکند.driverBotToken- توکن بات (xoxb-...) اپ Driver.sutBotToken- توکن بات (xoxb-...) اپ SUT که باید اپ Slack جداگانهای از driver باشد تا شناسه کاربر بات آن متمایز باشد.sutAppToken- توکن سطح اپ (xapp-...) اپ SUT باconnections:writeکه توسط Socket Mode استفاده میشود تا اپ SUT بتواند رویدادها را دریافت کند.
یک فضای کاری Slack اختصاصی برای QA را به استفاده دوباره از فضای کاری تولید ترجیح دهید.
مانیفست SUT زیر عمداً نصب تولید Plugin بستهبندیشده Slack (extensions/slack/src/setup-shared.ts:10) را به مجوزها و رویدادهایی محدود میکند که مجموعه QA زنده Slack پوشش میدهد. برای راهاندازی کانال تولید همانطور که کاربران آن را میبینند، راهاندازی سریع کانال Slack را ببینید؛ جفت QA Driver/SUT عمداً جداست، زیرا این lane به دو شناسه کاربر بات متمایز در یک فضای کاری نیاز دارد.
1. اپ Driver را ایجاد کنید
به api.slack.com/apps بروید → Create New App → From a manifest → فضای کاری QA را انتخاب کنید، مانیفست زیر را جایگذاری کنید، سپس 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
}
}
Bot User OAuth Token (xoxb-...) را کپی کنید - این مقدار به driverBotToken تبدیل میشود. driver فقط باید پیام ارسال کند و خودش را شناسایی کند؛ بدون رویداد، بدون Socket Mode.
2. اپ SUT را ایجاد کنید
Create New App → From a manifest را در همان فضای کاری تکرار کنید. این اپ QA عمداً از نسخه محدودتری از مانیفست تولید Plugin بستهبندیشده Slack (extensions/slack/src/setup-shared.ts:10) استفاده میکند: scopeها و رویدادهای واکنش حذف شدهاند، زیرا مجموعه QA زنده Slack هنوز مدیریت واکنش را پوشش نمیدهد.
{
"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"
]
}
}
}
پس از اینکه Slack اپ را ایجاد کرد، در صفحه تنظیمات آن دو کار انجام دهید:
- Install to Workspace → Bot User OAuth Token را کپی کنید → این مقدار به
sutBotTokenتبدیل میشود. - Basic Information → App-Level Tokens → Generate Token and Scopes → scope
connections:writeرا اضافه کنید → ذخیره کنید → مقدارxapp-...را کپی کنید → این مقدار بهsutAppTokenتبدیل میشود.
با فراخوانی auth.test روی هر توکن تأیید کنید که دو بات شناسه کاربری متمایز دارند. runtime بین driver و SUT براساس شناسه کاربر تمایز میگذارد؛ استفاده دوباره از یک اپ برای هر دو، mention-gating را فوراً با شکست مواجه میکند.
3. کانال را ایجاد کنید
در فضای کاری QA، یک کانال ایجاد کنید (برای مثال #openclaw-qa) و هر دو بات را از داخل کانال دعوت کنید:
/invite @OpenClaw QA Driver
/invite @OpenClaw QA SUT
شناسه Cxxxxxxxxxx را از channel info → About → Channel ID کپی کنید - این مقدار به channelId تبدیل میشود. کانال عمومی هم کار میکند؛ اگر از کانال خصوصی استفاده کنید، هر دو اپ از قبل groups:history دارند، بنابراین خواندن تاریخچه توسط سازوکار آزمون همچنان موفق خواهد بود.
4. اعتبارنامهها را ثبت کنید
دو گزینه وجود دارد. برای اشکالزدایی روی یک دستگاه از متغیرهای env استفاده کنید (چهار متغیر OPENCLAW_QA_SLACK_* را تنظیم کنید و --credential-source env را پاس دهید)، یا pool مشترک Convex را seed کنید تا CI و سایر maintainers بتوانند آنها را lease کنند.
برای pool Convex، چهار فیلد را در یک فایل JSON بنویسید:
{
"channelId": "Cxxxxxxxxxx",
"driverBotToken": "xoxb-...",
"sutBotToken": "xoxb-...",
"sutAppToken": "xapp-..."
}
در حالی که OPENCLAW_QA_CONVEX_SITE_URL و OPENCLAW_QA_CONVEX_SECRET_MAINTAINER در shell شما export شدهاند، ثبت و تأیید کنید:
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
انتظار count: 1، status: "active"، و نبود فیلد lease را داشته باشید.
5. انتها به انتها تأیید کنید
این lane را بهصورت محلی اجرا کنید تا تأیید شود هر دو بات میتوانند از طریق broker با یکدیگر گفتگو کنند:
pnpm openclaw qa slack \
--credential-source convex \
--credential-role maintainer \
--output-dir .artifacts/qa-e2e/slack-local
یک اجرای سبز در کمتر از ۳۰ ثانیه کامل میشود و slack-qa-report.md نشان میدهد که هر دو slack-canary و slack-mention-gating در وضعیت pass هستند. اگر lane حدود ۹۰ ثانیه معلق بماند و با Convex credential pool exhausted for kind "slack" خارج شود، یا pool خالی است یا همه ردیفها lease شدهاند - qa credentials list --kind slack --status all --json به شما میگوید کدام مورد است.
pool اعتبارنامه Convex
laneهای Telegram، Discord، و Slack میتوانند بهجای خواندن متغیرهای env بالا، اعتبارنامهها را از یک pool مشترک Convex lease کنند. --credential-source convex را پاس دهید (یا OPENCLAW_QA_CREDENTIAL_SOURCE=convex را تنظیم کنید)؛ QA Lab یک lease انحصاری میگیرد، در طول اجرا برای آن Heartbeat میفرستد، و هنگام خاموشی آن را آزاد میکند. انواع pool عبارتاند از "telegram"، "discord"، و "slack".
شکل payloadهایی که broker روی admin/add اعتبارسنجی میکند:
- Telegram (
kind: "telegram"):{ groupId: string, driverToken: string, sutToken: string }-groupIdباید یک رشته عددی chat-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]+$مطابقت داشته باشد (یک شناسه Slack مانندCxxxxxxxxxx). برای آمادهسازی اپ و scope، راهاندازی فضای کاری Slack را ببینید.
متغیرهای env عملیاتی و قرارداد endpoint مربوط به broker Convex در Testing → اعتبارنامههای مشترک Telegram از طریق Convex قرار دارند (نام این بخش به قبل از پشتیبانی Discord برمیگردد؛ معنای broker برای هر دو نوع یکسان است).
seedهای پشتیبانیشده با repo
داراییهای seed در qa/ قرار دارند:
qa/scenarios/index.mdqa/scenarios/<theme>/*.md
اینها عمداً در git هستند تا طرح QA هم برای انسانها و هم برای agent قابلمشاهده باشد.
qa-lab باید یک اجراکننده markdown عمومی باقی بماند. هر فایل markdown سناریو منبع حقیقت برای یک اجرای آزمون است و باید موارد زیر را تعریف کند:
- فراداده سناریو
- فراداده اختیاری category، capability، lane، و risk
- ارجاعهای docs و code
- نیازمندیهای اختیاری Plugin
- patch اختیاری پیکربندی Gateway
qa-flowاجرایی
سطح runtime قابلاستفاده مجدد که پشتوانه qa-flow است مجاز است عمومی و cross-cutting بماند. برای مثال، سناریوهای markdown میتوانند helperهای سمت transport را با helperهای سمت مرورگر ترکیب کنند که Control UI تعبیهشده را از طریق seam browser.request مربوط به Gateway هدایت میکنند، بدون اینکه اجراکننده special-case اضافه شود.
فایلهای سناریو باید براساس قابلیت محصول گروهبندی شوند، نه پوشه source tree. هنگام جابهجایی فایلها، شناسههای سناریو را پایدار نگه دارید؛ برای قابلیت ردگیری پیادهسازی از docsRefs و codeRefs استفاده کنید.
فهرست baseline باید به اندازه کافی گسترده بماند تا موارد زیر را پوشش دهد:
- گفتگوی DM و کانال
- رفتار thread
- چرخه عمر action پیام
- callbackهای cron
- بازیابی memory
- تغییر model
- تحویل به subagent
- خواندن repo و خواندن docs
- یک وظیفه کوچک build مانند Lobster Invaders
laneهای mock provider
qa suite دو lane محلی mock provider دارد:
mock-openaiهمان mock سناریوآگاه OpenClaw است. این lane همچنان lane mock قطعی پیشفرض برای QA پشتیبانیشده با repo و gateهای parity باقی میماند.aimockیک provider server مبتنی بر AIMock را برای پوشش آزمایشی protocol، fixture، record/replay، و chaos شروع میکند. این افزایشی است و جایگزین dispatcher سناریویmock-openaiنمیشود.
پیادهسازی provider-lane زیر extensions/qa-lab/src/providers/ قرار دارد. هر provider مالک defaults، شروع server محلی، پیکربندی model در Gateway، نیازهای آمادهسازی auth-profile، و پرچمهای قابلیت live/mock خودش است. کد مشترک suite و Gateway باید بهجای branching روی نام providerها، از طریق registry مربوط به provider مسیریابی کند.
آداپتورهای transport
qa-lab مالک یک درز انتقال عمومی برای سناریوهای QA در Markdown است. qa-channel نخستین آداپتر روی آن درز است، اما هدف طراحی گستردهتر است: کانالهای واقعی یا مصنوعی آینده باید به همان اجراکننده مجموعه متصل شوند، نه اینکه یک اجراکننده QA مخصوص انتقال اضافه کنند.
در سطح معماری، این تفکیک چنین است:
qa-labمالک اجرای سناریوی عمومی، همزمانی worker، نوشتن artifact، و گزارشدهی است.- آداپتر انتقال مالک پیکربندی Gateway، آمادگی، مشاهده ورودی و خروجی، کنشهای انتقال، و وضعیت انتقال نرمالسازیشده است.
- فایلهای سناریوی Markdown زیر
qa/scenarios/اجرای آزمون را تعریف میکنند؛qa-labسطح runtime قابل استفاده مجدد را فراهم میکند که آنها را اجرا میکند.
افزودن یک کانال
افزودن یک کانال به سامانه QA مبتنی بر Markdown دقیقاً به دو چیز نیاز دارد:
- یک آداپتر انتقال برای کانال.
- یک بسته سناریو که قرارداد کانال را تمرین کند.
وقتی میزبان مشترک qa-lab میتواند مالک جریان باشد، یک ریشه دستور QA سطحبالای جدید اضافه نکنید.
qa-lab مالک سازوکارهای میزبان مشترک است:
- ریشه دستور
openclaw qa - راهاندازی و teardown مجموعه
- همزمانی worker
- نوشتن artifact
- تولید گزارش
- اجرای سناریو
- aliasهای سازگاری برای سناریوهای قدیمیتر
qa-channel
Pluginهای اجراکننده مالک قرارداد انتقال هستند:
- اینکه
openclaw qa <runner>چگونه زیر ریشه مشترکqamount میشود - اینکه Gateway برای آن انتقال چگونه پیکربندی میشود
- اینکه آمادگی چگونه بررسی میشود
- اینکه رویدادهای ورودی چگونه inject میشوند
- اینکه پیامهای خروجی چگونه مشاهده میشوند
- اینکه رونوشتها و وضعیت انتقال نرمالسازیشده چگونه در دسترس قرار میگیرند
- اینکه کنشهای مبتنی بر انتقال چگونه اجرا میشوند
- اینکه reset یا پاکسازی مخصوص انتقال چگونه انجام میشود
حداقل سطح پذیرش برای یک کانال جدید:
qa-labرا بهعنوان مالک ریشه مشترکqaنگه دارید.- اجراکننده انتقال را روی درز میزبان مشترک
qa-labپیادهسازی کنید. - سازوکارهای مخصوص انتقال را داخل Plugin اجراکننده یا harness کانال نگه دارید.
- اجراکننده را بهصورت
openclaw qa <runner>mount کنید، بهجای ثبت یک دستور ریشه رقیب. Pluginهای اجراکننده بایدqaRunnersرا درopenclaw.plugin.jsonاعلام کنند و یک آرایه مطابقqaRunnerCliRegistrationsرا ازruntime-api.tsexport کنند.runtime-api.tsرا سبک نگه دارید؛ اجرای lazy CLI و اجراکننده باید پشت entrypointهای جداگانه بماند. - سناریوهای Markdown را زیر دایرکتوریهای تمدار
qa/scenarios/بنویسید یا تطبیق دهید. - برای سناریوهای جدید از helperهای سناریوی عمومی استفاده کنید.
- aliasهای سازگاری موجود را فعال نگه دارید، مگر اینکه repo در حال انجام یک مهاجرت عمدی باشد.
قاعده تصمیمگیری سختگیرانه است:
- اگر رفتاری را بتوان یکبار در
qa-labبیان کرد، آن را درqa-labبگذارید. - اگر رفتار به یک انتقال کانال وابسته است، آن را در Plugin اجراکننده یا harness Plugin نگه دارید.
- اگر یک سناریو به قابلیت جدیدی نیاز دارد که بیش از یک کانال میتواند از آن استفاده کند، بهجای شاخه مخصوص کانال در
suite.tsیک helper عمومی اضافه کنید. - اگر یک رفتار فقط برای یک انتقال معنا دارد، سناریو را مخصوص همان انتقال نگه دارید و این را در قرارداد سناریو صریح کنید.
نامهای helper سناریو
helperهای عمومی ترجیحی برای سناریوهای جدید:
waitForTransportReadywaitForChannelReadyinjectInboundMessageinjectOutboundMessagewaitForTransportOutboundMessagewaitForChannelOutboundMessagewaitForNoTransportOutboundgetTransportSnapshotreadTransportMessagereadTransportTranscriptformatTransportTranscriptresetTransport
aliasهای سازگاری برای سناریوهای موجود همچنان در دسترساند - waitForQaChannelReady، waitForOutboundMessage، waitForNoOutbound، formatConversationTranscript، resetBus - اما در نگارش سناریوهای جدید باید از نامهای عمومی استفاده شود. aliasها برای جلوگیری از یک مهاجرت یکباره وجود دارند، نه بهعنوان مدل آینده.
گزارشدهی
qa-lab یک گزارش پروتکل Markdown را از timeline مشاهدهشده bus صادر میکند.
گزارش باید به این پرسشها پاسخ دهد:
- چه چیزی کار کرد
- چه چیزی شکست خورد
- چه چیزی همچنان مسدود ماند
- افزودن کدام سناریوهای پیگیری ارزشمند است
برای فهرست سناریوهای موجود - که هنگام برآورد کارهای پیگیری یا اتصال یک انتقال جدید مفید است - pnpm openclaw qa coverage را اجرا کنید (برای خروجی قابل خواندن توسط ماشین --json را اضافه کنید).
برای بررسیهای شخصیت و سبک، همان سناریو را روی چندین ref مدل زنده اجرا کنید و یک گزارش Markdown داوریشده بنویسید:
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
این دستور child processهای Gateway محلی QA را اجرا میکند، نه Docker. سناریوهای ارزیابی شخصیت
باید persona را از طریق SOUL.md تنظیم کنند، سپس turnهای معمول کاربر
مانند chat، کمک در workspace، و taskهای کوچک فایل را اجرا کنند. به مدل candidate نباید
گفته شود که در حال ارزیابی است. دستور هر transcript کامل را حفظ میکند،
آمار پایه اجرا را ثبت میکند، سپس از مدلهای judge در fast mode با
reasoning سطح xhigh، در صورت پشتیبانی، میخواهد اجراها را بر اساس طبیعیبودن، vibe، و طنز رتبهبندی کنند.
هنگام مقایسه providerها از --blind-judge-models استفاده کنید: prompt داور همچنان
همه transcriptها و وضعیت اجرا را دریافت میکند، اما refهای candidate با labelهای خنثی
مانند candidate-01 جایگزین میشوند؛ گزارش پس از parsing رتبهبندیها را به refهای واقعی برمیگرداند.
اجرای candidateها بهطور پیشفرض از thinking سطح high استفاده میکند، با medium برای GPT-5.5 و xhigh
برای refهای ارزیابی قدیمیتر OpenAI که از آن پشتیبانی میکنند. یک candidate مشخص را inline با
--model provider/model,thinking=<level> override کنید. --thinking <level> همچنان یک
fallback سراسری تنظیم میکند، و شکل قدیمیتر --model-thinking <provider/model=level> برای
سازگاری نگه داشته شده است.
refهای candidate OpenAI بهطور پیشفرض از fast mode استفاده میکنند تا در جایی که
provider پشتیبانی میکند، priority processing استفاده شود. وقتی یک candidate یا judge
تکی به override نیاز دارد، ,fast، ,no-fast، یا ,fast=false را inline اضافه کنید. فقط وقتی --fast را پاس دهید که میخواهید
fast mode را برای همه مدلهای candidate اجباراً روشن کنید. مدتزمانهای candidate و judge برای
تحلیل benchmark در گزارش ثبت میشوند، اما promptهای judge صریحاً میگویند
بر اساس سرعت رتبهبندی نکنند.
اجرای مدلهای candidate و judge هر دو بهطور پیشفرض از همزمانی 16 استفاده میکنند. وقتی محدودیتهای
provider یا فشار Gateway محلی اجرای بیشازحد پرنویز ایجاد میکند، --concurrency یا --judge-concurrency را کاهش دهید.
وقتی هیچ candidate --model پاس داده نشود، character eval بهطور پیشفرض از
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 هستند.