diff --git a/.github/workflows/openclaw-release-checks.yml b/.github/workflows/openclaw-release-checks.yml index 05f71abf92d..bb668815865 100644 --- a/.github/workflows/openclaw-release-checks.yml +++ b/.github/workflows/openclaw-release-checks.yml @@ -650,6 +650,7 @@ jobs: env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1" + OPENCLAW_QA_MATRIX_CANARY_TIMEOUT_MS: "90000" OPENCLAW_QA_MATRIX_NO_REPLY_WINDOW_MS: "3000" run: | set -euo pipefail diff --git a/docs/concepts/qa-matrix.md b/docs/concepts/qa-matrix.md index 3e323e333cd..add045f4307 100644 --- a/docs/concepts/qa-matrix.md +++ b/docs/concepts/qa-matrix.md @@ -99,6 +99,7 @@ Pass `--scenario ` (repeatable) to run a hand-picked set; combine with `--pr | Variable | Default | Effect | | --------------------------------------- | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `OPENCLAW_QA_MATRIX_TIMEOUT_MS` | `1800000` (30 min) | Hard upper bound on the entire run. | +| `OPENCLAW_QA_MATRIX_CANARY_TIMEOUT_MS` | `45000` | Bound for the initial canary reply. Release CI raises this on shared runners so a slow first gateway turn does not fail before scenario coverage starts. | | `OPENCLAW_QA_MATRIX_NO_REPLY_WINDOW_MS` | `8000` | Quiet window for negative no-reply assertions. Clamped to `≤` the run timeout. | | `OPENCLAW_QA_MATRIX_CLEANUP_TIMEOUT_MS` | `90000` | Bound for Docker teardown. Failure surfaces include the recovery `docker compose ... down --remove-orphans` command. | | `OPENCLAW_QA_MATRIX_TUWUNEL_IMAGE` | `ghcr.io/matrix-construct/tuwunel:v1.5.1` | Override the homeserver image when validating against a different Tuwunel version. | diff --git a/extensions/qa-matrix/src/runners/contract/runtime.ts b/extensions/qa-matrix/src/runners/contract/runtime.ts index 36af67df6f0..ea65bb80954 100644 --- a/extensions/qa-matrix/src/runners/contract/runtime.ts +++ b/extensions/qa-matrix/src/runners/contract/runtime.ts @@ -943,9 +943,8 @@ export async function runMatrixQaLive(params: { } finally { if (gatewayHarness) { try { - const shouldPreserveGatewayDebugArtifacts = scenarioResults.some( - (scenario) => scenario?.status === "fail", - ); + const shouldPreserveGatewayDebugArtifacts = + scenarioResults.some((scenario) => scenario?.status === "fail") || canaryFailed; preservedGatewayDebugDirPath = shouldPreserveGatewayDebugArtifacts ? path.join(outputDir, "gateway-debug") : undefined; diff --git a/src/commands/doctor.runs-legacy-state-migrations-yes-mode-without.e2e.test.ts b/src/commands/doctor.runs-legacy-state-migrations-yes-mode-without.e2e.test.ts index c75fbe572c5..5a896425fd1 100644 --- a/src/commands/doctor.runs-legacy-state-migrations-yes-mode-without.e2e.test.ts +++ b/src/commands/doctor.runs-legacy-state-migrations-yes-mode-without.e2e.test.ts @@ -112,7 +112,19 @@ describe("doctor command", () => { }, ]); - await doctorCommand(createDoctorRuntime(), { yes: true }); + const previousConfigWriteSupport = + process.env.OPENCLAW_UPDATE_PARENT_SUPPORTS_DOCTOR_CONFIG_WRITE; + process.env.OPENCLAW_UPDATE_PARENT_SUPPORTS_DOCTOR_CONFIG_WRITE = "1"; + try { + await doctorCommand(createDoctorRuntime(), { yes: true }); + } finally { + if (previousConfigWriteSupport === undefined) { + delete process.env.OPENCLAW_UPDATE_PARENT_SUPPORTS_DOCTOR_CONFIG_WRITE; + } else { + process.env.OPENCLAW_UPDATE_PARENT_SUPPORTS_DOCTOR_CONFIG_WRITE = + previousConfigWriteSupport; + } + } const written = writeConfigFile.mock.calls .map((call) => call[0] as Record)