name: OpenClaw Live And E2E Checks (Reusable)

on:
  workflow_dispatch:
    inputs:
      ref:
        description: Ref, tag, or SHA to validate
        required: true
        default: main
        type: string
      include_repo_e2e:
        description: Whether to run pnpm test:e2e plus repo-specific extra E2E lanes
        required: false
        default: true
        type: boolean
      include_release_path_suites:
        description: Whether to run the Docker release-path suites
        required: false
        default: true
        type: boolean
      include_openwebui:
        description: Whether to run the Open WebUI Docker smoke
        required: false
        default: true
        type: boolean
      docker_lanes:
        description: Comma/space separated Docker scheduler lane names to run against the prepared image
        required: false
        default: ""
        type: string
      targeted_docker_lane_group_size:
        description: Number of targeted Docker lanes to batch into one runner job
        required: false
        default: 1
        type: number
      published_upgrade_survivor_baseline:
        description: Published OpenClaw package baseline for the published-upgrade-survivor/update-migration Docker lanes
        required: false
        default: openclaw@latest
        type: string
      published_upgrade_survivor_baselines:
        description: Optional exact baseline list for published-upgrade-survivor/update-migration lane expansion
        required: false
        default: ""
        type: string
      published_upgrade_survivor_scenarios:
        description: Optional scenario list for published-upgrade-survivor/update-migration lane expansion
        required: false
        default: ""
        type: string
      package_artifact_name:
        description: Existing workflow artifact containing openclaw-current.tgz; blank packs the selected ref
        required: false
        default: ""
        type: string
      package_artifact_run_id:
        description: Prior run id containing package_artifact_name; blank uses this run or packs the selected ref
        required: false
        default: ""
        type: string
      docker_e2e_bare_image:
        description: Existing bare Docker E2E image to reuse; blank derives from package SHA/ref
        required: false
        default: ""
        type: string
      docker_e2e_functional_image:
        description: Existing functional Docker E2E image to reuse; blank derives from package SHA/ref
        required: false
        default: ""
        type: string
      codex_plugin_spec:
        description: Optional Codex plugin install spec for the live package lane; blank packs extensions/codex from the selected ref
        required: false
        default: ""
        type: string
      include_live_suites:
        description: Whether to run live-provider coverage
        required: false
        default: true
        type: boolean
      live_models_only:
        description: Whether to run only the Docker live model matrix when live suites are enabled
        required: false
        default: false
        type: boolean
      live_model_providers:
        description: Comma/space separated provider ids for the Docker live model matrix; blank runs all providers
        required: false
        default: ""
        type: string
      live_suite_filter:
        description: Optional exact live suite id to run for focused failed-shard recovery; blank runs all selected suites
        required: false
        default: ""
        type: string
      release_test_profile:
        description: Release coverage profile for live/Docker/provider breadth
        required: false
        default: stable
        type: choice
        options:
          - beta
          - stable
          - full
      use_github_hosted_runners:
        description: Use GitHub-hosted runners instead of Blacksmith runners
        required: false
        default: false
        type: boolean
      advisory:
        description: Treat failures as advisory for the caller
        required: false
        default: false
        type: boolean
  workflow_call:
    inputs:
      advisory:
        description: Treat failures as advisory for the caller
        required: false
        default: false
        type: boolean
      ref:
        description: Ref, tag, or SHA to validate
        required: true
        type: string
      include_repo_e2e:
        description: Whether to run pnpm test:e2e
        required: false
        default: false
        type: boolean
      include_release_path_suites:
        description: Whether to run the Docker release-path suites
        required: false
        default: false
        type: boolean
      include_openwebui:
        description: Whether to run the Open WebUI Docker smoke
        required: false
        default: true
        type: boolean
      docker_lanes:
        description: Comma/space separated Docker scheduler lane names to run against the prepared image
        required: false
        default: ""
        type: string
      targeted_docker_lane_group_size:
        description: Number of targeted Docker lanes to batch into one runner job
        required: false
        default: 1
        type: number
      published_upgrade_survivor_baseline:
        description: Published OpenClaw package baseline for the published-upgrade-survivor/update-restart-auth/update-migration Docker lanes
        required: false
        default: openclaw@latest
        type: string
      published_upgrade_survivor_baselines:
        description: Optional exact baseline list for published-upgrade-survivor/update-migration lane expansion
        required: false
        default: ""
        type: string
      published_upgrade_survivor_scenarios:
        description: Optional scenario list for published-upgrade-survivor/update-migration lane expansion
        required: false
        default: ""
        type: string
      package_artifact_name:
        description: Existing workflow artifact containing openclaw-current.tgz; blank packs the selected ref
        required: false
        default: ""
        type: string
      package_artifact_run_id:
        description: Prior run id containing package_artifact_name; blank uses this run or packs the selected ref
        required: false
        default: ""
        type: string
      docker_e2e_bare_image:
        description: Existing bare Docker E2E image to reuse; blank derives from package SHA/ref
        required: false
        default: ""
        type: string
      docker_e2e_functional_image:
        description: Existing functional Docker E2E image to reuse; blank derives from package SHA/ref
        required: false
        default: ""
        type: string
      codex_plugin_spec:
        description: Optional Codex plugin install spec for the live package lane; blank packs extensions/codex from the selected ref
        required: false
        default: ""
        type: string
      include_live_suites:
        description: Whether to run live-provider coverage
        required: false
        default: true
        type: boolean
      live_models_only:
        description: Whether to run only the Docker live model matrix when live suites are enabled
        required: false
        default: false
        type: boolean
      live_model_providers:
        description: Comma/space separated provider ids for the Docker live model matrix; blank runs all providers
        required: false
        default: ""
        type: string
      live_suite_filter:
        description: Optional exact live suite id to run for focused failed-shard recovery; blank runs all selected suites
        required: false
        default: ""
        type: string
      release_test_profile:
        description: Release coverage profile for live/Docker/provider breadth
        required: false
        default: stable
        type: string
      use_github_hosted_runners:
        description: Use GitHub-hosted runners instead of Blacksmith runners
        required: false
        default: true
        type: boolean
    secrets:
      OPENAI_API_KEY:
        required: false
      OPENAI_BASE_URL:
        required: false
      ANTHROPIC_API_KEY:
        required: false
      ANTHROPIC_API_KEY_OLD:
        required: false
      ANTHROPIC_API_TOKEN:
        required: false
      FACTORY_API_KEY:
        required: false
      BYTEPLUS_API_KEY:
        required: false
      CEREBRAS_API_KEY:
        required: false
      DEEPINFRA_API_KEY:
        required: false
      DASHSCOPE_API_KEY:
        required: false
      GROQ_API_KEY:
        required: false
      KIMI_API_KEY:
        required: false
      MODELSTUDIO_API_KEY:
        required: false
      MOONSHOT_API_KEY:
        required: false
      MISTRAL_API_KEY:
        required: false
      MINIMAX_API_KEY:
        required: false
      OPENCODE_API_KEY:
        required: false
      OPENCODE_ZEN_API_KEY:
        required: false
      OPENCLAW_LIVE_BROWSER_CDP_URL:
        required: false
      OPENCLAW_LIVE_SETUP_TOKEN:
        required: false
      OPENCLAW_LIVE_SETUP_TOKEN_MODEL:
        required: false
      OPENCLAW_LIVE_SETUP_TOKEN_PROFILE:
        required: false
      OPENCLAW_LIVE_SETUP_TOKEN_VALUE:
        required: false
      GEMINI_API_KEY:
        required: false
      GOOGLE_API_KEY:
        required: false
      OPENROUTER_API_KEY:
        required: false
      QWEN_API_KEY:
        required: false
      FAL_KEY:
        required: false
      RUNWAY_API_KEY:
        required: false
      DEEPGRAM_API_KEY:
        required: false
      TOGETHER_API_KEY:
        required: false
      VYDRA_API_KEY:
        required: false
      XAI_API_KEY:
        required: false
      ZAI_API_KEY:
        required: false
      Z_AI_API_KEY:
        required: false
      BYTEPLUS_ACCESS_KEY_ID:
        required: false
      BYTEPLUS_SECRET_ACCESS_KEY:
        required: false
      CLAUDE_CODE_OAUTH_TOKEN:
        required: false
      OPENCLAW_CODEX_AUTH_JSON:
        required: false
      OPENCLAW_CODEX_CONFIG_TOML:
        required: false
      OPENCLAW_CLAUDE_JSON:
        required: false
      OPENCLAW_CLAUDE_CREDENTIALS_JSON:
        required: false
      OPENCLAW_CLAUDE_SETTINGS_JSON:
        required: false
      OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON:
        required: false
      OPENCLAW_GEMINI_SETTINGS_JSON:
        required: false
      FIREWORKS_API_KEY:
        required: false

permissions:
  contents: read
  packages: write
  pull-requests: read

env:
  FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
  NODE_VERSION: "24.15.0"

jobs:
  validate_selected_ref:
    runs-on: ubuntu-24.04
    outputs:
      selected_sha: ${{ steps.validate.outputs.selected_sha }}
      trusted_reason: ${{ steps.validate.outputs.trusted_reason }}
    steps:
      - name: Checkout workflow repository
        uses: actions/checkout@v6
        with:
          fetch-depth: 0

      - name: Validate selected ref
        id: validate
        env:
          INPUT_REF: ${{ inputs.ref }}
        shell: bash
        run: |
          set -euo pipefail
          trusted_reason=""

          # Resolve here instead of in actions/checkout so short SHAs work too.
          if ! selected_sha="$(git rev-parse --verify "${INPUT_REF}^{commit}")"; then
            echo "Ref '${INPUT_REF}' could not be resolved to a commit." >&2
            exit 1
          fi

          if git merge-base --is-ancestor "$selected_sha" refs/remotes/origin/main; then
            trusted_reason="main-ancestor"
          elif git tag --points-at "$selected_sha" | grep -Eq '^v'; then
            trusted_reason="release-tag"
          elif git for-each-ref --format='%(refname:short)' --contains "$selected_sha" refs/remotes/origin | grep -Eq '^origin/'; then
            trusted_reason="repository-branch-history"
          else
            trusted_reason=""
          fi

          if [[ -z "$trusted_reason" ]]; then
            echo "Ref '${INPUT_REF}' resolved to $selected_sha, which is not trusted for secret-bearing live/E2E checks." >&2
            echo "Allowed refs must be reachable from an OpenClaw branch or release tag." >&2
            exit 1
          fi

          echo "selected_sha=$selected_sha" >> "$GITHUB_OUTPUT"
          echo "trusted_reason=$trusted_reason" >> "$GITHUB_OUTPUT"
          {
            echo "Validated ref: \`${INPUT_REF}\`"
            echo "Resolved SHA: \`$selected_sha\`"
            echo "Trust reason: \`$trusted_reason\`"
          } >> "$GITHUB_STEP_SUMMARY"

  validate_live_suite_filter:
    runs-on: ubuntu-24.04
    if: inputs.live_suite_filter != ''
    steps:
      - name: Validate focused live suite filter
        shell: bash
        env:
          LIVE_SUITE_FILTER: ${{ inputs.live_suite_filter }}
          RELEASE_TEST_PROFILE: ${{ inputs.release_test_profile }}
          INCLUDE_REPO_E2E: ${{ inputs.include_repo_e2e }}
          INCLUDE_LIVE_SUITES: ${{ inputs.include_live_suites }}
          LIVE_MODELS_ONLY: ${{ inputs.live_models_only }}
          LIVE_MODEL_PROVIDERS: ${{ inputs.live_model_providers }}
        run: |
          set -euo pipefail

          selected_suites=()

          add_suite() {
            selected_suites+=("$1")
          }

          add_profile_suite() {
            local suite_id="$1"
            local profiles="$2"
            if [[ " ${profiles} " == *" ${RELEASE_TEST_PROFILE} "* ]]; then
              add_suite "$suite_id"
            fi
          }

          live_model_providers="${LIVE_MODEL_PROVIDERS//,/}"
          live_model_providers="${live_model_providers//[[:space:]]/}"

          if [[ "$INCLUDE_REPO_E2E" == "true" ]]; then
            add_suite openshell-e2e
          fi

          if [[ "$INCLUDE_LIVE_SUITES" == "true" ]]; then
            if [[ -n "$live_model_providers" ]]; then
              add_suite docker-live-models
            else
              add_profile_suite docker-live-models "beta minimum stable full"
            fi

            if [[ "$LIVE_MODELS_ONLY" != "true" ]]; then
              add_suite live-cache

              add_profile_suite native-live-src-agents "stable full"
              add_profile_suite native-live-src-gateway-core "beta minimum stable full"
              add_profile_suite native-live-src-gateway-profiles-anthropic "stable full"
              add_profile_suite native-live-src-gateway-profiles-anthropic-smoke "stable"
              add_profile_suite native-live-src-gateway-profiles-anthropic-opus "full"
              add_profile_suite native-live-src-gateway-profiles-anthropic-sonnet-haiku "full"
              add_profile_suite native-live-src-gateway-profiles-google "stable full"
              add_profile_suite native-live-src-gateway-profiles-minimax "stable full"
              add_profile_suite native-live-src-gateway-profiles-openai "beta minimum stable full"
              add_profile_suite native-live-src-gateway-profiles-fireworks "full"
              add_profile_suite native-live-src-gateway-profiles-deepseek "full"
              add_profile_suite native-live-src-gateway-profiles-opencode-go "full"
              add_profile_suite native-live-src-gateway-profiles-opencode-go-smoke "stable"
              add_profile_suite native-live-src-gateway-profiles-openrouter "full"
              add_profile_suite native-live-src-gateway-profiles-xai "full"
              add_profile_suite native-live-src-gateway-profiles-zai "full"
              add_profile_suite native-live-src-gateway-backends "stable full"
              add_profile_suite native-live-src-infra "stable full"
              add_profile_suite native-live-test "stable full"
              add_profile_suite native-live-extensions-l-n "full"
              add_profile_suite native-live-extensions-moonshot "full"
              add_profile_suite native-live-extensions-openai "beta minimum stable full"
              add_profile_suite native-live-extensions-o-z-other "full"
              add_profile_suite native-live-extensions-xai "full"

              add_profile_suite live-gateway-docker "beta minimum stable full"
              add_profile_suite live-gateway-anthropic-docker "stable full"
              add_profile_suite live-gateway-google-docker "stable full"
              add_profile_suite live-gateway-minimax-docker "stable full"
              add_profile_suite live-gateway-advisory-docker "full"
              add_profile_suite live-gateway-advisory-docker-deepseek-fireworks "full"
              add_profile_suite live-gateway-advisory-docker-opencode-openrouter "full"
              add_profile_suite live-gateway-advisory-docker-xai-zai "full"
              add_profile_suite live-cli-backend-docker "stable full"
              add_profile_suite live-acp-bind-docker "stable full"
              add_profile_suite live-codex-harness-docker "stable full"
              add_profile_suite live-subagent-announce-docker "stable full"

              add_profile_suite native-live-extensions-a-k "full"
              add_profile_suite native-live-extensions-media-audio "full"
              add_profile_suite native-live-extensions-media-music-google "full"
              add_profile_suite native-live-extensions-media-music-minimax "full"
              add_profile_suite native-live-extensions-media-video "full"
            fi
          fi

          for suite_id in "${selected_suites[@]}"; do
            if [[ "$LIVE_SUITE_FILTER" == "$suite_id" ]]; then
              echo "Focused live suite filter is valid: ${LIVE_SUITE_FILTER}"
              exit 0
            fi
          done

          echo "live_suite_filter '${LIVE_SUITE_FILTER}' does not match any runnable suite for release_test_profile='${RELEASE_TEST_PROFILE}' and the selected include flags." >&2
          if [[ "${#selected_suites[@]}" -gt 0 ]]; then
            printf 'Runnable focused suite ids: %s\n' "${selected_suites[*]}" >&2
          else
            echo "No focused live suites are runnable for the selected include flags." >&2
          fi
          exit 1

  plan_release_workflow_matrices:
    needs: validate_selected_ref
    runs-on: ubuntu-24.04
    outputs:
      docker_e2e_count: ${{ steps.plan.outputs.docker_e2e_count }}
      docker_e2e_matrix: ${{ steps.plan.outputs.docker_e2e_matrix }}
      docker_e2e_omitted_json: ${{ steps.plan.outputs.docker_e2e_omitted_json }}
      live_models_count: ${{ steps.plan.outputs.live_models_count }}
      live_models_matrix: ${{ steps.plan.outputs.live_models_matrix }}
      live_models_omitted_json: ${{ steps.plan.outputs.live_models_omitted_json }}
    steps:
      - name: Checkout trusted release harness
        uses: actions/checkout@v6
        with:
          persist-credentials: false
          ref: ${{ github.sha }}
          fetch-depth: 1

      - name: Plan release workflow matrices
        id: plan
        env:
          DOCKER_LANES: ${{ inputs.docker_lanes }}
          INCLUDE_LIVE_SUITES: ${{ inputs.include_live_suites }}
          INCLUDE_RELEASE_PATH_SUITES: ${{ inputs.include_release_path_suites }}
          LIVE_MODEL_PROVIDERS: ${{ inputs.live_model_providers }}
          LIVE_SUITE_FILTER: ${{ inputs.live_suite_filter }}
          RELEASE_TEST_PROFILE: ${{ inputs.release_test_profile }}
        run: node scripts/plan-release-workflow-matrix.mjs >> "$GITHUB_OUTPUT"

  validate_release_live_cache:
    needs: validate_selected_ref
    if: inputs.include_live_suites && !inputs.live_models_only && (inputs.live_suite_filter == '' || inputs.live_suite_filter == 'live-cache')
    continue-on-error: ${{ inputs.advisory }}
    runs-on: ${{ inputs.use_github_hosted_runners && 'ubuntu-24.04' || 'blacksmith-8vcpu-ubuntu-2404' }}
    timeout-minutes: 20
    env:
      OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
      ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
      OPENCLAW_LIVE_CACHE_TEST: "1"
      OPENCLAW_LIVE_TEST: "1"
    steps:
      - name: Checkout selected ref
        uses: actions/checkout@v6
        with:
          ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
          fetch-depth: 1

      - name: Setup Node environment
        uses: ./.github/actions/setup-node-env
        with:
          node-version: ${{ env.NODE_VERSION }}
          install-bun: "true"

      - name: Validate live cache credentials
        run: |
          set -euo pipefail
          if [[ -z "${OPENAI_API_KEY:-}" ]]; then
            echo "Missing OPENAI_API_KEY secret for live-cache validation." >&2
            exit 1
          fi
          if [[ -z "${ANTHROPIC_API_KEY:-}" ]]; then
            echo "Missing ANTHROPIC_API_KEY secret for live-cache validation." >&2
            exit 1
          fi

      - name: Verify live prompt cache floors
        run: |
          set -euo pipefail
          for attempt in 1 2; do
            echo "live-cache attempt ${attempt}/2"
            if timeout --foreground --kill-after=30s 8m pnpm test:live:cache; then
              exit 0
            fi
            if [[ "$attempt" == "2" ]]; then
              exit 1
            fi
            sleep $((attempt * 15))
          done

  validate_repo_e2e:
    needs: validate_selected_ref
    if: inputs.include_repo_e2e && inputs.live_suite_filter == ''
    continue-on-error: ${{ inputs.advisory }}
    runs-on: ${{ inputs.use_github_hosted_runners && 'ubuntu-24.04' || 'blacksmith-8vcpu-ubuntu-2404' }}
    timeout-minutes: ${{ inputs.release_test_profile == 'full' && 90 || 60 }}
    env:
      OPENCLAW_VITEST_MAX_WORKERS: "2"
    steps:
      - name: Checkout selected ref
        uses: actions/checkout@v6
        with:
          ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
          fetch-depth: 1

      - name: Setup Node environment
        uses: ./.github/actions/setup-node-env
        with:
          node-version: ${{ env.NODE_VERSION }}
          install-bun: "true"

      - name: Build dist for repo E2E
        env:
          NODE_OPTIONS: --max-old-space-size=8192
        run: pnpm build

      - name: Install Playwright Chromium
        run: pnpm --dir ui exec playwright install --with-deps chromium

      - name: Run repo E2E suite
        run: pnpm test:e2e

  validate_special_e2e:
    needs: validate_selected_ref
    if: inputs.include_repo_e2e && (inputs.live_suite_filter == '' || inputs.live_suite_filter == 'openshell-e2e')
    continue-on-error: ${{ inputs.advisory }}
    runs-on: ${{ inputs.use_github_hosted_runners && 'ubuntu-24.04' || 'blacksmith-8vcpu-ubuntu-2404' }}
    timeout-minutes: ${{ matrix.timeout_minutes }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - suite_id: openshell-e2e
            label: OpenShell repo E2E
            command: pnpm test:e2e:openshell
            timeout_minutes: 60
            requires_repo_e2e: true
            requires_live_suites: false
    env:
      OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
      OPENCLAW_E2E_WORKERS: "1"
      OPENCLAW_VITEST_MAX_WORKERS: "1"
    steps:
      - name: Checkout selected ref
        uses: actions/checkout@v6
        with:
          ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
          fetch-depth: 1

      - name: Setup Node environment
        uses: ./.github/actions/setup-node-env
        with:
          node-version: ${{ env.NODE_VERSION }}
          install-bun: "true"

      - name: Build dist for special E2E
        if: |
          (
            (inputs.include_repo_e2e && matrix.requires_repo_e2e) ||
            (inputs.include_live_suites && matrix.requires_live_suites)
          ) &&
          (inputs.live_suite_filter == '' || inputs.live_suite_filter == matrix.suite_id)
        env:
          NODE_OPTIONS: --max-old-space-size=8192
        run: pnpm build

      - name: Configure suite-specific env
        if: inputs.live_suite_filter == '' || inputs.live_suite_filter == matrix.suite_id
        shell: bash
        run: |
          set -euo pipefail
          case "${{ matrix.suite_id }}" in
            openshell-e2e)
              ;;
          esac

      - name: Validate suite credentials
        if: inputs.live_suite_filter == '' || inputs.live_suite_filter == matrix.suite_id
        shell: bash
        run: |
          set -euo pipefail
          case "${{ matrix.suite_id }}" in
            openshell-e2e)
              ;;
          esac

      - name: Run ${{ matrix.label }}
        if: |
          (
            (inputs.include_repo_e2e && matrix.requires_repo_e2e) ||
            (inputs.include_live_suites && matrix.requires_live_suites)
          ) &&
          (inputs.live_suite_filter == '' || inputs.live_suite_filter == matrix.suite_id)
        run: ${{ matrix.command }}

  validate_docker_e2e:
    needs: [validate_selected_ref, prepare_docker_e2e_image, plan_release_workflow_matrices]
    if: inputs.include_release_path_suites && inputs.docker_lanes == '' && needs.plan_release_workflow_matrices.outputs.docker_e2e_count != '0'
    name: Docker E2E (${{ matrix.label }})
    continue-on-error: ${{ inputs.advisory }}
    runs-on: ${{ inputs.use_github_hosted_runners && 'ubuntu-24.04' || 'blacksmith-32vcpu-ubuntu-2404' }}
    timeout-minutes: ${{ matrix.timeout_minutes }}
    strategy:
      fail-fast: false
      matrix: ${{ fromJson(needs.plan_release_workflow_matrices.outputs.docker_e2e_matrix) }}
    env:
      OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
      OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
      ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
      ANTHROPIC_API_TOKEN: ${{ secrets.ANTHROPIC_API_TOKEN }}
      ANTHROPIC_API_KEY_OLD: ${{ secrets.ANTHROPIC_API_KEY_OLD }}
      FACTORY_API_KEY: ${{ secrets.FACTORY_API_KEY }}
      BYTEPLUS_API_KEY: ${{ secrets.BYTEPLUS_API_KEY }}
      CEREBRAS_API_KEY: ${{ secrets.CEREBRAS_API_KEY }}
      DEEPINFRA_API_KEY: ${{ secrets.DEEPINFRA_API_KEY }}
      DASHSCOPE_API_KEY: ${{ secrets.DASHSCOPE_API_KEY }}
      GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
      KIMI_API_KEY: ${{ secrets.KIMI_API_KEY }}
      MODELSTUDIO_API_KEY: ${{ secrets.MODELSTUDIO_API_KEY }}
      MOONSHOT_API_KEY: ${{ secrets.MOONSHOT_API_KEY }}
      MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
      MINIMAX_API_KEY: ${{ secrets.MINIMAX_API_KEY }}
      OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
      OPENCODE_ZEN_API_KEY: ${{ secrets.OPENCODE_ZEN_API_KEY }}
      OPENCLAW_LIVE_BROWSER_CDP_URL: ${{ secrets.OPENCLAW_LIVE_BROWSER_CDP_URL }}
      OPENCLAW_LIVE_SETUP_TOKEN: ${{ secrets.OPENCLAW_LIVE_SETUP_TOKEN }}
      OPENCLAW_LIVE_SETUP_TOKEN_MODEL: ${{ secrets.OPENCLAW_LIVE_SETUP_TOKEN_MODEL }}
      OPENCLAW_LIVE_SETUP_TOKEN_PROFILE: ${{ secrets.OPENCLAW_LIVE_SETUP_TOKEN_PROFILE }}
      OPENCLAW_LIVE_SETUP_TOKEN_VALUE: ${{ secrets.OPENCLAW_LIVE_SETUP_TOKEN_VALUE }}
      GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
      GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
      OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
      QWEN_API_KEY: ${{ secrets.QWEN_API_KEY }}
      FAL_KEY: ${{ secrets.FAL_KEY }}
      RUNWAY_API_KEY: ${{ secrets.RUNWAY_API_KEY }}
      DEEPGRAM_API_KEY: ${{ secrets.DEEPGRAM_API_KEY }}
      TOGETHER_API_KEY: ${{ secrets.TOGETHER_API_KEY }}
      VYDRA_API_KEY: ${{ secrets.VYDRA_API_KEY }}
      XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
      ZAI_API_KEY: ${{ secrets.ZAI_API_KEY }}
      Z_AI_API_KEY: ${{ secrets.Z_AI_API_KEY }}
      BYTEPLUS_ACCESS_KEY_ID: ${{ secrets.BYTEPLUS_ACCESS_KEY_ID }}
      BYTEPLUS_SECRET_ACCESS_KEY: ${{ secrets.BYTEPLUS_SECRET_ACCESS_KEY }}
      CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
      OPENCLAW_CODEX_AUTH_JSON: ${{ secrets.OPENCLAW_CODEX_AUTH_JSON }}
      OPENCLAW_CODEX_CONFIG_TOML: ${{ secrets.OPENCLAW_CODEX_CONFIG_TOML }}
      OPENCLAW_CLAUDE_JSON: ${{ secrets.OPENCLAW_CLAUDE_JSON }}
      OPENCLAW_CLAUDE_CREDENTIALS_JSON: ${{ secrets.OPENCLAW_CLAUDE_CREDENTIALS_JSON }}
      OPENCLAW_CLAUDE_SETTINGS_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_JSON }}
      OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON }}
      OPENCLAW_GEMINI_SETTINGS_JSON: ${{ secrets.OPENCLAW_GEMINI_SETTINGS_JSON }}
      FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}
      OPENCLAW_DOCKER_E2E_IMAGE: ${{ needs.prepare_docker_e2e_image.outputs.image }}
      OPENCLAW_DOCKER_E2E_BARE_IMAGE: ${{ needs.prepare_docker_e2e_image.outputs.bare_image }}
      OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE: ${{ needs.prepare_docker_e2e_image.outputs.functional_image }}
      OPENCLAW_DOCKER_E2E_PACKAGE_ARTIFACT_NAME: ${{ inputs.package_artifact_name || 'docker-e2e-package' }}
      OPENCLAW_DOCKER_E2E_REPO_ROOT: ${{ github.workspace }}
      OPENCLAW_DOCKER_E2E_SELECTED_SHA: ${{ needs.validate_selected_ref.outputs.selected_sha }}
      OPENCLAW_DOCKER_ALL_RELEASE_PROFILE: ${{ inputs.release_test_profile }}
      OPENCLAW_CODEX_NPM_PLUGIN_SPEC: ${{ inputs.codex_plugin_spec }}
      OPENCLAW_CURRENT_PACKAGE_TGZ: .artifacts/docker-e2e-package/openclaw-current.tgz
      OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC: ${{ inputs.published_upgrade_survivor_baseline }}
      OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPECS: ${{ inputs.published_upgrade_survivor_baselines }}
      OPENCLAW_UPGRADE_SURVIVOR_SCENARIOS: ${{ inputs.published_upgrade_survivor_scenarios }}
      OPENCLAW_SKIP_DOCKER_BUILD: "1"
      INCLUDE_OPENWEBUI: ${{ inputs.include_openwebui }}
      DOCKER_E2E_CHUNK: ${{ matrix.chunk_id }}
    steps:
      - name: Checkout selected ref
        if: contains(matrix.profiles, inputs.release_test_profile)
        uses: actions/checkout@v6
        with:
          persist-credentials: false
          ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
          fetch-depth: 1

      - name: Checkout trusted release harness
        if: contains(matrix.profiles, inputs.release_test_profile)
        uses: actions/checkout@v6
        with:
          persist-credentials: false
          ref: ${{ github.sha }}
          fetch-depth: 1
          path: .release-harness

      - name: Log in to GHCR for shared Docker E2E image
        if: contains(matrix.profiles, inputs.release_test_profile)
        run: bash .release-harness/scripts/ci-docker-login-ghcr.sh
        env:
          GHCR_USERNAME: ${{ github.actor }}
          GITHUB_TOKEN: ${{ github.token }}

      - name: Setup Node environment
        if: contains(matrix.profiles, inputs.release_test_profile)
        uses: ./.github/actions/setup-node-env
        with:
          node-version: ${{ env.NODE_VERSION }}
          install-bun: "true"

      - name: Hydrate live auth/profile inputs
        if: contains(matrix.profiles, inputs.release_test_profile)
        run: bash scripts/ci-hydrate-live-auth.sh

      - name: Plan Docker E2E chunk
        if: contains(matrix.profiles, inputs.release_test_profile)
        id: plan
        shell: bash
        env:
          CHUNK: ${{ matrix.chunk_id }}
          INCLUDE_OPENWEBUI: ${{ inputs.include_openwebui }}
          RELEASE_TEST_PROFILE: ${{ inputs.release_test_profile }}
        run: |
          set -euo pipefail
          if [[ -z "$CHUNK" ]]; then
            echo "chunk input is required for Docker E2E chunk planning." >&2
            exit 1
          fi

          mkdir -p .artifacts/docker-tests
          export OPENCLAW_DOCKER_ALL_PROFILE=release-path
          export OPENCLAW_DOCKER_ALL_CHUNK="$CHUNK"
          export OPENCLAW_DOCKER_ALL_INCLUDE_OPENWEBUI="$INCLUDE_OPENWEBUI"
          export OPENCLAW_DOCKER_ALL_RELEASE_PROFILE="$RELEASE_TEST_PROFILE"

          plan_path=".artifacts/docker-tests/release-${CHUNK}-plan.json"
          node .release-harness/scripts/test-docker-all.mjs --plan-json > "$plan_path"
          node .release-harness/scripts/docker-e2e.mjs github-outputs "$plan_path" >> "$GITHUB_OUTPUT"
          echo "plan_json=$plan_path" >> "$GITHUB_OUTPUT"

      - name: Download OpenClaw Docker E2E package
        if: contains(matrix.profiles, inputs.release_test_profile) && steps.plan.outputs.needs_package == '1'
        uses: actions/download-artifact@v8
        with:
          name: ${{ inputs.package_artifact_name || 'docker-e2e-package' }}
          path: .artifacts/docker-e2e-package

      - name: Pull shared bare Docker E2E image
        if: contains(matrix.profiles, inputs.release_test_profile) && steps.plan.outputs.needs_bare_image == '1'
        shell: bash
        run: |
          set -euo pipefail
          bash .release-harness/scripts/ci-docker-pull-retry.sh "${OPENCLAW_DOCKER_E2E_BARE_IMAGE}"

      - name: Pull shared functional Docker E2E image
        if: contains(matrix.profiles, inputs.release_test_profile) && steps.plan.outputs.needs_functional_image == '1'
        shell: bash
        run: |
          set -euo pipefail
          bash .release-harness/scripts/ci-docker-pull-retry.sh "${OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE}"

      - name: Validate Docker E2E credentials
        if: contains(matrix.profiles, inputs.release_test_profile)
        shell: bash
        env:
          CREDENTIALS: ${{ steps.plan.outputs.credentials }}
        run: |
          set -euo pipefail
          credentials=",$CREDENTIALS,"
          require_any() {
            local label="$1"
            shift
            local key
            for key in "$@"; do
              if [[ -n "${!key:-}" ]]; then
                return 0
              fi
            done
            echo "Missing credential for ${label}: expected one of $*" >&2
            exit 1
          }
          if [[ "$credentials" == *",openai,"* ]]; then
            require_any OpenAI OPENAI_API_KEY
          fi
          if [[ "$credentials" == *",codex,"* ]]; then
            require_any Codex OPENCLAW_CODEX_AUTH_JSON
          fi
          if [[ "$credentials" == *",anthropic,"* ]]; then
            require_any Anthropic ANTHROPIC_API_TOKEN ANTHROPIC_API_KEY OPENCLAW_CLAUDE_CREDENTIALS_JSON OPENCLAW_CLAUDE_JSON
          fi
          if [[ "$credentials" == *",factory,"* ]]; then
            require_any Factory FACTORY_API_KEY
          fi
          if [[ "$credentials" == *",gemini,"* ]]; then
            require_any Gemini GEMINI_API_KEY GOOGLE_API_KEY OPENCLAW_GEMINI_SETTINGS_JSON
          fi
          if [[ "$credentials" == *",opencode,"* ]]; then
            require_any OpenCode OPENCODE_API_KEY OPENCODE_ZEN_API_KEY
          fi

      - name: Run Docker E2E chunk
        if: contains(matrix.profiles, inputs.release_test_profile)
        shell: bash
        run: |
          set -euo pipefail
          export OPENCLAW_DOCKER_ALL_PROFILE=release-path
          export OPENCLAW_DOCKER_ALL_CHUNK="${DOCKER_E2E_CHUNK}"
          export OPENCLAW_DOCKER_ALL_RELEASE_PROFILE="${OPENCLAW_DOCKER_ALL_RELEASE_PROFILE}"
          export OPENCLAW_DOCKER_ALL_BUILD=0
          export OPENCLAW_DOCKER_ALL_PREFLIGHT=0
          export OPENCLAW_DOCKER_ALL_FAIL_FAST=0
          export OPENCLAW_DOCKER_ALL_INCLUDE_OPENWEBUI="${INCLUDE_OPENWEBUI}"
          export OPENCLAW_DOCKER_ALL_LOG_DIR=".artifacts/docker-tests/release-${DOCKER_E2E_CHUNK}"
          export OPENCLAW_DOCKER_ALL_TIMINGS_FILE=".artifacts/docker-tests/release-${DOCKER_E2E_CHUNK}-timings.json"
          export OPENCLAW_DOCKER_ALL_PNPM_COMMAND="$(command -v pnpm)"
          if [[ "${{ steps.plan.outputs.needs_live_image }}" == "1" ]]; then
            OPENCLAW_DOCKER_BUILD_ON_MISSING=1 OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" bash .release-harness/scripts/test-live-build-docker.sh
          fi

          node .release-harness/scripts/test-docker-all.mjs

      - name: Summarize Docker E2E chunk
        if: always()
        shell: bash
        run: |
          set -euo pipefail
          summary=".artifacts/docker-tests/release-${DOCKER_E2E_CHUNK}/summary.json"
          if [[ ! -f "$summary" ]]; then
            echo "Docker chunk summary missing: \`$summary\`" >> "$GITHUB_STEP_SUMMARY"
            exit 0
          fi
          node .release-harness/scripts/docker-e2e.mjs summary "$summary" "Docker E2E chunk: ${DOCKER_E2E_CHUNK:-unknown}" >> "$GITHUB_STEP_SUMMARY"

      - name: Upload Docker E2E chunk artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: docker-e2e-${{ matrix.chunk_id }}
          path: .artifacts/docker-tests/
          if-no-files-found: ignore

  plan_docker_lane_groups:
    needs: validate_selected_ref
    if: inputs.docker_lanes != ''
    continue-on-error: ${{ inputs.advisory }}
    runs-on: ${{ inputs.use_github_hosted_runners && 'ubuntu-24.04' || 'blacksmith-4vcpu-ubuntu-2404' }}
    timeout-minutes: 5
    outputs:
      groups_json: ${{ steps.groups.outputs.groups_json }}
    steps:
      - name: Checkout trusted release harness
        uses: actions/checkout@v6
        with:
          persist-credentials: false
          ref: ${{ github.sha }}
          fetch-depth: 1

      - name: Build targeted Docker lane groups
        id: groups
        shell: bash
        env:
          LANES: ${{ inputs.docker_lanes }}
          GROUP_SIZE: ${{ inputs.targeted_docker_lane_group_size }}
          OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPECS: ${{ inputs.published_upgrade_survivor_baselines }}
        run: |
          set -euo pipefail
          groups_json="$(node scripts/plan-targeted-docker-lane-groups.mjs)"
          echo "groups_json=${groups_json}" >> "$GITHUB_OUTPUT"

  validate_docker_lanes:
    needs: [validate_selected_ref, prepare_docker_e2e_image, plan_docker_lane_groups]
    if: inputs.docker_lanes != ''
    name: Docker E2E targeted lanes (${{ matrix.group.label }})
    continue-on-error: ${{ inputs.advisory }}
    runs-on: ${{ inputs.use_github_hosted_runners && 'ubuntu-24.04' || 'blacksmith-32vcpu-ubuntu-2404' }}
    timeout-minutes: 60
    strategy:
      fail-fast: false
      matrix:
        group: ${{ fromJson(needs.plan_docker_lane_groups.outputs.groups_json) }}
    env:
      OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
      OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
      ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
      ANTHROPIC_API_TOKEN: ${{ secrets.ANTHROPIC_API_TOKEN }}
      ANTHROPIC_API_KEY_OLD: ${{ secrets.ANTHROPIC_API_KEY_OLD }}
      FACTORY_API_KEY: ${{ secrets.FACTORY_API_KEY }}
      BYTEPLUS_API_KEY: ${{ secrets.BYTEPLUS_API_KEY }}
      CEREBRAS_API_KEY: ${{ secrets.CEREBRAS_API_KEY }}
      DEEPINFRA_API_KEY: ${{ secrets.DEEPINFRA_API_KEY }}
      DASHSCOPE_API_KEY: ${{ secrets.DASHSCOPE_API_KEY }}
      GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
      KIMI_API_KEY: ${{ secrets.KIMI_API_KEY }}
      MODELSTUDIO_API_KEY: ${{ secrets.MODELSTUDIO_API_KEY }}
      MOONSHOT_API_KEY: ${{ secrets.MOONSHOT_API_KEY }}
      MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
      MINIMAX_API_KEY: ${{ secrets.MINIMAX_API_KEY }}
      OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
      OPENCODE_ZEN_API_KEY: ${{ secrets.OPENCODE_ZEN_API_KEY }}
      OPENCLAW_LIVE_BROWSER_CDP_URL: ${{ secrets.OPENCLAW_LIVE_BROWSER_CDP_URL }}
      OPENCLAW_LIVE_SETUP_TOKEN: ${{ secrets.OPENCLAW_LIVE_SETUP_TOKEN }}
      OPENCLAW_LIVE_SETUP_TOKEN_MODEL: ${{ secrets.OPENCLAW_LIVE_SETUP_TOKEN_MODEL }}
      OPENCLAW_LIVE_SETUP_TOKEN_PROFILE: ${{ secrets.OPENCLAW_LIVE_SETUP_TOKEN_PROFILE }}
      OPENCLAW_LIVE_SETUP_TOKEN_VALUE: ${{ secrets.OPENCLAW_LIVE_SETUP_TOKEN_VALUE }}
      GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
      GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
      OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
      QWEN_API_KEY: ${{ secrets.QWEN_API_KEY }}
      FAL_KEY: ${{ secrets.FAL_KEY }}
      RUNWAY_API_KEY: ${{ secrets.RUNWAY_API_KEY }}
      DEEPGRAM_API_KEY: ${{ secrets.DEEPGRAM_API_KEY }}
      TOGETHER_API_KEY: ${{ secrets.TOGETHER_API_KEY }}
      VYDRA_API_KEY: ${{ secrets.VYDRA_API_KEY }}
      XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
      ZAI_API_KEY: ${{ secrets.ZAI_API_KEY }}
      Z_AI_API_KEY: ${{ secrets.Z_AI_API_KEY }}
      BYTEPLUS_ACCESS_KEY_ID: ${{ secrets.BYTEPLUS_ACCESS_KEY_ID }}
      BYTEPLUS_SECRET_ACCESS_KEY: ${{ secrets.BYTEPLUS_SECRET_ACCESS_KEY }}
      CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
      OPENCLAW_CODEX_AUTH_JSON: ${{ secrets.OPENCLAW_CODEX_AUTH_JSON }}
      OPENCLAW_CODEX_CONFIG_TOML: ${{ secrets.OPENCLAW_CODEX_CONFIG_TOML }}
      OPENCLAW_CLAUDE_JSON: ${{ secrets.OPENCLAW_CLAUDE_JSON }}
      OPENCLAW_CLAUDE_CREDENTIALS_JSON: ${{ secrets.OPENCLAW_CLAUDE_CREDENTIALS_JSON }}
      OPENCLAW_CLAUDE_SETTINGS_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_JSON }}
      OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON }}
      OPENCLAW_GEMINI_SETTINGS_JSON: ${{ secrets.OPENCLAW_GEMINI_SETTINGS_JSON }}
      FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}
      OPENCLAW_DOCKER_E2E_IMAGE: ${{ needs.prepare_docker_e2e_image.outputs.image }}
      OPENCLAW_DOCKER_E2E_BARE_IMAGE: ${{ needs.prepare_docker_e2e_image.outputs.bare_image }}
      OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE: ${{ needs.prepare_docker_e2e_image.outputs.functional_image }}
      OPENCLAW_DOCKER_E2E_PACKAGE_ARTIFACT_NAME: ${{ inputs.package_artifact_name || 'docker-e2e-package' }}
      OPENCLAW_DOCKER_E2E_REPO_ROOT: ${{ github.workspace }}
      OPENCLAW_DOCKER_E2E_SELECTED_SHA: ${{ needs.validate_selected_ref.outputs.selected_sha }}
      OPENCLAW_CODEX_NPM_PLUGIN_SPEC: ${{ inputs.codex_plugin_spec }}
      OPENCLAW_CURRENT_PACKAGE_TGZ: .artifacts/docker-e2e-package/openclaw-current.tgz
      OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC: ${{ inputs.published_upgrade_survivor_baseline }}
      OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPECS: ${{ matrix.group.published_upgrade_survivor_baselines || inputs.published_upgrade_survivor_baselines }}
      OPENCLAW_UPGRADE_SURVIVOR_SCENARIOS: ${{ inputs.published_upgrade_survivor_scenarios }}
      OPENCLAW_SKIP_DOCKER_BUILD: "1"
      INCLUDE_OPENWEBUI: ${{ inputs.include_openwebui }}
      DOCKER_E2E_LANES: ${{ matrix.group.docker_lanes }}
    steps:
      - name: Checkout selected ref
        uses: actions/checkout@v6
        with:
          persist-credentials: false
          ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
          fetch-depth: 1

      - name: Checkout trusted release harness
        uses: actions/checkout@v6
        with:
          persist-credentials: false
          ref: ${{ github.sha }}
          fetch-depth: 1
          path: .release-harness

      - name: Log in to GHCR for shared Docker E2E image
        run: bash .release-harness/scripts/ci-docker-login-ghcr.sh
        env:
          GHCR_USERNAME: ${{ github.actor }}
          GITHUB_TOKEN: ${{ github.token }}

      - name: Setup Node environment
        uses: ./.github/actions/setup-node-env
        with:
          node-version: ${{ env.NODE_VERSION }}
          install-bun: "true"

      - name: Hydrate live auth/profile inputs
        run: bash scripts/ci-hydrate-live-auth.sh

      - name: Plan targeted Docker E2E lanes
        id: plan
        shell: bash
        env:
          LANES: ${{ matrix.group.docker_lanes }}
          GROUP_LABEL: ${{ matrix.group.label }}
          INCLUDE_OPENWEBUI: ${{ inputs.include_openwebui }}
          INCLUDE_RELEASE_PATH_SUITES: ${{ inputs.include_release_path_suites }}
        run: |
          set -euo pipefail
          if [[ -z "$LANES" ]]; then
            echo "lanes input is required for Docker E2E targeted planning." >&2
            exit 1
          fi

          mkdir -p .artifacts/docker-tests
          export OPENCLAW_DOCKER_ALL_LANES="$LANES"
          export OPENCLAW_DOCKER_ALL_INCLUDE_OPENWEBUI="$INCLUDE_OPENWEBUI"
          if [[ "$INCLUDE_RELEASE_PATH_SUITES" == "true" ]]; then
            export OPENCLAW_DOCKER_ALL_PROFILE=release-path
          fi

          plan_path=".artifacts/docker-tests/targeted-plan.json"
          node .release-harness/scripts/test-docker-all.mjs --plan-json > "$plan_path"
          node .release-harness/scripts/docker-e2e.mjs github-outputs "$plan_path" >> "$GITHUB_OUTPUT"
          suffix="$(printf '%s' "${GROUP_LABEL:-$LANES}" | tr ',[:space:]' '-' | tr -cd 'A-Za-z0-9._-' | sed -E 's/-+/-/g; s/^-//; s/-$//')"
          echo "artifact_suffix=${suffix:-targeted}" >> "$GITHUB_OUTPUT"
          echo "plan_json=$plan_path" >> "$GITHUB_OUTPUT"

      - name: Download OpenClaw Docker E2E package
        if: steps.plan.outputs.needs_package == '1'
        uses: actions/download-artifact@v8
        with:
          name: ${{ inputs.package_artifact_name || 'docker-e2e-package' }}
          path: .artifacts/docker-e2e-package

      - name: Pull shared bare Docker E2E image
        if: steps.plan.outputs.needs_bare_image == '1'
        shell: bash
        run: |
          set -euo pipefail
          bash .release-harness/scripts/ci-docker-pull-retry.sh "${OPENCLAW_DOCKER_E2E_BARE_IMAGE}"

      - name: Pull shared functional Docker E2E image
        if: steps.plan.outputs.needs_functional_image == '1'
        shell: bash
        run: |
          set -euo pipefail
          bash .release-harness/scripts/ci-docker-pull-retry.sh "${OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE}"

      - name: Validate Docker E2E credentials
        shell: bash
        env:
          CREDENTIALS: ${{ steps.plan.outputs.credentials }}
        run: |
          set -euo pipefail
          credentials=",$CREDENTIALS,"
          require_any() {
            local label="$1"
            shift
            local key
            for key in "$@"; do
              if [[ -n "${!key:-}" ]]; then
                return 0
              fi
            done
            echo "Missing credential for ${label}: expected one of $*" >&2
            exit 1
          }
          if [[ "$credentials" == *",openai,"* ]]; then
            require_any OpenAI OPENAI_API_KEY
          fi
          if [[ "$credentials" == *",codex,"* ]]; then
            require_any Codex OPENCLAW_CODEX_AUTH_JSON
          fi
          if [[ "$credentials" == *",anthropic,"* ]]; then
            require_any Anthropic ANTHROPIC_API_TOKEN ANTHROPIC_API_KEY OPENCLAW_CLAUDE_CREDENTIALS_JSON OPENCLAW_CLAUDE_JSON
          fi
          if [[ "$credentials" == *",factory,"* ]]; then
            require_any Factory FACTORY_API_KEY
          fi
          if [[ "$credentials" == *",gemini,"* ]]; then
            require_any Gemini GEMINI_API_KEY GOOGLE_API_KEY OPENCLAW_GEMINI_SETTINGS_JSON
          fi
          if [[ "$credentials" == *",opencode,"* ]]; then
            require_any OpenCode OPENCODE_API_KEY OPENCODE_ZEN_API_KEY
          fi

      - name: Run targeted Docker E2E lanes
        shell: bash
        run: |
          set -euo pipefail
          export OPENCLAW_DOCKER_ALL_LANES="${DOCKER_E2E_LANES}"
          export OPENCLAW_DOCKER_ALL_PREFLIGHT=0
          export OPENCLAW_DOCKER_ALL_FAIL_FAST=0
          export OPENCLAW_DOCKER_ALL_INCLUDE_OPENWEBUI="${INCLUDE_OPENWEBUI}"
          if [[ "${{ inputs.include_release_path_suites }}" == "true" ]]; then
            export OPENCLAW_DOCKER_ALL_PROFILE=release-path
          fi
          export OPENCLAW_DOCKER_ALL_LOG_DIR=".artifacts/docker-tests/targeted-${{ steps.plan.outputs.artifact_suffix }}"
          export OPENCLAW_DOCKER_ALL_TIMINGS_FILE=".artifacts/docker-tests/targeted-${{ steps.plan.outputs.artifact_suffix }}-timings.json"
          export OPENCLAW_DOCKER_ALL_PNPM_COMMAND="$(command -v pnpm)"
          if [[ "${{ steps.plan.outputs.needs_live_image }}" == "1" ]]; then
            OPENCLAW_DOCKER_BUILD_ON_MISSING=1 OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" bash .release-harness/scripts/test-live-build-docker.sh
          fi
          export OPENCLAW_DOCKER_ALL_BUILD=0

          node .release-harness/scripts/test-docker-all.mjs

      - name: Summarize targeted Docker E2E lanes
        if: always()
        shell: bash
        run: |
          set -euo pipefail
          summary=".artifacts/docker-tests/targeted-${{ steps.plan.outputs.artifact_suffix }}/summary.json"
          if [[ ! -f "$summary" ]]; then
            echo "Docker targeted summary missing: \`$summary\`" >> "$GITHUB_STEP_SUMMARY"
            exit 0
          fi
          node .release-harness/scripts/docker-e2e.mjs summary "$summary" "Docker E2E targeted lanes" >> "$GITHUB_STEP_SUMMARY"

      - name: Upload targeted Docker E2E artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: docker-e2e-${{ steps.plan.outputs.artifact_suffix }}
          path: .artifacts/docker-tests/
          if-no-files-found: ignore

  validate_docker_openwebui:
    needs: [validate_selected_ref, prepare_docker_e2e_image]
    if: inputs.include_openwebui && !inputs.include_release_path_suites && inputs.docker_lanes == ''
    name: Docker E2E (openwebui)
    continue-on-error: ${{ inputs.advisory }}
    runs-on: ${{ inputs.use_github_hosted_runners && 'ubuntu-24.04' || 'blacksmith-32vcpu-ubuntu-2404' }}
    timeout-minutes: 60
    env:
      OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
      OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
      OPENCLAW_DOCKER_E2E_IMAGE: ${{ needs.prepare_docker_e2e_image.outputs.image }}
      OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE: ${{ needs.prepare_docker_e2e_image.outputs.functional_image }}
      OPENCLAW_DOCKER_E2E_PACKAGE_ARTIFACT_NAME: ${{ inputs.package_artifact_name || 'docker-e2e-package' }}
      OPENCLAW_DOCKER_E2E_REPO_ROOT: ${{ github.workspace }}
      OPENCLAW_DOCKER_E2E_SELECTED_SHA: ${{ needs.validate_selected_ref.outputs.selected_sha }}
      OPENCLAW_CURRENT_PACKAGE_TGZ: .artifacts/docker-e2e-package/openclaw-current.tgz
      OPENCLAW_SKIP_DOCKER_BUILD: "1"
    steps:
      - name: Checkout selected ref
        uses: actions/checkout@v6
        with:
          ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
          fetch-depth: 1

      - name: Checkout trusted release harness
        uses: actions/checkout@v6
        with:
          ref: ${{ github.sha }}
          fetch-depth: 1
          path: .release-harness

      - name: Log in to GHCR for shared Docker E2E image
        run: bash .release-harness/scripts/ci-docker-login-ghcr.sh
        env:
          GHCR_USERNAME: ${{ github.actor }}
          GITHUB_TOKEN: ${{ github.token }}

      - name: Setup Node environment
        uses: ./.github/actions/setup-node-env
        with:
          node-version: ${{ env.NODE_VERSION }}
          install-bun: "true"

      - name: Validate Open WebUI credentials
        shell: bash
        run: |
          set -euo pipefail
          [[ -n "${OPENAI_API_KEY:-}" ]] || {
            echo "OPENAI_API_KEY is required for the Open WebUI Docker smoke." >&2
            exit 1
          }

      - name: Plan Open WebUI Docker E2E chunk
        id: plan
        shell: bash
        run: |
          set -euo pipefail
          mkdir -p .artifacts/docker-tests
          export OPENCLAW_DOCKER_ALL_PROFILE=release-path
          export OPENCLAW_DOCKER_ALL_CHUNK=openwebui
          export OPENCLAW_DOCKER_ALL_INCLUDE_OPENWEBUI=true

          plan_path=".artifacts/docker-tests/release-openwebui-plan.json"
          node .release-harness/scripts/test-docker-all.mjs --plan-json > "$plan_path"
          node .release-harness/scripts/docker-e2e.mjs github-outputs "$plan_path" >> "$GITHUB_OUTPUT"
          echo "plan_json=$plan_path" >> "$GITHUB_OUTPUT"

      - name: Download OpenClaw Docker E2E package
        if: steps.plan.outputs.needs_package == '1'
        uses: actions/download-artifact@v8
        with:
          name: ${{ inputs.package_artifact_name || 'docker-e2e-package' }}
          path: .artifacts/docker-e2e-package

      - name: Pull shared bare Docker E2E image
        if: steps.plan.outputs.needs_bare_image == '1'
        shell: bash
        run: |
          set -euo pipefail
          bash .release-harness/scripts/ci-docker-pull-retry.sh "${OPENCLAW_DOCKER_E2E_BARE_IMAGE}"

      - name: Pull shared functional Docker E2E image
        if: steps.plan.outputs.needs_functional_image == '1'
        shell: bash
        run: |
          set -euo pipefail
          bash .release-harness/scripts/ci-docker-pull-retry.sh "${OPENCLAW_DOCKER_E2E_FUNCTIONAL_IMAGE}"

      - name: Run Open WebUI Docker E2E chunk
        shell: bash
        run: |
          set -euo pipefail
          export OPENCLAW_DOCKER_ALL_PROFILE=release-path
          export OPENCLAW_DOCKER_ALL_CHUNK=openwebui
          export OPENCLAW_DOCKER_ALL_BUILD=0
          export OPENCLAW_DOCKER_ALL_PREFLIGHT=0
          export OPENCLAW_DOCKER_ALL_FAIL_FAST=0
          export OPENCLAW_DOCKER_ALL_INCLUDE_OPENWEBUI=1
          export OPENCLAW_DOCKER_ALL_LOG_DIR=".artifacts/docker-tests/release-openwebui"
          export OPENCLAW_DOCKER_ALL_TIMINGS_FILE=".artifacts/docker-tests/release-openwebui-timings.json"
          export OPENCLAW_DOCKER_ALL_PNPM_COMMAND="$(command -v pnpm)"
          if [[ "${{ steps.plan.outputs.needs_live_image }}" == "1" ]]; then
            OPENCLAW_DOCKER_BUILD_ON_MISSING=1 OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" bash .release-harness/scripts/test-live-build-docker.sh
          fi

          node .release-harness/scripts/test-docker-all.mjs

      - name: Summarize Open WebUI Docker E2E chunk
        if: always()
        shell: bash
        run: |
          set -euo pipefail
          summary=".artifacts/docker-tests/release-openwebui/summary.json"
          if [[ ! -f "$summary" ]]; then
            echo "Docker Open WebUI summary missing: \`$summary\`" >> "$GITHUB_STEP_SUMMARY"
            exit 0
          fi
          node .release-harness/scripts/docker-e2e.mjs summary "$summary" "Docker E2E chunk: openwebui" >> "$GITHUB_STEP_SUMMARY"

      - name: Upload Open WebUI Docker E2E artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: docker-e2e-openwebui
          path: .artifacts/docker-tests/
          if-no-files-found: ignore

  prepare_docker_e2e_image:
    needs: validate_selected_ref
    if: inputs.include_release_path_suites || inputs.include_openwebui || inputs.docker_lanes != ''
    continue-on-error: ${{ inputs.advisory }}
    runs-on: ${{ inputs.use_github_hosted_runners && 'ubuntu-24.04' || 'blacksmith-32vcpu-ubuntu-2404' }}
    timeout-minutes: ${{ inputs.release_test_profile == 'full' && 90 || 60 }}
    permissions:
      actions: read
      contents: read
      packages: write
    outputs:
      image: ${{ steps.image.outputs.image }}
      bare_image: ${{ steps.image.outputs.bare_image }}
      functional_image: ${{ steps.image.outputs.functional_image }}
      needs_bare_image: ${{ steps.plan.outputs.needs_bare_image }}
      needs_e2e_image: ${{ steps.plan.outputs.needs_e2e_image }}
      needs_functional_image: ${{ steps.plan.outputs.needs_functional_image }}
      needs_live_image: ${{ steps.plan.outputs.needs_live_image }}
      needs_package: ${{ steps.plan.outputs.needs_package }}
    env:
      DOCKER_BUILD_SUMMARY: "false"
      DOCKER_BUILD_RECORD_UPLOAD: "false"
      OPENCLAW_DOCKER_E2E_REPO_ROOT: ${{ github.workspace }}
    steps:
      - name: Checkout selected ref
        uses: actions/checkout@v6
        with:
          ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
          fetch-depth: 1

      - name: Checkout trusted release harness
        uses: actions/checkout@v6
        with:
          ref: ${{ github.sha }}
          fetch-depth: 1
          path: .release-harness

      - name: Plan Docker E2E images
        id: plan
        shell: bash
        env:
          LANES: ${{ inputs.docker_lanes }}
          INCLUDE_RELEASE_PATH_SUITES: ${{ inputs.include_release_path_suites }}
          INCLUDE_OPENWEBUI: ${{ inputs.include_openwebui }}
          RELEASE_TEST_PROFILE: ${{ inputs.release_test_profile }}
          OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPEC: ${{ inputs.published_upgrade_survivor_baseline }}
          OPENCLAW_UPGRADE_SURVIVOR_BASELINE_SPECS: ${{ inputs.published_upgrade_survivor_baselines }}
          OPENCLAW_UPGRADE_SURVIVOR_SCENARIOS: ${{ inputs.published_upgrade_survivor_scenarios }}
        run: |
          set -euo pipefail
          mkdir -p .artifacts/docker-tests

          if [[ "$INCLUDE_RELEASE_PATH_SUITES" == "true" ]]; then
            export OPENCLAW_DOCKER_ALL_PROFILE=release-path
            export OPENCLAW_DOCKER_ALL_PLAN_RELEASE_ALL=1
          elif [[ -n "$LANES" ]]; then
            export OPENCLAW_DOCKER_ALL_LANES="$LANES"
          elif [[ "$INCLUDE_OPENWEBUI" == "true" ]]; then
            export OPENCLAW_DOCKER_ALL_LANES=openwebui
          fi
          export OPENCLAW_DOCKER_ALL_INCLUDE_OPENWEBUI="$INCLUDE_OPENWEBUI"
          export OPENCLAW_DOCKER_ALL_RELEASE_PROFILE="$RELEASE_TEST_PROFILE"

          plan_path=".artifacts/docker-tests/plan.json"
          node .release-harness/scripts/test-docker-all.mjs --plan-json > "$plan_path"
          node .release-harness/scripts/docker-e2e.mjs github-outputs "$plan_path" >> "$GITHUB_OUTPUT"
          echo "plan_json=$plan_path" >> "$GITHUB_OUTPUT"

      - name: Setup Node environment
        if: steps.plan.outputs.needs_package == '1' && inputs.package_artifact_name == '' && inputs.package_artifact_run_id == ''
        uses: ./.github/actions/setup-node-env
        with:
          node-version: ${{ env.NODE_VERSION }}
          install-bun: "true"

      - name: Download current-run OpenClaw Docker E2E package
        if: steps.plan.outputs.needs_package == '1' && inputs.package_artifact_name != '' && inputs.package_artifact_run_id == ''
        uses: actions/download-artifact@v8
        with:
          name: ${{ inputs.package_artifact_name }}
          path: .artifacts/docker-e2e-package

      - name: Download previous-run OpenClaw Docker E2E package
        if: steps.plan.outputs.needs_package == '1' && inputs.package_artifact_run_id != ''
        uses: actions/download-artifact@v8
        with:
          name: ${{ inputs.package_artifact_name || 'docker-e2e-package' }}
          path: .artifacts/docker-e2e-package
          run-id: ${{ inputs.package_artifact_run_id }}
          github-token: ${{ github.token }}

      - name: Pack OpenClaw package for Docker E2E
        if: steps.plan.outputs.needs_package == '1' && inputs.package_artifact_name == '' && inputs.package_artifact_run_id == ''
        shell: bash
        run: |
          set -euo pipefail
          mkdir -p .artifacts/docker-e2e-package
          node scripts/package-openclaw-for-docker.mjs \
            --output-dir .artifacts/docker-e2e-package \
            --output-name openclaw-current.tgz

      - name: Validate OpenClaw Docker E2E package
        id: package
        if: steps.plan.outputs.needs_package == '1'
        shell: bash
        run: |
          set -euo pipefail
          mkdir -p .artifacts/docker-e2e-package
          target=".artifacts/docker-e2e-package/openclaw-current.tgz"
          if [[ ! -f "$target" ]]; then
            mapfile -t tgzs < <(find .artifacts/docker-e2e-package -type f -name '*.tgz' | sort)
            if [[ "${#tgzs[@]}" -ne 1 ]]; then
              echo "Expected exactly one package tarball in .artifacts/docker-e2e-package; found ${#tgzs[@]}." >&2
              printf '%s\n' "${tgzs[@]}" >&2
              exit 1
            fi
            cp "${tgzs[0]}" "$target"
          fi
          echo "Validating Docker E2E package tarball: $target"
          started_at="$(date +%s)"
          timeout --foreground 5m node scripts/check-openclaw-package-tarball.mjs "$target"
          finished_at="$(date +%s)"
          echo "Docker E2E package tarball validation finished in $((finished_at - started_at))s."
          digest="$(sha256sum "$target" | awk '{print $1}')"
          tag="pkg-${digest:0:32}"
          echo "sha256=$digest" >> "$GITHUB_OUTPUT"
          echo "tag=$tag" >> "$GITHUB_OUTPUT"
          {
            echo "Docker E2E package: \`$target\`"
            echo "Docker E2E package SHA-256: \`$digest\`"
          } >> "$GITHUB_STEP_SUMMARY"

      - name: Upload OpenClaw Docker E2E package
        if: steps.plan.outputs.needs_package == '1' && (inputs.package_artifact_name == '' || inputs.package_artifact_run_id != '')
        uses: actions/upload-artifact@v7
        with:
          name: ${{ inputs.package_artifact_name || 'docker-e2e-package' }}
          path: .artifacts/docker-e2e-package/openclaw-current.tgz
          if-no-files-found: error

      - name: Resolve shared Docker E2E image tags
        id: image
        shell: bash
        env:
          PACKAGE_TAG: ${{ steps.package.outputs.tag }}
          SELECTED_SHA: ${{ needs.validate_selected_ref.outputs.selected_sha }}
          PROVIDED_BARE_IMAGE: ${{ inputs.docker_e2e_bare_image }}
          PROVIDED_FUNCTIONAL_IMAGE: ${{ inputs.docker_e2e_functional_image }}
        run: |
          set -euo pipefail
          repository="${GITHUB_REPOSITORY,,}"
          image_tag="${PACKAGE_TAG:-$SELECTED_SHA}"
          bare_image="${PROVIDED_BARE_IMAGE:-ghcr.io/${repository}-docker-e2e-bare:${image_tag}}"
          functional_image="${PROVIDED_FUNCTIONAL_IMAGE:-ghcr.io/${repository}-docker-e2e-functional:${image_tag}}"
          image="$functional_image"
          echo "image=$image" >> "$GITHUB_OUTPUT"
          echo "bare_image=$bare_image" >> "$GITHUB_OUTPUT"
          echo "functional_image=$functional_image" >> "$GITHUB_OUTPUT"
          echo "Shared Docker E2E bare image: \`$bare_image\`" >> "$GITHUB_STEP_SUMMARY"
          echo "Shared Docker E2E functional image: \`$functional_image\`" >> "$GITHUB_STEP_SUMMARY"

      - name: Log in to GHCR
        if: steps.plan.outputs.needs_e2e_image == '1'
        run: bash .release-harness/scripts/ci-docker-login-ghcr.sh
        env:
          GHCR_USERNAME: ${{ github.actor }}
          GITHUB_TOKEN: ${{ github.token }}

      - name: Check existing shared Docker E2E images
        id: image_exists
        if: steps.plan.outputs.needs_e2e_image == '1'
        shell: bash
        env:
          PROVIDED_BARE_IMAGE: ${{ inputs.docker_e2e_bare_image }}
          PROVIDED_FUNCTIONAL_IMAGE: ${{ inputs.docker_e2e_functional_image }}
        run: |
          set -euo pipefail
          bare_exists=0
          functional_exists=0
          needs_build=0

          if [[ "${{ steps.plan.outputs.needs_bare_image }}" == "1" ]]; then
            if docker manifest inspect "${{ steps.image.outputs.bare_image }}" >/dev/null 2>&1; then
              bare_exists=1
              echo "Shared Docker E2E bare image already exists: ${{ steps.image.outputs.bare_image }}"
            elif [[ -n "$PROVIDED_BARE_IMAGE" ]]; then
              echo "Provided bare Docker E2E image does not exist: $PROVIDED_BARE_IMAGE" >&2
              exit 1
            else
              needs_build=1
            fi
          fi

          if [[ "${{ steps.plan.outputs.needs_functional_image }}" == "1" ]]; then
            if docker manifest inspect "${{ steps.image.outputs.functional_image }}" >/dev/null 2>&1; then
              functional_exists=1
              echo "Shared Docker E2E functional image already exists: ${{ steps.image.outputs.functional_image }}"
            elif [[ -n "$PROVIDED_FUNCTIONAL_IMAGE" ]]; then
              echo "Provided functional Docker E2E image does not exist: $PROVIDED_FUNCTIONAL_IMAGE" >&2
              exit 1
            else
              needs_build=1
            fi
          fi

          echo "bare_exists=$bare_exists" >> "$GITHUB_OUTPUT"
          echo "functional_exists=$functional_exists" >> "$GITHUB_OUTPUT"
          echo "needs_build=$needs_build" >> "$GITHUB_OUTPUT"

      - name: Setup Docker builder
        if: steps.image_exists.outputs.needs_build == '1'
        uses: useblacksmith/setup-docker-builder@722e97d12b1d06a961800dd6c05d79d951ad3c80 # v1
        with:
          max-cache-size-mb: 800000

      - name: Build and push bare Docker E2E image
        if: steps.plan.outputs.needs_bare_image == '1' && steps.image_exists.outputs.bare_exists != '1'
        uses: useblacksmith/build-push-action@fb9e3e6a9299c78462bfadd0d93352c316adc9b8 # v2
        with:
          context: .
          file: ./scripts/e2e/Dockerfile
          target: bare
          platforms: linux/amd64
          tags: ${{ steps.image.outputs.bare_image }}
          sbom: true
          provenance: mode=max
          push: true

      - name: Build and push functional Docker E2E image
        if: steps.plan.outputs.needs_functional_image == '1' && steps.image_exists.outputs.functional_exists != '1'
        uses: useblacksmith/build-push-action@fb9e3e6a9299c78462bfadd0d93352c316adc9b8 # v2
        with:
          context: .
          file: ./scripts/e2e/Dockerfile
          target: functional
          build-contexts: |
            openclaw_package=.artifacts/docker-e2e-package
          platforms: linux/amd64
          tags: ${{ steps.image.outputs.functional_image }}
          sbom: true
          provenance: mode=max
          push: true

  prepare_live_test_image:
    needs: validate_selected_ref
    if: inputs.include_live_suites && (inputs.live_suite_filter == '' || startsWith(inputs.live_suite_filter, 'live-') || startsWith(inputs.live_suite_filter, 'docker-live-models'))
    continue-on-error: ${{ inputs.advisory }}
    runs-on: ${{ inputs.use_github_hosted_runners && 'ubuntu-24.04' || 'blacksmith-32vcpu-ubuntu-2404' }}
    timeout-minutes: 60
    permissions:
      contents: read
      packages: write
    outputs:
      live_image: ${{ steps.image.outputs.live_image }}
    env:
      DOCKER_BUILD_SUMMARY: "false"
      DOCKER_BUILD_RECORD_UPLOAD: "false"
    steps:
      - name: Checkout selected ref
        uses: actions/checkout@v6
        with:
          ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
          fetch-depth: 1

      - name: Resolve shared live-test image tag
        id: image
        shell: bash
        env:
          SELECTED_SHA: ${{ needs.validate_selected_ref.outputs.selected_sha }}
        run: |
          set -euo pipefail
          repository="${GITHUB_REPOSITORY,,}"
          live_image="ghcr.io/${repository}-live-test:${SELECTED_SHA}"
          echo "live_image=${live_image}" >> "$GITHUB_OUTPUT"
          echo "Shared live-test image: \`${live_image}\`" >> "$GITHUB_STEP_SUMMARY"

      - name: Log in to GHCR
        run: bash scripts/ci-docker-login-ghcr.sh
        env:
          GHCR_USERNAME: ${{ github.actor }}
          GITHUB_TOKEN: ${{ github.token }}

      - name: Check existing shared live-test image
        id: image_exists
        shell: bash
        run: |
          set -euo pipefail
          if docker manifest inspect "${{ steps.image.outputs.live_image }}" >/dev/null 2>&1; then
            echo "Shared live-test image already exists: ${{ steps.image.outputs.live_image }}"
            echo "exists=1" >> "$GITHUB_OUTPUT"
          else
            echo "exists=0" >> "$GITHUB_OUTPUT"
          fi

      - name: Setup Docker builder
        if: steps.image_exists.outputs.exists != '1'
        uses: useblacksmith/setup-docker-builder@722e97d12b1d06a961800dd6c05d79d951ad3c80 # v1
        with:
          max-cache-size-mb: 800000

      - name: Build and push shared live-test image
        if: steps.image_exists.outputs.exists != '1'
        uses: useblacksmith/build-push-action@fb9e3e6a9299c78462bfadd0d93352c316adc9b8 # v2
        with:
          context: .
          file: ./Dockerfile
          target: build
          build-args: |
            OPENCLAW_EXTENSIONS=matrix
          platforms: linux/amd64
          tags: ${{ steps.image.outputs.live_image }}
          sbom: true
          provenance: mode=max
          push: true

  validate_live_models_docker:
    name: Docker live models (${{ matrix.provider_label }})
    needs: [validate_selected_ref, prepare_live_test_image, plan_release_workflow_matrices]
    if: inputs.include_live_suites && inputs.live_model_providers == '' && (inputs.live_suite_filter == '' || inputs.live_suite_filter == 'docker-live-models') && needs.plan_release_workflow_matrices.outputs.live_models_count != '0'
    continue-on-error: ${{ inputs.advisory }}
    runs-on: ${{ inputs.use_github_hosted_runners && 'ubuntu-24.04' || 'blacksmith-32vcpu-ubuntu-2404' }}
    timeout-minutes: 45
    strategy:
      fail-fast: false
      matrix: ${{ fromJson(needs.plan_release_workflow_matrices.outputs.live_models_matrix) }}
    env:
      OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
      OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
      ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
      ANTHROPIC_API_TOKEN: ${{ secrets.ANTHROPIC_API_TOKEN }}
      ANTHROPIC_API_KEY_OLD: ${{ secrets.ANTHROPIC_API_KEY_OLD }}
      BYTEPLUS_API_KEY: ${{ secrets.BYTEPLUS_API_KEY }}
      CEREBRAS_API_KEY: ${{ secrets.CEREBRAS_API_KEY }}
      DEEPINFRA_API_KEY: ${{ secrets.DEEPINFRA_API_KEY }}
      DASHSCOPE_API_KEY: ${{ secrets.DASHSCOPE_API_KEY }}
      GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
      KIMI_API_KEY: ${{ secrets.KIMI_API_KEY }}
      MODELSTUDIO_API_KEY: ${{ secrets.MODELSTUDIO_API_KEY }}
      MOONSHOT_API_KEY: ${{ secrets.MOONSHOT_API_KEY }}
      MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
      MINIMAX_API_KEY: ${{ secrets.MINIMAX_API_KEY }}
      OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
      OPENCODE_ZEN_API_KEY: ${{ secrets.OPENCODE_ZEN_API_KEY }}
      GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
      GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
      OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
      QWEN_API_KEY: ${{ secrets.QWEN_API_KEY }}
      XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
      ZAI_API_KEY: ${{ secrets.ZAI_API_KEY }}
      Z_AI_API_KEY: ${{ secrets.Z_AI_API_KEY }}
      CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
      OPENCLAW_CODEX_AUTH_JSON: ${{ secrets.OPENCLAW_CODEX_AUTH_JSON }}
      OPENCLAW_CODEX_CONFIG_TOML: ${{ secrets.OPENCLAW_CODEX_CONFIG_TOML }}
      OPENCLAW_CLAUDE_JSON: ${{ secrets.OPENCLAW_CLAUDE_JSON }}
      OPENCLAW_CLAUDE_CREDENTIALS_JSON: ${{ secrets.OPENCLAW_CLAUDE_CREDENTIALS_JSON }}
      OPENCLAW_CLAUDE_SETTINGS_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_JSON }}
      OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON }}
      OPENCLAW_GEMINI_SETTINGS_JSON: ${{ secrets.OPENCLAW_GEMINI_SETTINGS_JSON }}
      FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}
      OPENCLAW_LIVE_PROVIDERS: ${{ matrix.providers }}
      OPENCLAW_LIVE_IMAGE: ${{ needs.prepare_live_test_image.outputs.live_image }}
      OPENCLAW_LIVE_MAX_MODELS: "6"
      OPENCLAW_LIVE_MODEL_TIMEOUT_MS: "45000"
      OPENCLAW_SKIP_DOCKER_BUILD: "1"
      OPENCLAW_VITEST_MAX_WORKERS: "2"
    steps:
      - name: Checkout selected ref
        if: contains(matrix.profiles, inputs.release_test_profile)
        uses: actions/checkout@v6
        with:
          ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
          fetch-depth: 1

      - name: Checkout trusted live Docker harness
        if: contains(matrix.profiles, inputs.release_test_profile)
        uses: actions/checkout@v6
        with:
          ref: ${{ github.sha }}
          fetch-depth: 1
          path: .release-harness

      - name: Setup Node environment
        if: contains(matrix.profiles, inputs.release_test_profile)
        uses: ./.github/actions/setup-node-env
        with:
          node-version: ${{ env.NODE_VERSION }}
          install-bun: "true"

      - name: Hydrate live auth/profile inputs
        if: contains(matrix.profiles, inputs.release_test_profile)
        run: bash scripts/ci-hydrate-live-auth.sh

      - name: Log in to GHCR
        if: contains(matrix.profiles, inputs.release_test_profile)
        run: bash .release-harness/scripts/ci-docker-login-ghcr.sh
        env:
          GHCR_USERNAME: ${{ github.actor }}
          GITHUB_TOKEN: ${{ github.token }}

      - name: Validate provider credential
        if: contains(matrix.profiles, inputs.release_test_profile)
        shell: bash
        env:
          LIVE_MODEL_PROVIDERS: ${{ matrix.providers }}
        run: |
          set -euo pipefail

          require_any() {
            local label="$1"
            shift
            local key
            for key in "$@"; do
              if [[ -n "${!key:-}" ]]; then
                return 0
              fi
            done
            echo "Missing credential for ${label}: expected one of $*" >&2
            exit 1
          }

          case "${LIVE_MODEL_PROVIDERS}" in
            anthropic) require_any Anthropic ANTHROPIC_API_KEY ANTHROPIC_API_KEY_OLD ANTHROPIC_API_TOKEN ;;
            google) require_any Google GEMINI_API_KEY GOOGLE_API_KEY ;;
            minimax) require_any MiniMax MINIMAX_API_KEY ;;
            openai) require_any OpenAI OPENAI_API_KEY ;;
            opencode-go) require_any OpenCode OPENCODE_API_KEY OPENCODE_ZEN_API_KEY ;;
            openrouter) require_any OpenRouter OPENROUTER_API_KEY ;;
            xai) require_any xAI XAI_API_KEY ;;
            zai) require_any Z.ai ZAI_API_KEY Z_AI_API_KEY ;;
            fireworks) require_any Fireworks FIREWORKS_API_KEY ;;
            *)
              echo "Unhandled live model provider shard: ${LIVE_MODEL_PROVIDERS}" >&2
              exit 1
              ;;
          esac

      - name: Run Docker live model sweep
        if: contains(matrix.profiles, inputs.release_test_profile)
        run: OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" timeout --foreground --kill-after=30s 35m bash .release-harness/scripts/test-live-models-docker.sh

  validate_live_models_docker_targeted:
    name: Docker live models (selected providers)
    needs: [validate_selected_ref, prepare_live_test_image]
    if: inputs.include_live_suites && inputs.live_model_providers != '' && (inputs.live_suite_filter == '' || inputs.live_suite_filter == 'docker-live-models')
    continue-on-error: ${{ inputs.advisory }}
    runs-on: ${{ inputs.use_github_hosted_runners && 'ubuntu-24.04' || 'blacksmith-32vcpu-ubuntu-2404' }}
    timeout-minutes: 45
    env:
      OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
      OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
      ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
      ANTHROPIC_API_TOKEN: ${{ secrets.ANTHROPIC_API_TOKEN }}
      ANTHROPIC_API_KEY_OLD: ${{ secrets.ANTHROPIC_API_KEY_OLD }}
      BYTEPLUS_API_KEY: ${{ secrets.BYTEPLUS_API_KEY }}
      CEREBRAS_API_KEY: ${{ secrets.CEREBRAS_API_KEY }}
      DEEPINFRA_API_KEY: ${{ secrets.DEEPINFRA_API_KEY }}
      DASHSCOPE_API_KEY: ${{ secrets.DASHSCOPE_API_KEY }}
      GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
      KIMI_API_KEY: ${{ secrets.KIMI_API_KEY }}
      MODELSTUDIO_API_KEY: ${{ secrets.MODELSTUDIO_API_KEY }}
      MOONSHOT_API_KEY: ${{ secrets.MOONSHOT_API_KEY }}
      MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
      MINIMAX_API_KEY: ${{ secrets.MINIMAX_API_KEY }}
      OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
      OPENCODE_ZEN_API_KEY: ${{ secrets.OPENCODE_ZEN_API_KEY }}
      GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
      GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
      OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
      QWEN_API_KEY: ${{ secrets.QWEN_API_KEY }}
      XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
      ZAI_API_KEY: ${{ secrets.ZAI_API_KEY }}
      Z_AI_API_KEY: ${{ secrets.Z_AI_API_KEY }}
      CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
      OPENCLAW_CODEX_AUTH_JSON: ${{ secrets.OPENCLAW_CODEX_AUTH_JSON }}
      OPENCLAW_CODEX_CONFIG_TOML: ${{ secrets.OPENCLAW_CODEX_CONFIG_TOML }}
      OPENCLAW_CLAUDE_JSON: ${{ secrets.OPENCLAW_CLAUDE_JSON }}
      OPENCLAW_CLAUDE_CREDENTIALS_JSON: ${{ secrets.OPENCLAW_CLAUDE_CREDENTIALS_JSON }}
      OPENCLAW_CLAUDE_SETTINGS_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_JSON }}
      OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON }}
      OPENCLAW_GEMINI_SETTINGS_JSON: ${{ secrets.OPENCLAW_GEMINI_SETTINGS_JSON }}
      FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}
      REQUESTED_LIVE_MODEL_PROVIDERS: ${{ inputs.live_model_providers }}
      OPENCLAW_LIVE_IMAGE: ${{ needs.prepare_live_test_image.outputs.live_image }}
      OPENCLAW_LIVE_MAX_MODELS: "6"
      OPENCLAW_LIVE_MODEL_TIMEOUT_MS: "45000"
      OPENCLAW_SKIP_DOCKER_BUILD: "1"
      OPENCLAW_VITEST_MAX_WORKERS: "2"
    steps:
      - name: Checkout selected ref
        uses: actions/checkout@v6
        with:
          ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
          fetch-depth: 1

      - name: Checkout trusted live Docker harness
        uses: actions/checkout@v6
        with:
          ref: ${{ github.sha }}
          fetch-depth: 1
          path: .release-harness

      - name: Setup Node environment
        uses: ./.github/actions/setup-node-env
        with:
          node-version: ${{ env.NODE_VERSION }}
          install-bun: "true"

      - name: Normalize provider allowlist
        shell: bash
        run: |
          set -euo pipefail

          all_providers=(anthropic google minimax openai opencode-go openrouter xai zai fireworks)

          normalize_provider() {
            local value="${1,,}"
            case "$value" in
              opencode|opencode-go) echo "opencode-go" ;;
              open-router|openrouter) echo "openrouter" ;;
              *) echo "$value" ;;
            esac
          }

          is_known_provider() {
            local value="$1"
            local provider
            for provider in "${all_providers[@]}"; do
              [[ "$provider" == "$value" ]] && return 0
            done
            return 1
          }

          selected=()
          declare -A seen=()
          raw="${REQUESTED_LIVE_MODEL_PROVIDERS:-}"
          normalized_all="${raw,,}"
          normalized_all="${normalized_all//[[:space:],]/}"
          if [[ -z "$normalized_all" || "$normalized_all" == "all" ]]; then
            selected=("${all_providers[@]}")
          else
            while IFS= read -r entry; do
              [[ -z "$entry" ]] && continue
              provider="$(normalize_provider "$entry")"
              if ! is_known_provider "$provider"; then
                echo "Unknown live model provider '${entry}'. Expected one of: ${all_providers[*]}" >&2
                exit 1
              fi
              if [[ -z "${seen[$provider]:-}" ]]; then
                selected+=("$provider")
                seen[$provider]=1
              fi
            done < <(printf '%s\n' "$raw" | tr ',' '\n' | tr '[:space:]' '\n')
          fi

          if [[ "${#selected[@]}" -eq 0 ]]; then
            echo "No live model providers selected." >&2
            exit 1
          fi

          providers_csv="$(IFS=,; echo "${selected[*]}")"
          echo "OPENCLAW_LIVE_PROVIDERS=$providers_csv" >> "$GITHUB_ENV"
          {
            echo "Live model providers: \`$providers_csv\`"
          } >> "$GITHUB_STEP_SUMMARY"

      - name: Hydrate live auth/profile inputs
        run: bash scripts/ci-hydrate-live-auth.sh

      - name: Log in to GHCR
        run: bash .release-harness/scripts/ci-docker-login-ghcr.sh
        env:
          GHCR_USERNAME: ${{ github.actor }}
          GITHUB_TOKEN: ${{ github.token }}

      - name: Validate provider credentials
        shell: bash
        run: |
          set -euo pipefail

          require_any() {
            local label="$1"
            shift
            local key
            for key in "$@"; do
              if [[ -n "${!key:-}" ]]; then
                return 0
              fi
            done
            echo "Missing credential for ${label}: expected one of $*" >&2
            exit 1
          }

          IFS=',' read -r -a providers <<<"${OPENCLAW_LIVE_PROVIDERS}"
          for provider in "${providers[@]}"; do
            case "$provider" in
              anthropic) require_any Anthropic ANTHROPIC_API_KEY ANTHROPIC_API_KEY_OLD ANTHROPIC_API_TOKEN ;;
              google) require_any Google GEMINI_API_KEY GOOGLE_API_KEY ;;
              minimax) require_any MiniMax MINIMAX_API_KEY ;;
              openai) require_any OpenAI OPENAI_API_KEY ;;
              opencode-go) require_any OpenCode OPENCODE_API_KEY OPENCODE_ZEN_API_KEY ;;
              openrouter) require_any OpenRouter OPENROUTER_API_KEY ;;
              xai) require_any xAI XAI_API_KEY ;;
              zai) require_any Z.ai ZAI_API_KEY Z_AI_API_KEY ;;
              fireworks) require_any Fireworks FIREWORKS_API_KEY ;;
              *)
                echo "Unhandled live model provider shard: ${provider}" >&2
                exit 1
                ;;
            esac
          done

      - name: Run Docker live model sweep
        run: OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" timeout --foreground --kill-after=30s 35m bash .release-harness/scripts/test-live-models-docker.sh

  validate_live_provider_suites:
    needs: validate_selected_ref
    if: inputs.include_live_suites && !inputs.live_models_only && (inputs.live_suite_filter == '' || (startsWith(inputs.live_suite_filter, 'native-live-') && !startsWith(inputs.live_suite_filter, 'native-live-extensions-media') && inputs.live_suite_filter != 'native-live-extensions-a-k'))
    continue-on-error: ${{ inputs.advisory }}
    runs-on: ${{ inputs.use_github_hosted_runners && 'ubuntu-24.04' || 'blacksmith-8vcpu-ubuntu-2404' }}
    timeout-minutes: ${{ matrix.timeout_minutes }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - suite_id: native-live-src-agents
            label: Native live agents
            command: node .release-harness/scripts/test-live-shard.mjs native-live-src-agents
            timeout_minutes: 60
            profile_env_only: false
            profiles: stable full
          - suite_id: native-live-src-gateway-core
            label: Native live gateway core
            command: node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-core
            timeout_minutes: 60
            profile_env_only: false
            profiles: beta minimum stable full
          - suite_id: native-live-src-gateway-profiles-anthropic-smoke
            suite_group: native-live-src-gateway-profiles-anthropic
            label: Native live gateway profiles Anthropic smoke
            command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=anthropic OPENCLAW_LIVE_GATEWAY_SMOKE=1 OPENCLAW_LIVE_GATEWAY_MAX_MODELS=1 node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
            timeout_minutes: 45
            profile_env_only: false
            profiles: stable
          - suite_id: native-live-src-gateway-profiles-anthropic-opus
            suite_group: native-live-src-gateway-profiles-anthropic
            label: Native live gateway profiles Anthropic Opus
            command: OPENCLAW_LIVE_GATEWAY_THINKING=low OPENCLAW_LIVE_GATEWAY_PROVIDERS=anthropic OPENCLAW_LIVE_GATEWAY_MODELS=anthropic/claude-opus-4-8 node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
            timeout_minutes: 30
            profile_env_only: false
            advisory: true
            profiles: full
          - suite_id: native-live-src-gateway-profiles-anthropic-sonnet-haiku
            suite_group: native-live-src-gateway-profiles-anthropic
            label: Native live gateway profiles Anthropic Sonnet/Haiku
            command: OPENCLAW_LIVE_GATEWAY_THINKING=low OPENCLAW_LIVE_GATEWAY_PROVIDERS=anthropic OPENCLAW_LIVE_GATEWAY_MODELS=anthropic/claude-sonnet-4-6,anthropic/claude-haiku-4-5 node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
            timeout_minutes: 30
            profile_env_only: false
            advisory: true
            profiles: full
          - suite_id: native-live-src-gateway-profiles-google
            label: Native live gateway profiles Google
            command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=google OPENCLAW_LIVE_GATEWAY_MODELS=google/gemini-3.1-pro-preview node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
            timeout_minutes: 60
            profile_env_only: false
            profiles: stable full
          - suite_id: native-live-src-gateway-profiles-minimax
            label: Native live gateway profiles MiniMax
            command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=minimax,minimax-portal OPENCLAW_LIVE_GATEWAY_MODELS=minimax/MiniMax-M2.7,minimax-portal/MiniMax-M2.7 OPENCLAW_LIVE_GATEWAY_MAX_MODELS=2 node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
            timeout_minutes: 60
            profile_env_only: false
            profiles: stable full
          - suite_id: native-live-src-gateway-profiles-openai
            label: Native live gateway profiles OpenAI
            command: OPENCLAW_LIVE_GATEWAY_THINKING=off OPENCLAW_LIVE_GATEWAY_PROVIDERS=openai OPENCLAW_LIVE_GATEWAY_MODELS=openai/gpt-5.5 OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=180000 OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=600000 node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
            timeout_minutes: 60
            profile_env_only: false
            profiles: beta minimum stable full
          - suite_id: native-live-src-gateway-profiles-fireworks
            label: Native live gateway profiles Fireworks
            command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=fireworks node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
            timeout_minutes: 30
            profile_env_only: false
            advisory: true
            profiles: full
          - suite_id: native-live-src-gateway-profiles-deepseek
            label: Native live gateway profiles DeepSeek
            command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=deepseek node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
            timeout_minutes: 30
            profile_env_only: false
            advisory: true
            profiles: full
          - suite_id: native-live-src-gateway-profiles-opencode-go-deepseek-glm
            suite_group: native-live-src-gateway-profiles-opencode-go
            label: Native live gateway profiles OpenCode Go DeepSeek/GLM
            command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=opencode-go OPENCLAW_LIVE_GATEWAY_MODELS=opencode-go/deepseek-v4-flash,opencode-go/deepseek-v4-pro,opencode-go/glm-5,opencode-go/glm-5.1 node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
            timeout_minutes: 30
            profile_env_only: false
            advisory: true
            profiles: full
          - suite_id: native-live-src-gateway-profiles-opencode-go-kimi
            suite_group: native-live-src-gateway-profiles-opencode-go
            label: Native live gateway profiles OpenCode Go Kimi
            command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=opencode-go OPENCLAW_LIVE_GATEWAY_MODELS=opencode-go/kimi-k2.5,opencode-go/kimi-k2.6 node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
            timeout_minutes: 30
            profile_env_only: false
            advisory: true
            profiles: full
          - suite_id: native-live-src-gateway-profiles-opencode-go-mimo
            suite_group: native-live-src-gateway-profiles-opencode-go
            label: Native live gateway profiles OpenCode Go MiMo
            command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=opencode-go OPENCLAW_LIVE_GATEWAY_MODELS=opencode-go/mimo-v2-omni,opencode-go/mimo-v2-pro,opencode-go/mimo-v2.5,opencode-go/mimo-v2.5-pro node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
            timeout_minutes: 30
            profile_env_only: false
            advisory: true
            profiles: full
          - suite_id: native-live-src-gateway-profiles-opencode-go-minimax-qwen
            suite_group: native-live-src-gateway-profiles-opencode-go
            label: Native live gateway profiles OpenCode Go MiniMax/Qwen
            command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=opencode-go OPENCLAW_LIVE_GATEWAY_MODELS=opencode-go/minimax-m2.5,opencode-go/minimax-m2.7,opencode-go/qwen3.5-plus,opencode-go/qwen3.6-plus node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
            timeout_minutes: 30
            profile_env_only: false
            advisory: true
            profiles: full
          - suite_id: native-live-src-gateway-profiles-opencode-go-smoke
            label: Native live gateway profiles OpenCode Go smoke
            command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=opencode-go OPENCLAW_LIVE_GATEWAY_SMOKE=1 OPENCLAW_LIVE_GATEWAY_MAX_MODELS=1 node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
            timeout_minutes: 45
            profile_env_only: false
            profiles: stable
          - suite_id: native-live-src-gateway-profiles-openrouter
            label: Native live gateway profiles OpenRouter
            command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=openrouter node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
            timeout_minutes: 30
            profile_env_only: false
            advisory: true
            profiles: full
          - suite_id: native-live-src-gateway-profiles-xai
            label: Native live gateway profiles xAI
            command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=xai node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
            timeout_minutes: 30
            profile_env_only: false
            advisory: true
            profiles: full
          - suite_id: native-live-src-gateway-profiles-zai
            label: Native live gateway profiles Z.ai
            command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=zai node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-profiles
            timeout_minutes: 30
            profile_env_only: false
            advisory: true
            profiles: full
          - suite_id: native-live-src-gateway-backends
            label: Native live gateway backends
            command: node .release-harness/scripts/test-live-shard.mjs native-live-src-gateway-backends
            timeout_minutes: 60
            profile_env_only: false
            profiles: stable full
          - suite_id: native-live-src-infra
            label: Native live infra
            command: OPENCLAW_LIVE_APNS_REACHABILITY=1 node .release-harness/scripts/test-live-shard.mjs native-live-src-infra
            timeout_minutes: 45
            profile_env_only: false
            profiles: stable full
          - suite_id: native-live-test
            label: Native live test harnesses
            command: node .release-harness/scripts/test-live-shard.mjs native-live-test
            timeout_minutes: 60
            profile_env_only: false
            profiles: stable full
          - suite_id: native-live-extensions-l-n
            label: Native live plugins L-N
            command: node .release-harness/scripts/test-live-shard.mjs native-live-extensions-l-n
            timeout_minutes: 30
            profile_env_only: false
            advisory: true
            profiles: full
          - suite_id: native-live-extensions-moonshot
            label: Native live Moonshot plugin
            command: node .release-harness/scripts/test-live-shard.mjs native-live-extensions-moonshot
            timeout_minutes: 30
            profile_env_only: false
            advisory: true
            profiles: full
          - suite_id: native-live-extensions-openai
            label: Native live OpenAI plugin
            command: node .release-harness/scripts/test-live-shard.mjs native-live-extensions-openai
            timeout_minutes: 60
            profile_env_only: false
            profiles: beta minimum stable full
          - suite_id: native-live-extensions-o-z-other
            label: Native live plugins O-Z other
            command: node .release-harness/scripts/test-live-shard.mjs native-live-extensions-o-z-other
            timeout_minutes: 30
            profile_env_only: false
            advisory: true
            profiles: full
          - suite_id: native-live-extensions-xai
            label: Native live xAI plugin
            command: node .release-harness/scripts/test-live-shard.mjs native-live-extensions-xai
            timeout_minutes: 30
            profile_env_only: false
            advisory: true
            profiles: full
    env:
      OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
      OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
      ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
      ANTHROPIC_API_TOKEN: ${{ secrets.ANTHROPIC_API_TOKEN }}
      ANTHROPIC_API_KEY_OLD: ${{ secrets.ANTHROPIC_API_KEY_OLD }}
      BYTEPLUS_API_KEY: ${{ secrets.BYTEPLUS_API_KEY }}
      CEREBRAS_API_KEY: ${{ secrets.CEREBRAS_API_KEY }}
      DEEPINFRA_API_KEY: ${{ secrets.DEEPINFRA_API_KEY }}
      DASHSCOPE_API_KEY: ${{ secrets.DASHSCOPE_API_KEY }}
      GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
      KIMI_API_KEY: ${{ secrets.KIMI_API_KEY }}
      MODELSTUDIO_API_KEY: ${{ secrets.MODELSTUDIO_API_KEY }}
      MOONSHOT_API_KEY: ${{ secrets.MOONSHOT_API_KEY }}
      MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
      MINIMAX_API_KEY: ${{ secrets.MINIMAX_API_KEY }}
      OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
      OPENCODE_ZEN_API_KEY: ${{ secrets.OPENCODE_ZEN_API_KEY }}
      OPENCLAW_LIVE_BROWSER_CDP_URL: ${{ secrets.OPENCLAW_LIVE_BROWSER_CDP_URL }}
      OPENCLAW_LIVE_SETUP_TOKEN: ${{ secrets.OPENCLAW_LIVE_SETUP_TOKEN }}
      OPENCLAW_LIVE_SETUP_TOKEN_MODEL: ${{ secrets.OPENCLAW_LIVE_SETUP_TOKEN_MODEL }}
      OPENCLAW_LIVE_SETUP_TOKEN_PROFILE: ${{ secrets.OPENCLAW_LIVE_SETUP_TOKEN_PROFILE }}
      OPENCLAW_LIVE_SETUP_TOKEN_VALUE: ${{ secrets.OPENCLAW_LIVE_SETUP_TOKEN_VALUE }}
      GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
      GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
      OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
      QWEN_API_KEY: ${{ secrets.QWEN_API_KEY }}
      FAL_KEY: ${{ secrets.FAL_KEY }}
      RUNWAY_API_KEY: ${{ secrets.RUNWAY_API_KEY }}
      DEEPGRAM_API_KEY: ${{ secrets.DEEPGRAM_API_KEY }}
      TOGETHER_API_KEY: ${{ secrets.TOGETHER_API_KEY }}
      VYDRA_API_KEY: ${{ secrets.VYDRA_API_KEY }}
      XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
      ZAI_API_KEY: ${{ secrets.ZAI_API_KEY }}
      Z_AI_API_KEY: ${{ secrets.Z_AI_API_KEY }}
      BYTEPLUS_ACCESS_KEY_ID: ${{ secrets.BYTEPLUS_ACCESS_KEY_ID }}
      BYTEPLUS_SECRET_ACCESS_KEY: ${{ secrets.BYTEPLUS_SECRET_ACCESS_KEY }}
      CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
      OPENCLAW_CODEX_AUTH_JSON: ${{ secrets.OPENCLAW_CODEX_AUTH_JSON }}
      OPENCLAW_CODEX_CONFIG_TOML: ${{ secrets.OPENCLAW_CODEX_CONFIG_TOML }}
      OPENCLAW_CLAUDE_JSON: ${{ secrets.OPENCLAW_CLAUDE_JSON }}
      OPENCLAW_CLAUDE_CREDENTIALS_JSON: ${{ secrets.OPENCLAW_CLAUDE_CREDENTIALS_JSON }}
      OPENCLAW_CLAUDE_SETTINGS_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_JSON }}
      OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON }}
      OPENCLAW_GEMINI_SETTINGS_JSON: ${{ secrets.OPENCLAW_GEMINI_SETTINGS_JSON }}
      FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}
      OPENCLAW_LIVE_VIDEO_GENERATION_SKIP_PROVIDERS: ""
      OPENCLAW_LIVE_VYDRA_VIDEO: "1"
      OPENCLAW_VITEST_MAX_WORKERS: "2"
    steps:
      - name: Checkout selected ref
        if: contains(matrix.profiles, inputs.release_test_profile) && (inputs.live_suite_filter == '' || inputs.live_suite_filter == matrix.suite_id || (inputs.live_suite_filter == 'native-live-src-gateway-profiles-anthropic' && startsWith(matrix.suite_id, 'native-live-src-gateway-profiles-anthropic-')) || (inputs.live_suite_filter == 'native-live-src-gateway-profiles-opencode-go' && startsWith(matrix.suite_id, 'native-live-src-gateway-profiles-opencode-go-')))
        uses: actions/checkout@v6
        with:
          ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
          fetch-depth: 1

      - name: Checkout trusted live shard harness
        if: contains(matrix.profiles, inputs.release_test_profile) && (inputs.live_suite_filter == '' || inputs.live_suite_filter == matrix.suite_id || (inputs.live_suite_filter == 'native-live-src-gateway-profiles-anthropic' && startsWith(matrix.suite_id, 'native-live-src-gateway-profiles-anthropic-')) || (inputs.live_suite_filter == 'native-live-src-gateway-profiles-opencode-go' && startsWith(matrix.suite_id, 'native-live-src-gateway-profiles-opencode-go-')))
        uses: actions/checkout@v6
        with:
          ref: ${{ github.sha }}
          fetch-depth: 1
          path: .release-harness

      - name: Setup Node environment
        if: contains(matrix.profiles, inputs.release_test_profile) && (inputs.live_suite_filter == '' || inputs.live_suite_filter == matrix.suite_id || (inputs.live_suite_filter == 'native-live-src-gateway-profiles-anthropic' && startsWith(matrix.suite_id, 'native-live-src-gateway-profiles-anthropic-')) || (inputs.live_suite_filter == 'native-live-src-gateway-profiles-opencode-go' && startsWith(matrix.suite_id, 'native-live-src-gateway-profiles-opencode-go-')))
        uses: ./.github/actions/setup-node-env
        with:
          node-version: ${{ env.NODE_VERSION }}
          install-bun: "true"

      - name: Hydrate live auth/profile inputs
        if: contains(matrix.profiles, inputs.release_test_profile) && (inputs.live_suite_filter == '' || inputs.live_suite_filter == matrix.suite_id || (inputs.live_suite_filter == 'native-live-src-gateway-profiles-anthropic' && startsWith(matrix.suite_id, 'native-live-src-gateway-profiles-anthropic-')) || (inputs.live_suite_filter == 'native-live-src-gateway-profiles-opencode-go' && startsWith(matrix.suite_id, 'native-live-src-gateway-profiles-opencode-go-')))
        run: bash scripts/ci-hydrate-live-auth.sh

      - name: Configure suite-specific env
        if: contains(matrix.profiles, inputs.release_test_profile) && (inputs.live_suite_filter == '' || inputs.live_suite_filter == matrix.suite_id || (inputs.live_suite_filter == 'native-live-src-gateway-profiles-anthropic' && startsWith(matrix.suite_id, 'native-live-src-gateway-profiles-anthropic-')) || (inputs.live_suite_filter == 'native-live-src-gateway-profiles-opencode-go' && startsWith(matrix.suite_id, 'native-live-src-gateway-profiles-opencode-go-')))
        shell: bash
        run: |
          set -euo pipefail
          if [[ "${{ matrix.profile_env_only }}" == "true" ]]; then
            echo "OPENCLAW_DOCKER_PROFILE_ENV_ONLY=1" >> "$GITHUB_ENV"
          fi
          case "${{ matrix.suite_id }}" in
            live-cli-backend-docker)
              echo "OPENCLAW_LIVE_CLI_BACKEND_MODEL=claude-cli/claude-sonnet-4-6" >> "$GITHUB_ENV"
              echo "OPENCLAW_LIVE_CLI_BACKEND_AUTH=api-key" >> "$GITHUB_ENV"
              echo "OPENCLAW_LIVE_CLI_BACKEND_DEBUG=1" >> "$GITHUB_ENV"
              echo "OPENCLAW_CLI_BACKEND_LOG_OUTPUT=1" >> "$GITHUB_ENV"
              echo "OPENCLAW_TEST_CONSOLE=1" >> "$GITHUB_ENV"
              ;;
            live-codex-harness-docker)
              # Keep CI on the API-key path for now. The staged Codex auth secret
              # is currently stale, but the wrapper still supports codex-auth for
              # local maintainer reruns without changing Peter's flow.
              echo "OPENCLAW_LIVE_CODEX_HARNESS_AUTH=api-key" >> "$GITHUB_ENV"
              echo "OPENCLAW_LIVE_CODEX_HARNESS_DEBUG=1" >> "$GITHUB_ENV"
              echo "OPENCLAW_CLI_BACKEND_LOG_OUTPUT=1" >> "$GITHUB_ENV"
              echo "OPENCLAW_TEST_CONSOLE=1" >> "$GITHUB_ENV"
              ;;
            live-acp-bind-docker)
              if [[ -n "${GEMINI_API_KEY:-}" || -n "${GOOGLE_API_KEY:-}" ]]; then
                echo "OPENCLAW_LIVE_ACP_BIND_AGENTS=claude,codex,gemini" >> "$GITHUB_ENV"
              else
                # The hydrated Gemini settings file only selects Gemini CLI auth
                # mode. CI still needs a usable Gemini or Google API key before
                # ACP bind can initialize a Gemini session.
                echo "OPENCLAW_LIVE_ACP_BIND_AGENTS=claude,codex" >> "$GITHUB_ENV"
              fi
              ;;
          esac

      - name: Run ${{ matrix.label }}
        if: contains(matrix.profiles, inputs.release_test_profile) && (inputs.live_suite_filter == '' || inputs.live_suite_filter == matrix.suite_id || (inputs.live_suite_filter == 'native-live-src-gateway-profiles-anthropic' && startsWith(matrix.suite_id, 'native-live-src-gateway-profiles-anthropic-')) || (inputs.live_suite_filter == 'native-live-src-gateway-profiles-opencode-go' && startsWith(matrix.suite_id, 'native-live-src-gateway-profiles-opencode-go-')))
        env:
          OPENCLAW_LIVE_COMMAND: ${{ matrix.command }}
          OPENCLAW_LIVE_SUITE_ADVISORY: ${{ matrix.advisory }}
        shell: bash
        run: |
          set +e
          bash .release-harness/scripts/ci-live-command-retry.sh
          status=$?
          set -e
          if [[ "$status" -eq 0 ]]; then
            exit 0
          fi
          if [[ "${OPENCLAW_LIVE_SUITE_ADVISORY:-}" == "true" ]]; then
            echo "::warning::Advisory live suite failed with exit code ${status}: ${{ matrix.suite_id }}"
            exit 0
          fi
          exit "$status"

  validate_live_docker_provider_suites:
    name: Docker live suites (${{ matrix.label }})
    needs: [validate_selected_ref, prepare_live_test_image]
    if: inputs.include_live_suites && !inputs.live_models_only && (inputs.live_suite_filter == '' || startsWith(inputs.live_suite_filter, 'live-'))
    continue-on-error: ${{ inputs.advisory }}
    runs-on: ${{ inputs.use_github_hosted_runners && 'ubuntu-24.04' || 'blacksmith-32vcpu-ubuntu-2404' }}
    timeout-minutes: ${{ matrix.timeout_minutes }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - suite_id: live-gateway-docker
            label: Docker live gateway OpenAI
            command: OPENCLAW_LIVE_GATEWAY_THINKING=off OPENCLAW_LIVE_GATEWAY_PROVIDERS=openai OPENCLAW_LIVE_GATEWAY_MODELS=openai/gpt-5.5 OPENCLAW_LIVE_GATEWAY_MAX_MODELS=1 OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=90000 OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=600000 OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" timeout --foreground --kill-after=30s 35m bash .release-harness/scripts/test-live-gateway-models-docker.sh
            timeout_minutes: 40
            profile_env_only: false
            profiles: beta minimum stable full
          - suite_id: live-gateway-anthropic-docker
            label: Docker live gateway Anthropic
            command: OPENCLAW_LIVE_GATEWAY_THINKING=low OPENCLAW_LIVE_GATEWAY_PROVIDERS=anthropic OPENCLAW_LIVE_GATEWAY_MODELS=anthropic/claude-sonnet-4-6,anthropic/claude-haiku-4-5 OPENCLAW_LIVE_GATEWAY_MAX_MODELS=2 OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=90000 OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=600000 OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" timeout --foreground --kill-after=30s 35m bash .release-harness/scripts/test-live-gateway-models-docker.sh
            timeout_minutes: 40
            profile_env_only: false
            profiles: stable full
          - suite_id: live-gateway-google-docker
            label: Docker live gateway Google
            command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=google OPENCLAW_LIVE_GATEWAY_MODELS=google/gemini-3.1-pro-preview OPENCLAW_LIVE_GATEWAY_MAX_MODELS=1 OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=90000 OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=180000 OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" timeout --foreground --kill-after=30s 35m bash .release-harness/scripts/test-live-gateway-models-docker.sh
            timeout_minutes: 40
            profile_env_only: false
            profiles: stable full
          - suite_id: live-gateway-minimax-docker
            label: Docker live gateway MiniMax
            command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=minimax,minimax-portal OPENCLAW_LIVE_GATEWAY_MODELS=minimax/MiniMax-M2.7,minimax-portal/MiniMax-M2.7 OPENCLAW_LIVE_GATEWAY_MAX_MODELS=1 OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=90000 OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=180000 OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" timeout --foreground --kill-after=30s 35m bash .release-harness/scripts/test-live-gateway-models-docker.sh
            timeout_minutes: 40
            profile_env_only: false
            profiles: stable full
          - suite_id: live-gateway-advisory-docker-deepseek-fireworks
            suite_group: live-gateway-advisory-docker
            label: Docker live gateway advisory DeepSeek/Fireworks
            command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=deepseek,fireworks OPENCLAW_LIVE_GATEWAY_MAX_MODELS=2 OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=90000 OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=180000 OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" timeout --foreground --kill-after=30s 35m bash .release-harness/scripts/test-live-gateway-models-docker.sh
            timeout_minutes: 40
            profile_env_only: false
            advisory: true
            profiles: full
          - suite_id: live-gateway-advisory-docker-opencode-openrouter
            suite_group: live-gateway-advisory-docker
            label: Docker live gateway advisory OpenCode/OpenRouter
            command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=opencode-go,openrouter OPENCLAW_LIVE_GATEWAY_MAX_MODELS=2 OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=90000 OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=180000 OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" timeout --foreground --kill-after=30s 35m bash .release-harness/scripts/test-live-gateway-models-docker.sh
            timeout_minutes: 40
            profile_env_only: false
            advisory: true
            profiles: full
          - suite_id: live-gateway-advisory-docker-xai-zai
            suite_group: live-gateway-advisory-docker
            label: Docker live gateway advisory xAI/Z.ai
            command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=xai,zai OPENCLAW_LIVE_GATEWAY_MAX_MODELS=2 OPENCLAW_LIVE_GATEWAY_STEP_TIMEOUT_MS=90000 OPENCLAW_LIVE_GATEWAY_MODEL_TIMEOUT_MS=180000 OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" timeout --foreground --kill-after=30s 35m bash .release-harness/scripts/test-live-gateway-models-docker.sh
            timeout_minutes: 40
            profile_env_only: false
            advisory: true
            profiles: full
          - suite_id: live-cli-backend-docker
            label: Docker live CLI backend
            command: OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" timeout --foreground --kill-after=30s 45m bash .release-harness/scripts/test-live-cli-backend-docker.sh
            timeout_minutes: 50
            profile_env_only: false
            profiles: stable full
          - suite_id: live-acp-bind-docker
            label: Docker live ACP bind
            command: OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" timeout --foreground --kill-after=30s 45m bash .release-harness/scripts/test-live-acp-bind-docker.sh
            timeout_minutes: 50
            profile_env_only: false
            profiles: stable full
          - suite_id: live-codex-harness-docker
            label: Docker live Codex harness
            command: OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" timeout --foreground --kill-after=30s 35m bash .release-harness/scripts/test-live-codex-harness-docker.sh
            timeout_minutes: 40
            profile_env_only: false
            profiles: stable full
          - suite_id: live-subagent-announce-docker
            label: Docker live subagent announce
            command: OPENCLAW_LIVE_DOCKER_REPO_ROOT="$GITHUB_WORKSPACE" timeout --foreground --kill-after=30s 20m bash .release-harness/scripts/test-live-subagent-announce-docker.sh
            timeout_minutes: 25
            profile_env_only: false
            profiles: stable full
    env:
      OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
      OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
      ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
      ANTHROPIC_API_TOKEN: ${{ secrets.ANTHROPIC_API_TOKEN }}
      ANTHROPIC_API_KEY_OLD: ${{ secrets.ANTHROPIC_API_KEY_OLD }}
      BYTEPLUS_API_KEY: ${{ secrets.BYTEPLUS_API_KEY }}
      CEREBRAS_API_KEY: ${{ secrets.CEREBRAS_API_KEY }}
      DEEPINFRA_API_KEY: ${{ secrets.DEEPINFRA_API_KEY }}
      DASHSCOPE_API_KEY: ${{ secrets.DASHSCOPE_API_KEY }}
      GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
      KIMI_API_KEY: ${{ secrets.KIMI_API_KEY }}
      MODELSTUDIO_API_KEY: ${{ secrets.MODELSTUDIO_API_KEY }}
      MOONSHOT_API_KEY: ${{ secrets.MOONSHOT_API_KEY }}
      MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
      MINIMAX_API_KEY: ${{ secrets.MINIMAX_API_KEY }}
      OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
      OPENCODE_ZEN_API_KEY: ${{ secrets.OPENCODE_ZEN_API_KEY }}
      OPENCLAW_LIVE_BROWSER_CDP_URL: ${{ secrets.OPENCLAW_LIVE_BROWSER_CDP_URL }}
      OPENCLAW_LIVE_SETUP_TOKEN: ${{ secrets.OPENCLAW_LIVE_SETUP_TOKEN }}
      OPENCLAW_LIVE_SETUP_TOKEN_MODEL: ${{ secrets.OPENCLAW_LIVE_SETUP_TOKEN_MODEL }}
      OPENCLAW_LIVE_SETUP_TOKEN_PROFILE: ${{ secrets.OPENCLAW_LIVE_SETUP_TOKEN_PROFILE }}
      OPENCLAW_LIVE_SETUP_TOKEN_VALUE: ${{ secrets.OPENCLAW_LIVE_SETUP_TOKEN_VALUE }}
      GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
      GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
      OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
      QWEN_API_KEY: ${{ secrets.QWEN_API_KEY }}
      FAL_KEY: ${{ secrets.FAL_KEY }}
      RUNWAY_API_KEY: ${{ secrets.RUNWAY_API_KEY }}
      DEEPGRAM_API_KEY: ${{ secrets.DEEPGRAM_API_KEY }}
      TOGETHER_API_KEY: ${{ secrets.TOGETHER_API_KEY }}
      VYDRA_API_KEY: ${{ secrets.VYDRA_API_KEY }}
      XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
      ZAI_API_KEY: ${{ secrets.ZAI_API_KEY }}
      Z_AI_API_KEY: ${{ secrets.Z_AI_API_KEY }}
      BYTEPLUS_ACCESS_KEY_ID: ${{ secrets.BYTEPLUS_ACCESS_KEY_ID }}
      BYTEPLUS_SECRET_ACCESS_KEY: ${{ secrets.BYTEPLUS_SECRET_ACCESS_KEY }}
      CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
      OPENCLAW_CODEX_AUTH_JSON: ${{ secrets.OPENCLAW_CODEX_AUTH_JSON }}
      OPENCLAW_CODEX_CONFIG_TOML: ${{ secrets.OPENCLAW_CODEX_CONFIG_TOML }}
      OPENCLAW_CLAUDE_JSON: ${{ secrets.OPENCLAW_CLAUDE_JSON }}
      OPENCLAW_CLAUDE_CREDENTIALS_JSON: ${{ secrets.OPENCLAW_CLAUDE_CREDENTIALS_JSON }}
      OPENCLAW_CLAUDE_SETTINGS_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_JSON }}
      OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON }}
      OPENCLAW_GEMINI_SETTINGS_JSON: ${{ secrets.OPENCLAW_GEMINI_SETTINGS_JSON }}
      FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}
      OPENCLAW_LIVE_IMAGE: ${{ needs.prepare_live_test_image.outputs.live_image }}
      OPENCLAW_SKIP_DOCKER_BUILD: "1"
      OPENCLAW_LIVE_VIDEO_GENERATION_SKIP_PROVIDERS: ""
      OPENCLAW_LIVE_VYDRA_VIDEO: "1"
      OPENCLAW_VITEST_MAX_WORKERS: "2"
    steps:
      - name: Checkout selected ref
        if: contains(matrix.profiles, inputs.release_test_profile) && (inputs.live_suite_filter == '' || inputs.live_suite_filter == matrix.suite_id || (inputs.live_suite_filter == 'live-gateway-advisory-docker' && startsWith(matrix.suite_id, 'live-gateway-advisory-docker-')))
        uses: actions/checkout@v6
        with:
          ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
          fetch-depth: 1

      - name: Checkout trusted live shard harness
        if: contains(matrix.profiles, inputs.release_test_profile) && (inputs.live_suite_filter == '' || inputs.live_suite_filter == matrix.suite_id || (inputs.live_suite_filter == 'live-gateway-advisory-docker' && startsWith(matrix.suite_id, 'live-gateway-advisory-docker-')))
        uses: actions/checkout@v6
        with:
          ref: ${{ github.sha }}
          fetch-depth: 1
          path: .release-harness

      - name: Setup Node environment
        if: contains(matrix.profiles, inputs.release_test_profile) && (inputs.live_suite_filter == '' || inputs.live_suite_filter == matrix.suite_id || (inputs.live_suite_filter == 'live-gateway-advisory-docker' && startsWith(matrix.suite_id, 'live-gateway-advisory-docker-')))
        uses: ./.github/actions/setup-node-env
        with:
          node-version: ${{ env.NODE_VERSION }}
          install-bun: "true"

      - name: Hydrate live auth/profile inputs
        if: contains(matrix.profiles, inputs.release_test_profile) && (inputs.live_suite_filter == '' || inputs.live_suite_filter == matrix.suite_id || (inputs.live_suite_filter == 'live-gateway-advisory-docker' && startsWith(matrix.suite_id, 'live-gateway-advisory-docker-')))
        run: bash scripts/ci-hydrate-live-auth.sh

      - name: Log in to GHCR
        if: contains(matrix.profiles, inputs.release_test_profile) && (inputs.live_suite_filter == '' || inputs.live_suite_filter == matrix.suite_id || (inputs.live_suite_filter == 'live-gateway-advisory-docker' && startsWith(matrix.suite_id, 'live-gateway-advisory-docker-')))
        run: bash .release-harness/scripts/ci-docker-login-ghcr.sh
        env:
          GHCR_USERNAME: ${{ github.actor }}
          GITHUB_TOKEN: ${{ github.token }}

      - name: Configure suite-specific env
        if: contains(matrix.profiles, inputs.release_test_profile) && (inputs.live_suite_filter == '' || inputs.live_suite_filter == matrix.suite_id || (inputs.live_suite_filter == 'live-gateway-advisory-docker' && startsWith(matrix.suite_id, 'live-gateway-advisory-docker-')))
        shell: bash
        run: |
          set -euo pipefail
          if [[ "${{ matrix.profile_env_only }}" == "true" ]]; then
            echo "OPENCLAW_DOCKER_PROFILE_ENV_ONLY=1" >> "$GITHUB_ENV"
          fi
          case "${{ matrix.suite_id }}" in
            live-cli-backend-docker)
              echo "OPENCLAW_LIVE_CLI_BACKEND_MODEL=claude-cli/claude-sonnet-4-6" >> "$GITHUB_ENV"
              echo "OPENCLAW_LIVE_CLI_BACKEND_AUTH=api-key" >> "$GITHUB_ENV"
              echo "OPENCLAW_LIVE_CLI_BACKEND_DEBUG=1" >> "$GITHUB_ENV"
              echo "OPENCLAW_CLI_BACKEND_LOG_OUTPUT=1" >> "$GITHUB_ENV"
              echo "OPENCLAW_TEST_CONSOLE=1" >> "$GITHUB_ENV"
              ;;
            live-codex-harness-docker)
              echo "OPENCLAW_LIVE_CODEX_HARNESS_AUTH=api-key" >> "$GITHUB_ENV"
              echo "OPENCLAW_LIVE_CODEX_HARNESS_DEBUG=1" >> "$GITHUB_ENV"
              echo "OPENCLAW_CLI_BACKEND_LOG_OUTPUT=1" >> "$GITHUB_ENV"
              echo "OPENCLAW_TEST_CONSOLE=1" >> "$GITHUB_ENV"
              ;;
            live-acp-bind-docker)
              if [[ -n "${GEMINI_API_KEY:-}" || -n "${GOOGLE_API_KEY:-}" ]]; then
                echo "OPENCLAW_LIVE_ACP_BIND_AGENTS=claude,codex,gemini" >> "$GITHUB_ENV"
              else
                echo "OPENCLAW_LIVE_ACP_BIND_AGENTS=claude,codex" >> "$GITHUB_ENV"
              fi
              ;;
          esac

      - name: Run ${{ matrix.label }}
        if: contains(matrix.profiles, inputs.release_test_profile) && (inputs.live_suite_filter == '' || inputs.live_suite_filter == matrix.suite_id || (inputs.live_suite_filter == 'live-gateway-advisory-docker' && startsWith(matrix.suite_id, 'live-gateway-advisory-docker-')))
        env:
          OPENCLAW_LIVE_COMMAND: ${{ matrix.command }}
          OPENCLAW_LIVE_SUITE_ADVISORY: ${{ matrix.advisory }}
        shell: bash
        run: |
          set +e
          bash .release-harness/scripts/ci-live-command-retry.sh
          status=$?
          set -e
          if [[ "$status" -eq 0 ]]; then
            exit 0
          fi
          if [[ "${OPENCLAW_LIVE_SUITE_ADVISORY:-}" == "true" ]]; then
            echo "::warning::Advisory live suite failed with exit code ${status}: ${{ matrix.suite_id }}"
            exit 0
          fi
          exit "$status"

  validate_live_media_provider_suites:
    name: Live media suites (${{ matrix.label }})
    needs: validate_selected_ref
    if: inputs.include_live_suites && !inputs.live_models_only && (inputs.live_suite_filter == '' || startsWith(inputs.live_suite_filter, 'native-live-extensions-media') || inputs.live_suite_filter == 'native-live-extensions-a-k')
    continue-on-error: ${{ inputs.advisory }}
    runs-on: ${{ inputs.use_github_hosted_runners && 'ubuntu-24.04' || 'blacksmith-8vcpu-ubuntu-2404' }}
    container:
      image: ghcr.io/openclaw/openclaw-live-media-runner:ubuntu-24.04
      credentials:
        username: ${{ github.actor }}
        password: ${{ github.token }}
    timeout-minutes: ${{ matrix.timeout_minutes }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - suite_id: native-live-extensions-a-k
            label: Native live plugins A-K
            command: node .release-harness/scripts/test-live-shard.mjs native-live-extensions-a-k
            timeout_minutes: 30
            profile_env_only: false
            advisory: true
            profiles: full
          - suite_id: native-live-extensions-media-audio
            label: Native live media audio plugins
            command: node .release-harness/scripts/test-live-shard.mjs native-live-extensions-media-audio
            timeout_minutes: 30
            profile_env_only: false
            advisory: true
            profiles: full
          - suite_id: native-live-extensions-media-music-google
            label: Native live media music Google
            command: OPENCLAW_LIVE_MUSIC_GENERATION_PROVIDERS=google node .release-harness/scripts/test-live-shard.mjs native-live-extensions-media-music-google
            timeout_minutes: 30
            profile_env_only: false
            advisory: true
            profiles: full
          - suite_id: native-live-extensions-media-music-minimax
            label: Native live media music MiniMax
            command: OPENCLAW_LIVE_MUSIC_GENERATION_PROVIDERS=minimax node .release-harness/scripts/test-live-shard.mjs native-live-extensions-media-music-minimax
            timeout_minutes: 30
            profile_env_only: false
            advisory: true
            profiles: full
          - suite_id: native-live-extensions-media-video-a
            suite_group: native-live-extensions-media-video
            label: Native live media video plugins A
            command: OPENCLAW_LIVE_VIDEO_GENERATION_PROVIDERS=alibaba,byteplus,deepinfra,fal node .release-harness/scripts/test-live-shard.mjs native-live-extensions-media-video
            timeout_minutes: 30
            profile_env_only: false
            advisory: true
            profiles: full
          - suite_id: native-live-extensions-media-video-b
            suite_group: native-live-extensions-media-video
            label: Native live media video plugins B
            command: OPENCLAW_LIVE_VIDEO_GENERATION_PROVIDERS=google,minimax node .release-harness/scripts/test-live-shard.mjs native-live-extensions-media-video
            timeout_minutes: 30
            profile_env_only: false
            advisory: true
            profiles: full
          - suite_id: native-live-extensions-media-video-c
            suite_group: native-live-extensions-media-video
            label: Native live media video plugins C
            command: OPENCLAW_LIVE_VIDEO_GENERATION_PROVIDERS=openai,openrouter,xai node .release-harness/scripts/test-live-shard.mjs native-live-extensions-media-video
            timeout_minutes: 30
            profile_env_only: false
            advisory: true
            profiles: full
          - suite_id: native-live-extensions-media-video-d
            suite_group: native-live-extensions-media-video
            label: Native live media video plugins D
            command: OPENCLAW_LIVE_VIDEO_GENERATION_PROVIDERS=qwen,runway,together,vydra node .release-harness/scripts/test-live-shard.mjs native-live-extensions-media-video
            timeout_minutes: 30
            profile_env_only: false
            advisory: true
            profiles: full
    env:
      OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
      OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
      ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
      ANTHROPIC_API_TOKEN: ${{ secrets.ANTHROPIC_API_TOKEN }}
      ANTHROPIC_API_KEY_OLD: ${{ secrets.ANTHROPIC_API_KEY_OLD }}
      BYTEPLUS_API_KEY: ${{ secrets.BYTEPLUS_API_KEY }}
      CEREBRAS_API_KEY: ${{ secrets.CEREBRAS_API_KEY }}
      DEEPINFRA_API_KEY: ${{ secrets.DEEPINFRA_API_KEY }}
      DASHSCOPE_API_KEY: ${{ secrets.DASHSCOPE_API_KEY }}
      GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
      KIMI_API_KEY: ${{ secrets.KIMI_API_KEY }}
      MODELSTUDIO_API_KEY: ${{ secrets.MODELSTUDIO_API_KEY }}
      MOONSHOT_API_KEY: ${{ secrets.MOONSHOT_API_KEY }}
      MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
      MINIMAX_API_KEY: ${{ secrets.MINIMAX_API_KEY }}
      OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }}
      OPENCODE_ZEN_API_KEY: ${{ secrets.OPENCODE_ZEN_API_KEY }}
      OPENCLAW_LIVE_BROWSER_CDP_URL: ${{ secrets.OPENCLAW_LIVE_BROWSER_CDP_URL }}
      OPENCLAW_LIVE_SETUP_TOKEN: ${{ secrets.OPENCLAW_LIVE_SETUP_TOKEN }}
      OPENCLAW_LIVE_SETUP_TOKEN_MODEL: ${{ secrets.OPENCLAW_LIVE_SETUP_TOKEN_MODEL }}
      OPENCLAW_LIVE_SETUP_TOKEN_PROFILE: ${{ secrets.OPENCLAW_LIVE_SETUP_TOKEN_PROFILE }}
      OPENCLAW_LIVE_SETUP_TOKEN_VALUE: ${{ secrets.OPENCLAW_LIVE_SETUP_TOKEN_VALUE }}
      GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
      GOOGLE_API_KEY: ${{ secrets.GOOGLE_API_KEY }}
      OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
      QWEN_API_KEY: ${{ secrets.QWEN_API_KEY }}
      FAL_KEY: ${{ secrets.FAL_KEY }}
      RUNWAY_API_KEY: ${{ secrets.RUNWAY_API_KEY }}
      DEEPGRAM_API_KEY: ${{ secrets.DEEPGRAM_API_KEY }}
      TOGETHER_API_KEY: ${{ secrets.TOGETHER_API_KEY }}
      VYDRA_API_KEY: ${{ secrets.VYDRA_API_KEY }}
      XAI_API_KEY: ${{ secrets.XAI_API_KEY }}
      ZAI_API_KEY: ${{ secrets.ZAI_API_KEY }}
      Z_AI_API_KEY: ${{ secrets.Z_AI_API_KEY }}
      BYTEPLUS_ACCESS_KEY_ID: ${{ secrets.BYTEPLUS_ACCESS_KEY_ID }}
      BYTEPLUS_SECRET_ACCESS_KEY: ${{ secrets.BYTEPLUS_SECRET_ACCESS_KEY }}
      CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
      OPENCLAW_CODEX_AUTH_JSON: ${{ secrets.OPENCLAW_CODEX_AUTH_JSON }}
      OPENCLAW_CODEX_CONFIG_TOML: ${{ secrets.OPENCLAW_CODEX_CONFIG_TOML }}
      OPENCLAW_CLAUDE_JSON: ${{ secrets.OPENCLAW_CLAUDE_JSON }}
      OPENCLAW_CLAUDE_CREDENTIALS_JSON: ${{ secrets.OPENCLAW_CLAUDE_CREDENTIALS_JSON }}
      OPENCLAW_CLAUDE_SETTINGS_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_JSON }}
      OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON: ${{ secrets.OPENCLAW_CLAUDE_SETTINGS_LOCAL_JSON }}
      OPENCLAW_GEMINI_SETTINGS_JSON: ${{ secrets.OPENCLAW_GEMINI_SETTINGS_JSON }}
      FIREWORKS_API_KEY: ${{ secrets.FIREWORKS_API_KEY }}
      OPENCLAW_LIVE_VIDEO_GENERATION_SKIP_PROVIDERS: ""
      OPENCLAW_LIVE_VYDRA_VIDEO: "1"
      OPENCLAW_VITEST_MAX_WORKERS: "2"
    steps:
      - name: Checkout selected ref
        if: contains(matrix.profiles, inputs.release_test_profile) && (inputs.live_suite_filter == '' || inputs.live_suite_filter == matrix.suite_id || (inputs.live_suite_filter == 'native-live-extensions-media-video' && startsWith(matrix.suite_id, 'native-live-extensions-media-video-')))
        uses: actions/checkout@v6
        with:
          ref: ${{ needs.validate_selected_ref.outputs.selected_sha }}
          fetch-depth: 1

      - name: Checkout trusted live shard harness
        if: contains(matrix.profiles, inputs.release_test_profile) && (inputs.live_suite_filter == '' || inputs.live_suite_filter == matrix.suite_id || (inputs.live_suite_filter == 'native-live-extensions-media-video' && startsWith(matrix.suite_id, 'native-live-extensions-media-video-')))
        uses: actions/checkout@v6
        with:
          ref: ${{ github.sha }}
          fetch-depth: 1
          path: .release-harness

      - name: Verify preinstalled live media dependencies
        if: contains(matrix.profiles, inputs.release_test_profile) && (inputs.live_suite_filter == '' || inputs.live_suite_filter == matrix.suite_id || (inputs.live_suite_filter == 'native-live-extensions-media-video' && startsWith(matrix.suite_id, 'native-live-extensions-media-video-')))
        shell: bash
        run: |
          set -euo pipefail
          ffmpeg -version | head -1
          ffprobe -version | head -1

      - name: Setup Node environment
        if: contains(matrix.profiles, inputs.release_test_profile) && (inputs.live_suite_filter == '' || inputs.live_suite_filter == matrix.suite_id || (inputs.live_suite_filter == 'native-live-extensions-media-video' && startsWith(matrix.suite_id, 'native-live-extensions-media-video-')))
        uses: ./.github/actions/setup-node-env
        with:
          node-version: ${{ env.NODE_VERSION }}
          install-bun: "true"

      - name: Hydrate live auth/profile inputs
        if: contains(matrix.profiles, inputs.release_test_profile) && (inputs.live_suite_filter == '' || inputs.live_suite_filter == matrix.suite_id || (inputs.live_suite_filter == 'native-live-extensions-media-video' && startsWith(matrix.suite_id, 'native-live-extensions-media-video-')))
        run: bash scripts/ci-hydrate-live-auth.sh

      - name: Configure suite-specific env
        if: contains(matrix.profiles, inputs.release_test_profile) && (inputs.live_suite_filter == '' || inputs.live_suite_filter == matrix.suite_id || (inputs.live_suite_filter == 'native-live-extensions-media-video' && startsWith(matrix.suite_id, 'native-live-extensions-media-video-')))
        shell: bash
        run: |
          set -euo pipefail
          if [[ "${{ matrix.profile_env_only }}" == "true" ]]; then
            echo "OPENCLAW_DOCKER_PROFILE_ENV_ONLY=1" >> "$GITHUB_ENV"
          fi

      - name: Run ${{ matrix.label }}
        if: contains(matrix.profiles, inputs.release_test_profile) && (inputs.live_suite_filter == '' || inputs.live_suite_filter == matrix.suite_id || (inputs.live_suite_filter == 'native-live-extensions-media-video' && startsWith(matrix.suite_id, 'native-live-extensions-media-video-')))
        env:
          OPENCLAW_LIVE_SUITE_ADVISORY: ${{ matrix.advisory }}
        shell: bash
        run: |
          set +e
          ${{ matrix.command }}
          status=$?
          set -e
          if [[ "$status" -eq 0 ]]; then
            exit 0
          fi
          if [[ "${OPENCLAW_LIVE_SUITE_ADVISORY:-}" == "true" ]]; then
            echo "::warning::Advisory live suite failed with exit code ${status}: ${{ matrix.suite_id }}"
            exit 0
          fi
          exit "$status"
