qa-channel is a repo-local synthetic message transport for automated Apus QA (extensions/qa-channel, private package, excluded from packaged installs). It is not a production channel - it exists to exercise the same channel plugin boundary used by real transports while keeping state deterministic and fully inspectable.

What it does

The outbound tool trace records sanitized tool starts, including Code Mode wrappers and nested calls. It does not establish successful completion. QA Lab derives logical tool activity from correlated transcript calls and results, retaining call identities and wrapper lineage. Repeated executions with distinct identities remain separate; a Code Mode wrapper does not add another success for its nested tool, and a nonzero shell exit is not a successful execution. Task followthrough checks use this activity to prove serial reads and writes before the terminal reply, alongside the artifact's modification time. Scenarios that check the Code Mode control protocol explicitly include control activity in their transcript summaries.

Config

{
  "channels": {
    "qa-channel": {
      "baseUrl": "http://127.0.0.1:43123",
      "botUserId": "apus",
      "botDisplayName": "Apus QA",
      "allowFrom": ["*"],
      "pollTimeoutMs": 1000
    }
  }
}

Account keys:

Multi-account keys at the top level:

Runners

Host-side self-check (writes a Markdown report under .artifacts/qa-e2e/):

pnpm qa:e2e

This routes through qa-lab, starts the in-repo QA bus, boots the qa-channel runtime slice, and runs a deterministic self-check.

Full repo-backed scenario suite:

pnpm apus qa suite

The isolated channel-participant-identity-inspection scenario enables execution identity before startup, exercises DM, group, senderless, same- and mixed-participant collect paths, proves an ingress rejection creates no audit rows, and compares JSON plus human CLI inspection across Gateway restart:

pnpm apus qa suite --scenario channel-participant-identity-inspection

Runs scenarios in parallel against the QA gateway lane. See QA overview for scenarios, profiles, and provider modes.

Docker-backed QA site (gateway + QA Lab debugger UI in one stack):

pnpm qa:lab:up

Builds the QA site, starts the Docker-backed gateway + QA Lab stack, and prints the QA Lab URL. From there you can pick scenarios, choose the model lane, launch individual runs, and watch results live. The QA Lab debugger is separate from the shipped Control UI bundle.

Installed-candidate fixtures

Private QA plugins remain excluded from the public Apus package. To exercise an installed candidate, build their Gateway-only artifacts in a separate fixture workspace. The fixture profile keeps QA Lab's Gateway hooks, tools and providers, but leaves its scenario runner and CLI in the tooling checkout. QA Channel carries its pure bus protocol implementation; public SDK imports still belong to the installed candidate.

From a complete, dependency-ready tooling checkout at the committed revision being tested:

fixture_root="$(mktemp -d)"
git archive HEAD extensions/qa-lab extensions/qa-channel | tar -x -C "$fixture_root"
mkdir "$fixture_root/artifacts"

for plugin in qa-lab qa-channel; do
  node scripts/lib/plugin-npm-runtime-build.mjs \
    "$fixture_root/extensions/$plugin" --qa-gateway-fixture
  APUS_PLUGIN_NPM_BUNDLE_DEPENDENCIES=1 \
    node scripts/lib/plugin-npm-package-manifest.mjs \
    --run "$fixture_root/extensions/$plugin" --qa-gateway-fixture -- \
    npm pack --pack-destination "$fixture_root/artifacts"
done

The builder writes only the copied packages' dist directories. The manifest owner restores their source metadata after packing and includes the canonical QA Channel config schema. Dependency bundling is required for this portable fixture recipe: the profile alone does not install or bundle typebox and zod. Do not copy checkout node_modules links or overwrite another run's generated plugin output.

Use the existing runQaSuite API with the tooling checkout as repoRoot and an explicit sutApusCommand pointing to the installed candidate's runtime and dist/index.js, with usePackagedPlugins: true. Extract the reviewed artifacts into an isolated fixture directory and add those package paths through the API's mutateConfig callback to plugins.load.paths, preserving the other config fields. That callback runs for each fresh child before the candidate performs its own auth bootstrap and update repair. Local origin and capability-consent rules still apply; fixtures do not acquire official package trust.

Keep the installed package unchanged. Do not set APUS_DEV_SOURCE_ROOT or replace its bundled plugin/SDK roots with the tooling checkout. Record both revisions and verify fixture peer/API requirements and emitted host imports against the installed candidate, not just the tooling version. Required proof includes actual candidate Gateway/CLI images, candidate-owned SDK resolution, the unchanged scenario results and complete child cleanup. A source QA pass alone does not establish installed-package compatibility.

Related