diff --git a/.github/workflows/openclaw-release-checks.yml b/.github/workflows/openclaw-release-checks.yml index 6a14ff1ab9c..46bcac87c29 100644 --- a/.github/workflows/openclaw-release-checks.yml +++ b/.github/workflows/openclaw-release-checks.yml @@ -836,6 +836,7 @@ jobs: uses: ./.github/workflows/package-acceptance.yml with: advisory: false + allow_frozen_target_scenario_omissions: ${{ inputs.allow_frozen_target_scenario_omissions }} workflow_ref: ${{ github.sha }} source: ${{ (needs.resolve_target.outputs.package_acceptance_package_spec != '' || needs.resolve_target.outputs.release_package_spec != '') && 'npm' || 'artifact' }} package_spec: ${{ needs.resolve_target.outputs.package_acceptance_package_spec || needs.resolve_target.outputs.release_package_spec || 'openclaw@beta' }} diff --git a/.github/workflows/package-acceptance.yml b/.github/workflows/package-acceptance.yml index 9b2eabdbe6a..cfdf10efa55 100644 --- a/.github/workflows/package-acceptance.yml +++ b/.github/workflows/package-acceptance.yml @@ -263,6 +263,11 @@ on: required: false default: "" type: string + allow_frozen_target_scenario_omissions: + description: Trusted opt-in to omit survivor scenarios absent from a canonical frozen target + required: false + default: false + type: boolean telegram_mode: description: Optional Telegram QA lane for the resolved package candidate required: false @@ -801,6 +806,7 @@ jobs: published_upgrade_survivor_baseline: ${{ inputs.published_upgrade_survivor_baseline }} published_upgrade_survivor_baselines: ${{ needs.resolve_package.outputs.published_upgrade_survivor_baselines }} published_upgrade_survivor_scenarios: ${{ needs.resolve_package.outputs.published_upgrade_survivor_scenarios }} + allow_frozen_target_scenario_omissions: ${{ inputs.allow_frozen_target_scenario_omissions }} package_artifact_name: ${{ needs.resolve_package.outputs.package_artifact_name }} package_artifact_digest: ${{ needs.resolve_package.outputs.package_artifact_digest }} package_artifact_id: ${{ needs.resolve_package.outputs.package_artifact_id }} diff --git a/scripts/ci-live-command-retry.sh b/scripts/ci-live-command-retry.sh index 3d12a3d4b78..6031275e8a3 100755 --- a/scripts/ci-live-command-retry.sh +++ b/scripts/ci-live-command-retry.sh @@ -16,7 +16,7 @@ delay_seconds="${OPENCLAW_LIVE_COMMAND_RETRY_DELAY_SECONDS:-10}" rate_limit_delay_seconds="${OPENCLAW_LIVE_COMMAND_RATE_LIMIT_RETRY_DELAY_SECONDS:-60}" # Live provider 5xx responses and one-off test timeouts get one retry; deterministic # hangs still fail the second attempt. Keep auth and input failures fail-fast. -retry_pattern="${OPENCLAW_LIVE_COMMAND_RETRY_PATTERN:-ECONNRESET|ETIMEDOUT|ENOTFOUND|EAI_AGAIN|fetch failed|TLS connection|socket hang up|UND_ERR|gateway request timeout|HTTP 5[0-9][0-9]|Test timed out in [0-9]+ms|MiniMax image generation API error \\(1000\\)|model idle timeout|did not produce a response before the model idle timeout|\\b429\\b|\\b529\\b}" +retry_pattern="${OPENCLAW_LIVE_COMMAND_RETRY_PATTERN:-ECONNRESET|ETIMEDOUT|ENOTFOUND|EAI_AGAIN|fetch failed|TLS connection|socket hang up|UND_ERR|gateway request timeout|HTTP 5[0-9][0-9]|Test timed out in [0-9]+ms|terminal timeout after [0-9]+ms|MiniMax image generation API error \\(1000\\)|model idle timeout|did not produce a response before the model idle timeout|\\b429\\b|\\b529\\b}" rate_limit_pattern="${OPENCLAW_LIVE_COMMAND_RATE_LIMIT_PATTERN:-Rate limit reached|rate.?limit|tokens per min|requests per min|\\bTPM\\b|\\bRPM\\b}" if ! [[ "$attempts" =~ ^[1-9][0-9]*$ ]]; then diff --git a/test/scripts/ci-live-command-retry.test.ts b/test/scripts/ci-live-command-retry.test.ts index 3aad768ed4c..59d04574efd 100644 --- a/test/scripts/ci-live-command-retry.test.ts +++ b/test/scripts/ci-live-command-retry.test.ts @@ -69,6 +69,7 @@ describe("scripts/ci-live-command-retry.sh", () => { it.each([ ["provider HTTP 500", "xAI image edit failed (HTTP 500): Please try again later"], ["live test timeout", "Error: Test timed out in 45000ms."], + ["live terminal timeout", "Error: terminal timeout after 300000ms"], ])("retries a transient %s", (_label, message) => { const { commandPath, counterPath } = writeCommand("openclaw-ci-live-transient-", [ 'attempts="$(cat "$OPENCLAW_RETRY_TEST_COUNTER" 2>/dev/null || printf 0)"', diff --git a/test/scripts/package-acceptance-workflow.test.ts b/test/scripts/package-acceptance-workflow.test.ts index 0f4b98d65ba..ca27b0e1fb8 100644 --- a/test/scripts/package-acceptance-workflow.test.ts +++ b/test/scripts/package-acceptance-workflow.test.ts @@ -2317,8 +2317,29 @@ describe("package artifact reuse", () => { it("includes package acceptance in release checks", () => { const workflow = readFileSync(RELEASE_CHECKS_WORKFLOW, "utf8"); + const packageAcceptanceWorkflow = parse(readFileSync(PACKAGE_ACCEPTANCE_WORKFLOW, "utf8")) as { + on?: { + workflow_call?: { inputs?: Record }; + }; + }; + const packageAcceptanceJob = workflowJob( + RELEASE_CHECKS_WORKFLOW, + "package_acceptance_release_checks", + ); + const dockerAcceptanceJob = workflowJob(PACKAGE_ACCEPTANCE_WORKFLOW, "docker_acceptance"); expect(workflow).toContain("package_acceptance_release_checks:"); + expect(packageAcceptanceWorkflow.on?.workflow_call?.inputs).toHaveProperty( + "allow_frozen_target_scenario_omissions", + ); + expect(packageAcceptanceJob.with).toMatchObject({ + allow_frozen_target_scenario_omissions: + "${{ inputs.allow_frozen_target_scenario_omissions }}", + }); + expect(dockerAcceptanceJob.with).toMatchObject({ + allow_frozen_target_scenario_omissions: + "${{ inputs.allow_frozen_target_scenario_omissions }}", + }); expect(workflow).toContain( "live_repo_e2e_release_checks:\n name: Run repo/live E2E validation\n needs: [resolve_target]", );