Compare commits

..

8 Commits

Author SHA1 Message Date
Dallin Romney
9f1112a576 ci: tighten maturity artifact inputs 2026-06-19 13:38:59 -07:00
Dallin Romney
5e932c9f18 ci: type maturity docs renderer 2026-06-19 13:38:59 -07:00
Dallin Romney
343bb68a99 ci: render qa scorecard evidence 2026-06-19 13:38:59 -07:00
Dallin Romney
1cbe7d98cc ci: add maturity scorecard renderer 2026-06-19 13:38:59 -07:00
Dallin Romney
a740724b87 ci: simplify release qa profile evidence 2026-06-19 13:38:52 -07:00
Dallin Romney
4df934a516 ci: add release qa profile evidence 2026-06-19 13:37:56 -07:00
Alix-007
3fa4fdaec1 docs: fix two broken cross-reference anchors (#93941)
Merged via squash.

Prepared head SHA: 32c61da44d
Co-authored-by: Alix-007 <267018309+Alix-007@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
Reviewed-by: @steipete
2026-06-19 20:27:25 +01:00
Vincent Koc
efc36d71bd refactor(qa-lab): drop unused report type aliases 2026-06-20 03:16:55 +08:00
20 changed files with 1638 additions and 233 deletions

124
.github/workflows/maturity-scorecard.yml vendored Normal file
View File

@@ -0,0 +1,124 @@
name: Maturity scorecard
on:
workflow_dispatch:
inputs:
source_run_id:
description: Optional workflow run id containing qa-evidence.json artifacts
required: false
type: string
artifact_pattern:
description: Artifact name pattern to download from source_run_id
required: false
default: "*qa*"
type: string
strict_inputs:
description: Fail when score or QA evidence inputs have non-fatal drift
required: false
default: false
type: boolean
push:
branches: [main]
paths:
- "taxonomy.yaml"
- "docs/maturity-scores.yaml"
- "docs/maturity-scorecard.md"
- "docs/taxonomy.md"
- "docs/taxonomy-outline.md"
- "scripts/render-maturity-docs.ts"
- "package.json"
- ".github/workflows/maturity-scorecard.yml"
pull_request:
paths:
- "taxonomy.yaml"
- "docs/maturity-scores.yaml"
- "docs/maturity-scorecard.md"
- "docs/taxonomy.md"
- "docs/taxonomy-outline.md"
- "scripts/render-maturity-docs.ts"
- "package.json"
- ".github/workflows/maturity-scorecard.yml"
permissions:
actions: read
contents: read
concurrency:
group: ${{ format('{0}-{1}', github.workflow, github.ref) }}
cancel-in-progress: true
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
NODE_VERSION: "24.x"
jobs:
render:
name: Render maturity docs
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
fetch-depth: 1
fetch-tags: false
persist-credentials: false
submodules: false
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
node-version: ${{ env.NODE_VERSION }}
install-bun: "false"
- name: Check committed maturity docs
run: pnpm maturity:check
- name: Download QA evidence artifacts
if: ${{ github.event_name == 'workflow_dispatch' && inputs.source_run_id != '' }}
env:
GH_TOKEN: ${{ github.token }}
SOURCE_RUN_ID: ${{ inputs.source_run_id }}
ARTIFACT_PATTERN: ${{ inputs.artifact_pattern }}
run: |
set -euo pipefail
mkdir -p .artifacts/maturity-evidence
gh run download "$SOURCE_RUN_ID" \
--repo "$GITHUB_REPOSITORY" \
--pattern "$ARTIFACT_PATTERN" \
--dir .artifacts/maturity-evidence
find .artifacts/maturity-evidence -name qa-evidence.json -print
- name: Render artifact docs
env:
STRICT_INPUTS: ${{ github.event_name == 'workflow_dispatch' && inputs.strict_inputs }}
run: |
set -euo pipefail
args=(--output-dir .artifacts/maturity-docs --static-assets-dir .artifacts/maturity-docs/assets/maturity)
if [[ "$STRICT_INPUTS" == "true" ]]; then
args+=(--strict-inputs)
fi
if find .artifacts/maturity-evidence -name qa-evidence.json -print -quit 2>/dev/null | grep -q .; then
args+=(--evidence-dir .artifacts/maturity-evidence)
fi
pnpm maturity:render -- "${args[@]}"
{
echo "### Maturity scorecard docs"
echo
echo "- Committed docs check: passed"
echo "- Artifact docs: \`.artifacts/maturity-docs\`"
echo "- Strict inputs: \`${STRICT_INPUTS:-false}\`"
if find .artifacts/maturity-evidence -name qa-evidence.json -print -quit 2>/dev/null | grep -q .; then
echo "- QA evidence: included"
else
echo "- QA evidence: none downloaded"
fi
} >> "$GITHUB_STEP_SUMMARY"
- name: Upload maturity docs artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: maturity-scorecard-docs-${{ github.run_id }}-${{ github.run_attempt }}
path: .artifacts/maturity-docs/
retention-days: 30
if-no-files-found: error

View File

@@ -768,6 +768,122 @@ jobs:
OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
qa_profile_release_evidence_release_checks:
name: Generate QA profile release evidence
needs: [resolve_target]
if: contains(fromJSON('["all","qa"]'), needs.resolve_target.outputs.rerun_group)
continue-on-error: true
runs-on: blacksmith-8vcpu-ubuntu-2404
timeout-minutes: 60
permissions:
contents: read
environment: qa-live-shared
env:
OPENCLAW_BUILD_PRIVATE_QA: "1"
OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1"
OPENCLAW_QA_TRANSPORT_READY_TIMEOUT_MS: "180000"
OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
steps:
- name: Checkout selected ref
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
persist-credentials: true
ref: ${{ needs.resolve_target.outputs.revision }}
fetch-depth: 1
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
node-version: ${{ env.NODE_VERSION }}
install-bun: "true"
- name: Validate required QA credential env
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
shell: bash
run: |
set -euo pipefail
if [[ -z "${OPENAI_API_KEY:-}" ]]; then
echo "Missing required OPENAI_API_KEY." >&2
exit 1
fi
- name: Build private QA runtime
env:
NODE_OPTIONS: --max-old-space-size=8192
run: node scripts/build-all.mjs qaRuntime
- name: Run release QA profile
id: run_profile
shell: bash
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
set -euo pipefail
output_dir=".artifacts/qa-e2e/release-profile-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
echo "output_dir=${output_dir}" >> "$GITHUB_OUTPUT"
pnpm openclaw qa run \
--repo-root . \
--qa-profile release \
--output-dir "${output_dir}"
- name: Upload release QA profile evidence
id: upload_profile_evidence
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: release-qa-profile-release-${{ needs.resolve_target.outputs.revision }}
path: ${{ steps.run_profile.outputs.output_dir || '.artifacts/qa-e2e/' }}
retention-days: 30
if-no-files-found: warn
- name: Record advisory status
if: always()
shell: bash
env:
RELEASE_CHECK_JOB: qa_profile_release_evidence_release_checks
JOB_STATUS: ${{ job.status }}
RELEASE_CHECK_STEP_OUTCOMES: ${{ steps.run_profile.outcome }} ${{ steps.upload_profile_evidence.outcome }}
run: |
set -euo pipefail
status="success"
mark_status() {
case "$1" in
failure) status="failure" ;;
cancelled)
if [[ "$status" != "failure" ]]; then
status="cancelled"
fi
;;
success|skipped|"") ;;
*) status="failure" ;;
esac
}
mark_status "${JOB_STATUS:-}"
for outcome in ${RELEASE_CHECK_STEP_OUTCOMES:-}; do
mark_status "$outcome"
done
mkdir -p .artifacts/release-check-status
status_path=".artifacts/release-check-status/${RELEASE_CHECK_JOB}.env"
{
printf 'job=%s\n' "$RELEASE_CHECK_JOB"
printf 'status=%s\n' "$status"
printf 'job_status=%s\n' "${JOB_STATUS:-}"
printf 'step_outcomes=%s\n' "${RELEASE_CHECK_STEP_OUTCOMES:-}"
} > "$status_path"
- name: Upload advisory status
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: release-check-status-qa-profile-release-${{ needs.resolve_target.outputs.revision }}
path: .artifacts/release-check-status/qa_profile_release_evidence_release_checks.env
retention-days: 14
if-no-files-found: error
qa_lab_parity_lane_release_checks:
name: Run QA Lab parity lane (${{ matrix.lane }})
needs: [resolve_target]
@@ -1947,6 +2063,7 @@ jobs:
- docker_e2e_release_checks
- package_acceptance_release_checks
- qa_lab_parity_lane_release_checks
- qa_profile_release_evidence_release_checks
- qa_lab_parity_report_release_checks
- qa_lab_runtime_parity_release_checks
- runtime_tool_coverage_release_checks
@@ -2016,7 +2133,7 @@ jobs:
}
advisory_status_override_allowed() {
case "$1" in
qa_lab_parity_lane_release_checks|qa_lab_parity_report_release_checks|qa_lab_runtime_parity_release_checks|qa_live_matrix_release_checks|qa_live_telegram_release_checks|qa_live_discord_release_checks|qa_live_whatsapp_release_checks|qa_live_slack_release_checks)
qa_lab_parity_lane_release_checks|qa_profile_release_evidence_release_checks|qa_lab_parity_report_release_checks|qa_lab_runtime_parity_release_checks|qa_live_matrix_release_checks|qa_live_telegram_release_checks|qa_live_discord_release_checks|qa_live_whatsapp_release_checks|qa_live_slack_release_checks)
return 0
;;
*)
@@ -2032,6 +2149,7 @@ jobs:
"docker_e2e_release_checks=${{ needs.docker_e2e_release_checks.result }}" \
"package_acceptance_release_checks=${{ needs.package_acceptance_release_checks.result }}" \
"qa_lab_parity_lane_release_checks=${{ needs.qa_lab_parity_lane_release_checks.result }}" \
"qa_profile_release_evidence_release_checks=${{ needs.qa_profile_release_evidence_release_checks.result }}" \
"qa_lab_parity_report_release_checks=${{ needs.qa_lab_parity_report_release_checks.result }}" \
"qa_lab_runtime_parity_release_checks=${{ needs.qa_lab_runtime_parity_release_checks.result }}" \
"runtime_tool_coverage_release_checks=${{ needs.runtime_tool_coverage_release_checks.result }}" \

View File

@@ -37,7 +37,7 @@ that agent; if you copy credentials manually, copy only portable static
`api_key` or `token` profiles.
</Warning>
Skills are loaded from each agent workspace plus shared roots such as `~/.openclaw/skills`, then filtered by the effective agent skill allowlist when configured. Use `agents.defaults.skills` for a shared baseline and `agents.list[].skills` for per-agent replacement. See [Skills: per-agent vs shared](/tools/skills#per-agent-vs-shared-skills) and [Skills: agent skill allowlists](/tools/skills#agent-skill-allowlists).
Skills are loaded from each agent workspace plus shared roots such as `~/.openclaw/skills`, then filtered by the effective agent skill allowlist when configured. Use `agents.defaults.skills` for a shared baseline and `agents.list[].skills` for per-agent replacement. See [Skills: per-agent vs shared](/tools/skills#per-agent-vs-shared-skills) and [Skills: agent skill allowlists](/tools/skills#agent-allowlists).
The Gateway can host **one agent** (default) or **many agents** side-by-side.

View File

@@ -160,7 +160,7 @@ it disabled for read-only shared skill roots.
Related:
- [Skills config](/tools/skills-config#symlinked-sibling-repos)
- [Skills config](/tools/skills-config#symlinked-skill-roots)
- [Configuration examples](/gateway/configuration-examples#symlinked-sibling-skill-repo)
## Anthropic 429 extra usage required for long context

View File

@@ -98,16 +98,6 @@ export type HarnessParityResult = {
firstDriftTurn?: number;
};
export type HarnessParityReport = {
generatedAt: string;
providerMode: string;
left: HarnessVariant;
right: HarnessVariant;
results: HarnessParityResult[];
pass: boolean;
failures: string[];
};
function sha256(value: string) {
return createHash("sha256").update(value).digest("hex");
}

View File

@@ -23,8 +23,6 @@ export type QaRuntimeCapabilityLayer =
| "optional-profile-or-plugin"
| "structural-text";
export type QaCodexToolLoading = "direct" | "searchable";
export type RuntimeParityComparisonMode = "default" | "codex-native-workspace" | "outcome-only";
export type QaRuntimeToolCoverageMetadata = {

View File

@@ -50,19 +50,22 @@ describe("qa scenario catalog", () => {
expect(
scenarioIds.filter((scenarioId) => requiredScenarioIds.includes(scenarioId)).toSorted(),
).toEqual(requiredScenarioIds);
const nativeExecutionScenarios = pack.scenarios.filter(
(scenario) => scenario.execution.kind !== "flow",
expect(
pack.scenarios
.filter((scenario) => scenario.execution?.kind !== "flow")
.map((scenario) => scenario.id)
.toSorted(),
).toStrictEqual(
[
"channel-message-flows",
"control-ui-chat-flow-playwright",
"gateway-smoke",
"package-openclaw-for-docker",
"plugin-lifecycle-probe",
"qa-otel-smoke",
"ux-matrix-evidence-dashboard",
].toSorted(),
);
expect(nativeExecutionScenarios.length).toBeGreaterThan(0);
for (const scenario of nativeExecutionScenarios) {
const execution = scenario.execution;
if (execution.kind === "flow") {
throw new Error(`expected native execution scenario: ${scenario.id}`);
}
expect(["playwright", "script", "vitest"]).toContain(execution.kind);
expect(fs.existsSync(execution.path), `${scenario.id} execution.path exists`).toBe(true);
expect(execution.flow).toBeUndefined();
}
expect(
pack.scenarios
.filter((scenario) => scenario.execution.kind === "flow")
@@ -173,21 +176,6 @@ describe("qa scenario catalog", () => {
expect(uxMatrix.coverage?.primary).toContain("qa.artifact-safety");
});
it("loads folded HTTP API script scenarios with primary taxonomy coverage", () => {
expect(readQaScenarioById("openai-compatible-chat-tools").coverage?.primary).toStrictEqual([
"gateway.openai-compatible-apis",
]);
expect(readQaScenarioById("openai-web-search-minimal").coverage?.primary).toStrictEqual([
"runtime.reasoning-and-cache-controls",
]);
expect(
readQaScenarioById("openai-web-search-native-assertions").coverage?.primary,
).toStrictEqual(["web-search.openai-native-web-search", "plugins.web-search-and-fetch"]);
expect(readQaScenarioById("openwebui-openai-compatible").coverage?.primary).toStrictEqual([
"gateway.openai-compatible-apis",
]);
});
it("loads runtime parity tier metadata for first-hour and soak lanes", () => {
const firstHour = readQaScenarioById("runtime-first-hour-20-turn");
const soak = readQaScenarioById("runtime-soak-100-turn");

View File

@@ -1573,6 +1573,8 @@
"docs:list": "node scripts/docs-list.js",
"docs:spellcheck": "bash scripts/docs-spellcheck.sh",
"docs:spellcheck:fix": "bash scripts/docs-spellcheck.sh --write",
"maturity:check": "node --import tsx scripts/render-maturity-docs.ts --check",
"maturity:render": "node --import tsx scripts/render-maturity-docs.ts",
"dup:check": "node scripts/check-duplicates.mjs",
"dup:check:coverage": "node scripts/check-duplicates.mjs --coverage",
"dup:check:json": "node scripts/check-duplicates.mjs --json",

View File

@@ -1,29 +0,0 @@
title: OpenAI-compatible chat tools HTTP API
scenario:
id: openai-compatible-chat-tools
surface: runtime
coverage:
primary:
- gateway.openai-compatible-apis
secondary:
- runtime.hosted-tool-use
objective: Verify the OpenAI-compatible chat-completions client and Docker lane preserve strict tool-call API behavior.
successCriteria:
- The Docker lane fails missing or placeholder OpenAI auth before Docker build work starts.
- The generated config preserves strict positive gateway port and timeout values.
- The chat-completions client posts to `/v1/chat/completions` with the expected gateway token and model header.
- Tool-call-only responses are accepted, visible content beside a tool call is rejected, and response bodies remain bounded.
docsRefs:
- docs/gateway/protocol.md
- docs/help/testing.md
- docs/concepts/qa-e2e-automation.md
codeRefs:
- scripts/e2e/lib/openai-chat-tools/client.mjs
- scripts/e2e/lib/openai-chat-tools/write-config.mjs
- scripts/e2e/openai-chat-tools-docker.sh
- test/e2e/qa-lab/runtime/openai-compatible-chat-tools.e2e.test.ts
execution:
kind: vitest
path: test/e2e/qa-lab/runtime/openai-compatible-chat-tools.e2e.test.ts
summary: Vitest coverage for OpenAI-compatible chat-completions tool-call API behavior.

View File

@@ -1,29 +0,0 @@
title: OpenAI web_search minimal reasoning gate
scenario:
id: openai-web-search-minimal
surface: model-provider
coverage:
primary:
- runtime.reasoning-and-cache-controls
secondary:
- web-search.openai-native-web-search
- tools.web-search
objective: Verify the OpenAI web_search minimal-reasoning E2E client distinguishes successful grounded turns from provider schema rejection.
successCriteria:
- Reject mode accepts the expected raw OpenAI schema rejection and the gateway schema wrapper.
- Reject mode fails if the agent run unexpectedly succeeds or fails for unrelated transport reasons.
- Success mode requires an `ok` agent result with the expected marker in visible reply payloads.
- Gateway ports are parsed strictly before connecting.
docsRefs:
- docs/tools/web.md
- docs/help/testing.md
- docs/concepts/qa-e2e-automation.md
codeRefs:
- scripts/e2e/lib/openai-web-search-minimal/client.mjs
- scripts/e2e/openai-web-search-minimal-docker.sh
- test/e2e/qa-lab/runtime/openai-web-search-minimal.e2e.test.ts
execution:
kind: vitest
path: test/e2e/qa-lab/runtime/openai-web-search-minimal.e2e.test.ts
summary: Vitest coverage for OpenAI web_search minimal-reasoning success and rejection validation.

View File

@@ -1,30 +0,0 @@
title: OpenAI native web_search request assertions
scenario:
id: openai-web-search-native-assertions
surface: model-provider
coverage:
primary:
- web-search.openai-native-web-search
- plugins.web-search-and-fetch
secondary:
- web-search.model-and-filter-routing
- tools.web-search
objective: Verify the OpenAI web_search Docker lane assertions require native Responses web_search evidence with bounded diagnostics.
successCriteria:
- A successful request must hit `/v1/responses` with native `web_search` and non-minimal reasoning.
- Large request logs are scanned without missing later success requests.
- Failure diagnostics are bounded and do not dump stale or oversized request bodies.
- Function-shaped `web_search` is rejected as native Responses proof.
docsRefs:
- docs/tools/web.md
- docs/help/testing.md
- docs/concepts/qa-e2e-automation.md
codeRefs:
- scripts/e2e/lib/openai-web-search-minimal/assertions.mjs
- scripts/e2e/lib/openai-web-search-minimal/mock-server.mjs
- test/e2e/qa-lab/runtime/openai-web-search-minimal-assertions.e2e.test.ts
execution:
kind: vitest
path: test/e2e/qa-lab/runtime/openai-web-search-minimal-assertions.e2e.test.ts
summary: Vitest coverage for native OpenAI web_search request-log assertions.

View File

@@ -1,28 +0,0 @@
title: OpenWebUI OpenAI-compatible API probe
scenario:
id: openwebui-openai-compatible
surface: runtime
coverage:
primary:
- gateway.openai-compatible-apis
secondary:
- runtime.hosted-provider-turns
- runtime.provider-specific-model-options
objective: Verify the OpenWebUI E2E probe exercises OpenClaw through OpenWebUI's OpenAI-compatible model and chat APIs.
successCriteria:
- Probe environment limits are parsed strictly and control-plane requests time out quickly.
- Sign-in and model-list error bodies are bounded before diagnostics are emitted.
- Models mode authenticates and finds the OpenClaw model exposed by OpenWebUI.
- Chat mode posts to `/api/chat/completions`, validates the expected nonce, and fails when the reply omits it.
docsRefs:
- docs/help/testing.md
- docs/concepts/qa-e2e-automation.md
codeRefs:
- scripts/e2e/openwebui-probe.mjs
- scripts/e2e/openwebui-docker.sh
- test/e2e/qa-lab/runtime/openwebui-probe.e2e.test.ts
execution:
kind: vitest
path: test/e2e/qa-lab/runtime/openwebui-probe.e2e.test.ts
summary: Vitest coverage for OpenWebUI model and chat-completions probe behavior.

File diff suppressed because it is too large Load Diff

View File

@@ -1067,70 +1067,28 @@ const TOOLING_SOURCE_TEST_TARGETS = new Map([
"src/image-generation/openai-compatible-image-provider.test.ts",
],
],
[
"scripts/e2e/lib/openai-chat-tools/client.mjs",
["test/e2e/qa-lab/runtime/openai-compatible-chat-tools.e2e.test.ts"],
],
[
"scripts/e2e/lib/openai-chat-tools/scenario.sh",
["test/e2e/qa-lab/runtime/openai-compatible-chat-tools.e2e.test.ts"],
],
[
"scripts/e2e/lib/openai-chat-tools/write-config.mjs",
["test/e2e/qa-lab/runtime/openai-compatible-chat-tools.e2e.test.ts"],
],
[
"scripts/e2e/openai-chat-tools-docker.sh",
[
"test/e2e/qa-lab/runtime/openai-compatible-chat-tools.e2e.test.ts",
"test/scripts/docker-e2e-plan.test.ts",
],
],
[
"scripts/e2e/lib/openai-web-search-minimal/assertions.mjs",
["test/e2e/qa-lab/runtime/openai-web-search-minimal-assertions.e2e.test.ts"],
],
[
"scripts/e2e/lib/openai-web-search-minimal/client.mjs",
["test/e2e/qa-lab/runtime/openai-web-search-minimal.e2e.test.ts"],
],
[
"scripts/e2e/lib/openai-web-search-minimal/mock-server.mjs",
[
"test/e2e/qa-lab/runtime/openai-web-search-minimal.e2e.test.ts",
"test/e2e/qa-lab/runtime/openai-web-search-minimal-assertions.e2e.test.ts",
],
],
[
"scripts/e2e/lib/openai-web-search-minimal/scenario.sh",
[
"test/e2e/qa-lab/runtime/openai-web-search-minimal.e2e.test.ts",
"test/e2e/qa-lab/runtime/openai-web-search-minimal-assertions.e2e.test.ts",
],
["test/scripts/openai-chat-tools-client.test.ts", "test/scripts/docker-e2e-plan.test.ts"],
],
[
"scripts/e2e/openai-web-search-minimal-docker.sh",
[
"test/scripts/docker-build-helper.test.ts",
"test/scripts/docker-e2e-plan.test.ts",
"test/e2e/qa-lab/runtime/openai-web-search-minimal.e2e.test.ts",
"test/e2e/qa-lab/runtime/openai-web-search-minimal-assertions.e2e.test.ts",
"test/scripts/openai-web-search-minimal-client.test.ts",
"test/scripts/openai-web-search-minimal-assertions.test.ts",
],
],
[
"scripts/e2e/lib/openwebui/http-probe.mjs",
["test/e2e/qa-lab/runtime/openwebui-probe.e2e.test.ts"],
],
[
"scripts/e2e/openwebui-docker.sh",
[
"test/scripts/docker-build-helper.test.ts",
"test/scripts/docker-e2e-plan.test.ts",
"test/e2e/qa-lab/runtime/openwebui-probe.e2e.test.ts",
"test/scripts/openwebui-probe.test.ts",
"test/scripts/fixture-config.test.ts",
],
],
["scripts/e2e/openwebui-probe.mjs", ["test/e2e/qa-lab/runtime/openwebui-probe.e2e.test.ts"]],
[
"scripts/e2e/plugin-binding-command-escape-docker.sh",
[

View File

@@ -885,6 +885,7 @@ describe("test-projects args", () => {
"test/scripts/ios-team-id.test.ts",
"test/scripts/ios-version.test.ts",
"test/scripts/kitchen-sink-rpc-walk.test.ts",
"test/scripts/openai-chat-tools-client.test.ts",
"test/scripts/report-test-temp-creations.test.ts",
"test/scripts/test-projects.test.ts",
"test/test-env.test.ts",
@@ -911,7 +912,6 @@ describe("test-projects args", () => {
config: "test/vitest/vitest.e2e.config.ts",
forwardedArgs: [
"test/e2e/qa-lab/plugins/plugin-lifecycle-probe.e2e.test.ts",
"test/e2e/qa-lab/runtime/openai-compatible-chat-tools.e2e.test.ts",
"test/openclaw-launcher.e2e.test.ts",
],
includePatterns: null,

View File

@@ -1,12 +1,12 @@
// OpenAI-compatible chat tools tests cover QA Lab HTTP tool-call evidence.
// Openai Chat Tools Client tests cover openai chat tools client script behavior.
import { spawn, spawnSync } from "node:child_process";
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { createServer, type Server } from "node:http";
import { tmpdir } from "node:os";
import path from "node:path";
import { beforeAll, describe, expect, it } from "vitest";
import { createBoundedChildOutput } from "../../../helpers/bounded-child-output.js";
import { cleanupTempDirs, makeTempDir } from "../../../helpers/temp-dir.js";
import { createBoundedChildOutput } from "../helpers/bounded-child-output.js";
import { cleanupTempDirs, makeTempDir } from "../helpers/temp-dir.js";
const clientPath = path.resolve("scripts/e2e/lib/openai-chat-tools/client.mjs");
const dockerRunnerPath = path.resolve("scripts/e2e/openai-chat-tools-docker.sh");
@@ -14,6 +14,7 @@ const writeConfigPath = path.resolve("scripts/e2e/lib/openai-chat-tools/write-co
interface ClientResult {
error?: Error;
signal: NodeJS.Signals | null;
status: number | null;
stderr: string;
stdout: string;
@@ -68,12 +69,13 @@ function runClient(
}, timeout);
child.on("error", (error) => {
clearTimeout(timer);
resolve({ error, status: null, stderr: stderr.text(), stdout: stdout.text() });
resolve({ error, signal: null, status: null, stderr: stderr.text(), stdout: stdout.text() });
});
child.on("exit", (status) => {
child.on("exit", (status, signal) => {
clearTimeout(timer);
resolve({
error: timedOut ? new Error(`client timed out after ${timeout}ms`) : undefined,
signal,
status,
stderr: stderr.text(),
stdout: stdout.text(),

View File

@@ -1,4 +1,4 @@
// OpenAI web-search minimal assertion tests cover QA Lab native web_search evidence.
// Openai Web Search Minimal Assertions tests cover openai web search minimal assertions script behavior.
import { spawnSync } from "node:child_process";
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";

View File

@@ -1,6 +1,6 @@
// OpenAI web-search minimal tests cover QA Lab hosted provider schema evidence.
// Openai Web Search Minimal Client tests cover openai web search minimal client script behavior.
import { describe, expect, it } from "vitest";
import { testing } from "../../../../scripts/e2e/lib/openai-web-search-minimal/client.mjs";
import { testing } from "../../scripts/e2e/lib/openai-web-search-minimal/client.mjs";
describe("scripts/e2e/lib/openai-web-search-minimal/client.mjs", () => {
it("accepts only the expected raw schema rejection in reject mode", () => {

View File

@@ -1,16 +1,17 @@
// OpenWebUI probe tests cover QA Lab OpenAI-compatible API evidence.
// Openwebui Probe tests cover openwebui probe script behavior.
import { spawn } from "node:child_process";
import { readFileSync } from "node:fs";
import { createServer, type IncomingMessage, type Server as HttpServer } from "node:http";
import { createServer as createTcpServer, type Server as TcpServer, type Socket } from "node:net";
import path from "node:path";
import { describe, expect, it } from "vitest";
import { createBoundedChildOutput } from "../../../helpers/bounded-child-output.js";
import { createBoundedChildOutput } from "../helpers/bounded-child-output.js";
const probePath = path.resolve("scripts/e2e/openwebui-probe.mjs");
interface ProbeResult {
error?: Error;
signal: NodeJS.Signals | null;
status: number | null;
stderr: string;
stdout: string;
@@ -66,12 +67,13 @@ function runProbe(baseUrl: string, env: Record<string, string> = {}, timeout = 3
}, timeout);
child.on("error", (error) => {
clearTimeout(timer);
resolve({ error, status: null, stderr: stderr.text(), stdout: stdout.text() });
resolve({ error, signal: null, status: null, stderr: stderr.text(), stdout: stdout.text() });
});
child.on("exit", (status) => {
child.on("exit", (status, signal) => {
clearTimeout(timer);
resolve({
error: timedOut ? new Error(`probe timed out after ${timeout}ms`) : undefined,
signal,
status,
stderr: stderr.text(),
stdout: stdout.text(),

View File

@@ -294,7 +294,7 @@ describe("scripts/test-projects changed-target routing", () => {
it("routes nested scripts through conventional owner tests", () => {
expect(resolveChangedTestTargetPlan(["scripts/e2e/openwebui-probe.mjs"])).toEqual({
mode: "targets",
targets: ["test/e2e/qa-lab/runtime/openwebui-probe.e2e.test.ts"],
targets: ["test/scripts/openwebui-probe.test.ts"],
});
expect(resolveChangedTestTargetPlan(["scripts/lib/docker-e2e-plan.mjs"])).toEqual({
mode: "targets",
@@ -374,24 +374,21 @@ describe("scripts/test-projects changed-target routing", () => {
],
[
"scripts/e2e/lib/openai-chat-tools/write-config.mjs",
["test/e2e/qa-lab/runtime/openai-compatible-chat-tools.e2e.test.ts"],
["test/scripts/openai-chat-tools-client.test.ts"],
],
[
"scripts/e2e/lib/openai-chat-tools/scenario.sh",
["test/e2e/qa-lab/runtime/openai-compatible-chat-tools.e2e.test.ts"],
["test/scripts/openai-chat-tools-client.test.ts"],
],
[
"scripts/e2e/openai-chat-tools-docker.sh",
[
"test/e2e/qa-lab/runtime/openai-compatible-chat-tools.e2e.test.ts",
"test/scripts/docker-e2e-plan.test.ts",
],
["test/scripts/openai-chat-tools-client.test.ts", "test/scripts/docker-e2e-plan.test.ts"],
],
[
"scripts/e2e/lib/openai-web-search-minimal/mock-server.mjs",
[
"test/e2e/qa-lab/runtime/openai-web-search-minimal.e2e.test.ts",
"test/e2e/qa-lab/runtime/openai-web-search-minimal-assertions.e2e.test.ts",
"test/scripts/openai-web-search-minimal-client.test.ts",
"test/scripts/openai-web-search-minimal-assertions.test.ts",
],
],
[
@@ -399,8 +396,8 @@ describe("scripts/test-projects changed-target routing", () => {
[
"test/scripts/docker-build-helper.test.ts",
"test/scripts/docker-e2e-plan.test.ts",
"test/e2e/qa-lab/runtime/openai-web-search-minimal.e2e.test.ts",
"test/e2e/qa-lab/runtime/openai-web-search-minimal-assertions.e2e.test.ts",
"test/scripts/openai-web-search-minimal-client.test.ts",
"test/scripts/openai-web-search-minimal-assertions.test.ts",
],
],
[
@@ -408,14 +405,11 @@ describe("scripts/test-projects changed-target routing", () => {
[
"test/scripts/docker-build-helper.test.ts",
"test/scripts/docker-e2e-plan.test.ts",
"test/e2e/qa-lab/runtime/openwebui-probe.e2e.test.ts",
"test/scripts/openwebui-probe.test.ts",
"test/scripts/fixture-config.test.ts",
],
],
[
"scripts/e2e/lib/openwebui/http-probe.mjs",
["test/e2e/qa-lab/runtime/openwebui-probe.e2e.test.ts"],
],
["scripts/e2e/lib/openwebui/http-probe.mjs", ["test/scripts/openwebui-probe.test.ts"]],
[
"scripts/e2e/lib/plugins/npm-registry-server.mjs",
["test/scripts/plugins-assertions.test.ts"],