diff --git a/.openclaw-sync/source.json b/.openclaw-sync/source.json index 8fcde122d..4a4c4c7e9 100644 --- a/.openclaw-sync/source.json +++ b/.openclaw-sync/source.json @@ -1,5 +1,5 @@ { "repository": "openclaw/openclaw", - "sha": "15b86ac6d05f0ae13dbc438d5013996db6246480", - "syncedAt": "2026-04-12T17:52:52.365Z" + "sha": "000fc7f233469b2d64223cc10e6fbce75bdb0748", + "syncedAt": "2026-04-12T18:03:38.674Z" } diff --git a/docs/concepts/qa-e2e-automation.md b/docs/concepts/qa-e2e-automation.md index fa2e022f9..faa72fa5c 100644 --- a/docs/concepts/qa-e2e-automation.md +++ b/docs/concepts/qa-e2e-automation.md @@ -132,6 +132,22 @@ agent. The baseline list should stay broad enough to cover: - repo-reading and docs-reading - one small build task such as Lobster Invaders +## Transport adapters + +`qa-lab` owns a generic transport seam for markdown QA scenarios. +`qa-channel` is the first adapter on that seam, but the design target is wider: +future real or synthetic channels should plug into the same suite runner +instead of adding a transport-specific QA runner. + +At the architecture level, the split is: + +- `qa-lab` owns scenario execution, worker concurrency, artifact writing, and reporting. +- the transport adapter owns gateway config, readiness, inbound and outbound observation, transport actions, and normalized transport state. +- scenarios stay markdown-first under `qa/scenarios/`. + +Maintainer-facing adoption guidance for new channel adapters lives in +[Testing](/help/testing#adding-a-channel-to-qa). + ## Reporting `qa-lab` exports a Markdown protocol report from the observed bus timeline. diff --git a/docs/help/testing.md b/docs/help/testing.md index 38f98bb20..37a4798d8 100644 --- a/docs/help/testing.md +++ b/docs/help/testing.md @@ -87,6 +87,78 @@ transport coverage matrix. | Matrix | x | x | x | x | x | x | x | x | | | Telegram | x | | | | | | | | x | +### Adding a channel to QA + +Adding a channel to the markdown QA system requires exactly two things: + +1. A transport adapter for the channel. +2. A scenario pack that exercises the channel contract. + +Do not add a channel-specific QA runner when the shared `qa-lab` runner can +own the flow. + +`qa-lab` owns the shared mechanics: + +- suite startup and teardown +- worker concurrency +- artifact writing +- report generation +- scenario execution +- compatibility aliases for older `qa-channel` scenarios + +The channel adapter owns the transport contract: + +- how the gateway is configured for that transport +- how readiness is checked +- how inbound events are injected +- how outbound messages are observed +- how transcripts and normalized transport state are exposed +- how transport-backed actions are executed +- how transport-specific reset or cleanup is handled + +The minimum adoption bar for a new channel is: + +1. Implement the transport adapter on the shared `qa-lab` seam. +2. Register the adapter in the transport registry. +3. Keep transport-specific mechanics inside the adapter or the channel harness. +4. Author or adapt markdown scenarios under `qa/scenarios/`. +5. Use the generic scenario helpers for new scenarios. +6. Keep existing compatibility aliases working unless the repo is doing an intentional migration. + +The decision rule is strict: + +- If behavior can be expressed once in `qa-lab`, put it in `qa-lab`. +- If behavior depends on one channel transport, keep it in that adapter or plugin harness. +- If a scenario needs a new capability that more than one channel can use, add a generic helper instead of a channel-specific branch in `suite.ts`. +- If a behavior is only meaningful for one transport, keep the scenario transport-specific and make that explicit in the scenario contract. + +Preferred generic helper names for new scenarios are: + +- `waitForTransportReady` +- `waitForChannelReady` +- `injectInboundMessage` +- `injectOutboundMessage` +- `waitForTransportOutboundMessage` +- `waitForChannelOutboundMessage` +- `waitForNoTransportOutbound` +- `getTransportSnapshot` +- `readTransportMessage` +- `readTransportTranscript` +- `formatTransportTranscript` +- `resetTransport` + +Compatibility aliases remain available for existing scenarios, including: + +- `waitForQaChannelReady` +- `waitForOutboundMessage` +- `waitForNoOutbound` +- `formatConversationTranscript` +- `resetBus` + +New channel work should use the generic helper names. +Compatibility aliases exist to avoid a flag day migration, not as the model for +new scenario authoring. + ## Test suites (what runs where) Think of the suites as “increasing realism” (and increasing flakiness/cost):