name: OpenClaw Release Checks

on:
  workflow_dispatch:
    inputs:
      ref:
        description: Branch, tag, or full commit SHA to validate
        required: true
        type: string
      expected_sha:
        description: Optional full SHA that ref must resolve to
        required: false
        default: ""
        type: string
      provider:
        description: Provider lane for cross-OS onboarding and the end-to-end agent turn
        required: false
        default: openai
        type: choice
        options:
          - openai
          - anthropic
          - minimax
      mode:
        description: Which cross-OS release lanes to run
        required: false
        default: both
        type: choice
        options:
          - fresh
          - upgrade
          - both
      release_profile:
        description: Release coverage profile for live/Docker/provider breadth
        required: false
        default: stable
        type: choice
        options:
          - beta
          - stable
          - full
      run_release_soak:
        description: Run exhaustive live/Docker and upgrade-survivor soak lanes; forced on for release_profile=full
        required: false
        default: false
        type: boolean
      rerun_group:
        description: Release check group to run
        required: false
        default: all
        type: choice
        options:
          - all
          - install-smoke
          - cross-os
          - live-e2e
          - package
          - qa
          - qa-parity
          - qa-live
      live_suite_filter:
        description: Optional exact live/E2E suite id, or comma-separated QA live lanes such as qa-live-matrix,qa-live-telegram,qa-live-discord,qa-live-whatsapp; blank runs all selected live suites
        required: false
        default: ""
        type: string
      cross_os_suite_filter:
        description: Optional focused cross-OS suite filter, e.g. windows/packaged-upgrade or packaged-fresh
        required: false
        default: ""
        type: string
      release_package_spec:
        description: Optional published package spec for release checks; blank builds the selected SHA package artifact
        required: false
        default: ""
        type: string
      package_acceptance_package_spec:
        description: Optional published package spec for Package Acceptance; blank uses the prepared release artifact
        required: false
        default: ""
        type: string
      codex_plugin_spec:
        description: Optional Codex plugin install spec for live Docker package checks; blank derives from release_package_spec or packs the selected ref
        required: false
        default: ""
        type: string

concurrency:
  group: openclaw-release-checks-${{ inputs.expected_sha || inputs.ref }}-${{ inputs.rerun_group }}
  cancel-in-progress: ${{ startsWith(github.ref, 'refs/heads/tideclaw/alpha/') }}

env:
  FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
  NODE_VERSION: "24.15.0"
  OPENCLAW_CI_OPENAI_MODEL: ${{ vars.OPENCLAW_CI_OPENAI_MODEL || 'openai/gpt-5.5' }}

jobs:
  resolve_target:
    runs-on: ubuntu-24.04
    timeout-minutes: 30
    permissions:
      contents: read
    outputs:
      ref: ${{ steps.inputs.outputs.ref }}
      revision: ${{ steps.ref.outputs.sha }}
      provider: ${{ steps.inputs.outputs.provider }}
      mode: ${{ steps.inputs.outputs.mode }}
      release_profile: ${{ steps.inputs.outputs.release_profile }}
      run_release_soak: ${{ steps.inputs.outputs.run_release_soak }}
      rerun_group: ${{ steps.inputs.outputs.rerun_group }}
      live_suite_filter: ${{ steps.inputs.outputs.live_suite_filter }}
      cross_os_suite_filter: ${{ steps.inputs.outputs.cross_os_suite_filter }}
      qa_live_matrix_enabled: ${{ steps.inputs.outputs.qa_live_matrix_enabled }}
      qa_live_telegram_enabled: ${{ steps.inputs.outputs.qa_live_telegram_enabled }}
      qa_live_discord_enabled: ${{ steps.inputs.outputs.qa_live_discord_enabled }}
      qa_live_whatsapp_enabled: ${{ steps.inputs.outputs.qa_live_whatsapp_enabled }}
      qa_live_slack_enabled: ${{ steps.inputs.outputs.qa_live_slack_enabled }}
      release_package_spec: ${{ steps.inputs.outputs.release_package_spec }}
      package_acceptance_package_spec: ${{ steps.inputs.outputs.package_acceptance_package_spec }}
      codex_plugin_spec: ${{ steps.inputs.outputs.codex_plugin_spec }}
    steps:
      - name: Require trusted workflow ref for release checks
        env:
          RELEASE_REF: ${{ inputs.ref }}
          WORKFLOW_REF: ${{ github.ref }}
        run: |
          set -euo pipefail
          tideclaw_alpha_check=false
          if [[ "${WORKFLOW_REF}" =~ ^refs/heads/tideclaw/alpha/[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{4}Z$ ]]; then
            workflow_branch="${WORKFLOW_REF#refs/heads/}"
            if [[ "${RELEASE_REF}" == *"-alpha."* || "${RELEASE_REF}" =~ ^[0-9a-fA-F]{40}$ || "${RELEASE_REF}" == "${workflow_branch}" || "${RELEASE_REF}" == "refs/heads/${workflow_branch}" ]]; then
              tideclaw_alpha_check=true
            fi
          fi
          if [[ "${WORKFLOW_REF}" != "refs/heads/main" ]] && [[ ! "${WORKFLOW_REF}" =~ ^refs/heads/release/[0-9]{4}\.[1-9][0-9]*\.[1-9][0-9]*$ ]] && [[ ! "${WORKFLOW_REF}" =~ ^refs/heads/release-ci/[0-9a-f]{12}-[0-9]+$ ]] && [[ "${tideclaw_alpha_check}" != "true" ]]; then
            echo "Release checks must be dispatched from main, release/YYYY.M.D, a Full Release Validation release-ci/<sha>-<timestamp> ref, or a Tideclaw alpha branch for alpha prereleases." >&2
            exit 1
          fi

      - name: Validate ref input
        env:
          RELEASE_REF: ${{ inputs.ref }}
          EXPECTED_SHA: ${{ inputs.expected_sha }}
        run: |
          set -euo pipefail
          if [[ -z "${RELEASE_REF// }" ]] || [[ "${RELEASE_REF}" == -* ]]; then
            echo "Expected a branch, tag, or full commit SHA; got: ${RELEASE_REF}" >&2
            exit 1
          fi
          if [[ -n "${EXPECTED_SHA// }" ]] && [[ ! "${EXPECTED_SHA}" =~ ^[0-9a-fA-F]{40}$ ]]; then
            echo "Expected expected_sha to be a full commit SHA; got: ${EXPECTED_SHA}" >&2
            exit 1
          fi

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

      - name: Fast-resolve selected ref
        id: fast_ref
        env:
          RELEASE_REF: ${{ inputs.ref }}
          EXPECTED_SHA: ${{ inputs.expected_sha }}
        run: |
          bash workflow/scripts/github/resolve-openclaw-ref.sh \
            --ref "$RELEASE_REF" \
            --expected-sha "$EXPECTED_SHA" \
            --fallback-ok \
            --github-output "$GITHUB_OUTPUT"

      - name: Checkout selected ref for reachability fallback
        if: steps.fast_ref.outputs.fallback == 'true'
        uses: actions/checkout@v6
        with:
          persist-credentials: false
          ref: ${{ inputs.ref }}
          path: source
          fetch-depth: 0

      - name: Resolve checked-out fallback SHA
        if: steps.fast_ref.outputs.fallback == 'true'
        id: fallback_ref
        working-directory: source
        run: echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"

      - name: Validate selected ref belongs to this repository
        if: steps.fast_ref.outputs.fallback == 'true'
        working-directory: source
        env:
          RELEASE_REF: ${{ inputs.ref }}
          GITHUB_TOKEN: ${{ github.token }}
        run: |
          set -euo pipefail
          SELECTED_SHA="$(git rev-parse HEAD)"
          git_fetch_with_checkout_auth() {
            if git config --get-all http.https://github.com/.extraheader >/dev/null; then
              git fetch "$@"
              return
            fi
            local auth_header
            auth_header="$(printf 'x-access-token:%s' "$GITHUB_TOKEN" | base64 | tr -d '\n')"
            git -c "http.https://github.com/.extraheader=AUTHORIZATION: basic ${auth_header}" fetch "$@"
          }
          git_fetch_with_checkout_auth --no-tags origin '+refs/heads/*:refs/remotes/origin/*'
          git_fetch_with_checkout_auth --tags origin '+refs/tags/*:refs/tags/*'

          if git tag --points-at "${SELECTED_SHA}" | grep -Eq '^v'; then
            exit 0
          fi

          if git for-each-ref --format='%(refname:short)' --contains "${SELECTED_SHA}" refs/remotes/origin | grep -Eq '^origin/'; then
            exit 0
          fi

          echo "Ref '${RELEASE_REF}' resolved to ${SELECTED_SHA}, but that commit is not reachable from an OpenClaw branch or release tag." >&2
          echo "Secret-bearing release checks only run repository-owned branch/tag history, not arbitrary unreferenced commits." >&2
          exit 1

      - name: Finalize resolved SHA
        id: ref
        env:
          FAST_SHA: ${{ steps.fast_ref.outputs.sha }}
          FALLBACK_SHA: ${{ steps.fallback_ref.outputs.sha }}
          EXPECTED_SHA: ${{ inputs.expected_sha }}
          USED_FALLBACK: ${{ steps.fast_ref.outputs.fallback }}
        run: |
          set -euo pipefail
          selected_sha="$FAST_SHA"
          if [[ "$USED_FALLBACK" == "true" ]]; then
            selected_sha="$FALLBACK_SHA"
          fi
          if [[ -z "$selected_sha" ]]; then
            echo "Failed to resolve selected ref SHA." >&2
            exit 1
          fi
          if [[ -n "${EXPECTED_SHA// }" ]] && [[ "${selected_sha,,}" != "${EXPECTED_SHA,,}" ]]; then
            echo "Ref resolved to ${selected_sha}, expected ${EXPECTED_SHA}." >&2
            exit 1
          fi
          echo "sha=${selected_sha,,}" >> "$GITHUB_OUTPUT"

      - name: Validate Tideclaw alpha target matches workflow branch
        if: startsWith(github.ref, 'refs/heads/tideclaw/alpha/')
        working-directory: workflow
        env:
          SELECTED_SHA: ${{ steps.ref.outputs.sha }}
          WORKFLOW_REF: ${{ github.ref }}
          GITHUB_TOKEN: ${{ github.token }}
        run: |
          set -euo pipefail
          if [[ ! "${WORKFLOW_REF}" =~ ^refs/heads/tideclaw/alpha/[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{4}Z$ ]]; then
            echo "Tideclaw alpha release checks must run from tideclaw/alpha/YYYY-MM-DD-HHMMZ." >&2
            exit 1
          fi
          alpha_branch="${WORKFLOW_REF#refs/heads/}"
          git_fetch_with_checkout_auth() {
            if git config --get-all http.https://github.com/.extraheader >/dev/null; then
              git fetch "$@"
              return
            fi
            local auth_header
            auth_header="$(printf 'x-access-token:%s' "$GITHUB_TOKEN" | base64 | tr -d '\n')"
            git -c "http.https://github.com/.extraheader=AUTHORIZATION: basic ${auth_header}" fetch "$@"
          }
          git_fetch_with_checkout_auth --no-tags origin "+refs/heads/${alpha_branch}:refs/remotes/origin/${alpha_branch}"
          if ! git merge-base --is-ancestor "${SELECTED_SHA}" "refs/remotes/origin/${alpha_branch}"; then
            echo "Alpha release target ${SELECTED_SHA} must be reachable from ${alpha_branch}." >&2
            exit 1
          fi

      - name: Capture selected inputs
        id: inputs
        env:
          RELEASE_REF_INPUT: ${{ inputs.ref }}
          RELEASE_PROVIDER_INPUT: ${{ inputs.provider }}
          RELEASE_MODE_INPUT: ${{ inputs.mode }}
          RELEASE_PROFILE_INPUT: ${{ inputs.release_profile }}
          RELEASE_RUN_RELEASE_SOAK_INPUT: ${{ inputs.run_release_soak }}
          RELEASE_RERUN_GROUP_INPUT: ${{ inputs.rerun_group }}
          RELEASE_LIVE_SUITE_FILTER_INPUT: ${{ inputs.live_suite_filter }}
          RELEASE_CROSS_OS_SUITE_FILTER_INPUT: ${{ inputs.cross_os_suite_filter }}
          RELEASE_QA_DISCORD_LIVE_CI_ENABLED: ${{ vars.OPENCLAW_RELEASE_QA_DISCORD_LIVE_CI_ENABLED || 'false' }}
          RELEASE_QA_WHATSAPP_LIVE_CI_ENABLED: ${{ vars.OPENCLAW_RELEASE_QA_WHATSAPP_LIVE_CI_ENABLED || 'false' }}
          RELEASE_QA_SLACK_LIVE_CI_ENABLED: ${{ vars.OPENCLAW_RELEASE_QA_SLACK_LIVE_CI_ENABLED || 'false' }}
          RELEASE_PACKAGE_SPEC_INPUT: ${{ inputs.release_package_spec }}
          RELEASE_PACKAGE_ACCEPTANCE_PACKAGE_SPEC_INPUT: ${{ inputs.package_acceptance_package_spec }}
          RELEASE_CODEX_PLUGIN_SPEC_INPUT: ${{ inputs.codex_plugin_spec }}
        run: |
          set -euo pipefail
          qa_live_matrix_enabled=true
          qa_live_telegram_enabled=true
          qa_live_discord_ci_enabled="$(printf '%s' "$RELEASE_QA_DISCORD_LIVE_CI_ENABLED" | tr '[:upper:]' '[:lower:]')"
          if [[ "$qa_live_discord_ci_enabled" != "true" && "$qa_live_discord_ci_enabled" != "1" && "$qa_live_discord_ci_enabled" != "yes" ]]; then
            qa_live_discord_ci_enabled=false
          else
            qa_live_discord_ci_enabled=true
          fi
          qa_live_whatsapp_ci_enabled="$(printf '%s' "$RELEASE_QA_WHATSAPP_LIVE_CI_ENABLED" | tr '[:upper:]' '[:lower:]')"
          if [[ "$qa_live_whatsapp_ci_enabled" != "true" && "$qa_live_whatsapp_ci_enabled" != "1" && "$qa_live_whatsapp_ci_enabled" != "yes" ]]; then
            qa_live_whatsapp_ci_enabled=false
          else
            qa_live_whatsapp_ci_enabled=true
          fi
          qa_live_slack_ci_enabled="$(printf '%s' "$RELEASE_QA_SLACK_LIVE_CI_ENABLED" | tr '[:upper:]' '[:lower:]')"
          if [[ "$qa_live_slack_ci_enabled" != "true" && "$qa_live_slack_ci_enabled" != "1" && "$qa_live_slack_ci_enabled" != "yes" ]]; then
            qa_live_slack_ci_enabled=false
          else
            qa_live_slack_ci_enabled=true
          fi
          qa_live_discord_enabled="$qa_live_discord_ci_enabled"
          qa_live_whatsapp_enabled="$qa_live_whatsapp_ci_enabled"
          qa_live_slack_enabled="$qa_live_slack_ci_enabled"
          run_release_soak="$(printf '%s' "$RELEASE_RUN_RELEASE_SOAK_INPUT" | tr '[:upper:]' '[:lower:]')"
          if [[ "$run_release_soak" != "true" && "$run_release_soak" != "1" && "$run_release_soak" != "yes" ]]; then
            run_release_soak=false
          else
            run_release_soak=true
          fi
          release_profile="$RELEASE_PROFILE_INPUT"
          if [[ "$release_profile" == "minimum" ]]; then
            release_profile=beta
          fi
          case "$release_profile" in
            beta|stable|full) ;;
            *)
              echo "release_profile must be one of: beta, stable, full" >&2
              exit 1
              ;;
          esac
          if [[ "$release_profile" == "full" ]]; then
            run_release_soak=true
          fi
          codex_plugin_spec="$RELEASE_CODEX_PLUGIN_SPEC_INPUT"
          if [[ -z "${codex_plugin_spec// }" && "$RELEASE_PACKAGE_SPEC_INPUT" =~ ^openclaw@(.+)$ ]]; then
            codex_plugin_spec="npm:@openclaw/codex@${BASH_REMATCH[1]}"
          fi

          filter="$(printf '%s' "$RELEASE_LIVE_SUITE_FILTER_INPUT" | tr '[:upper:]' '[:lower:]')"
          if [[ -n "${filter// }" ]]; then
            qa_filter_seen=false
            matrix_selected=false
            telegram_selected=false
            discord_selected=false
            whatsapp_selected=false
            slack_selected=false

            IFS=', ' read -r -a filter_tokens <<< "$filter"
            for token in "${filter_tokens[@]}"; do
              token="${token//$'\t'/}"
              token="${token//$'\r'/}"
              token="${token//$'\n'/}"
              [[ -z "$token" ]] && continue
              case "$token" in
                qa-live|qa-live-all|qa-all)
                  qa_filter_seen=true
                  matrix_selected=true
                  telegram_selected=true
                  discord_selected="$qa_live_discord_ci_enabled"
                  whatsapp_selected="$qa_live_whatsapp_ci_enabled"
                  slack_selected="$qa_live_slack_ci_enabled"
                  ;;
                qa-live-non-slack|qa-non-slack|non-slack|no-slack|without-slack)
                  qa_filter_seen=true
                  matrix_selected=true
                  telegram_selected=true
                  discord_selected="$qa_live_discord_ci_enabled"
                  whatsapp_selected="$qa_live_whatsapp_ci_enabled"
                  ;;
                qa-live-matrix|qa-matrix|matrix)
                  qa_filter_seen=true
                  matrix_selected=true
                  ;;
                qa-live-telegram|qa-telegram|telegram)
                  qa_filter_seen=true
                  telegram_selected=true
                  ;;
                qa-live-discord|qa-discord|discord)
                  qa_filter_seen=true
                  discord_selected="$qa_live_discord_ci_enabled"
                  ;;
                qa-live-whatsapp|qa-whatsapp|whatsapp)
                  qa_filter_seen=true
                  whatsapp_selected="$qa_live_whatsapp_ci_enabled"
                  ;;
                qa-live-slack|qa-slack|slack)
                  qa_filter_seen=true
                  slack_selected="$qa_live_slack_ci_enabled"
                  ;;
              esac
            done

            if [[ "$qa_filter_seen" == "true" ]]; then
              qa_live_matrix_enabled="$matrix_selected"
              qa_live_telegram_enabled="$telegram_selected"
              qa_live_discord_enabled="$discord_selected"
              qa_live_whatsapp_enabled="$whatsapp_selected"
              qa_live_slack_enabled="$slack_selected"
            fi
          fi

          {
            printf 'ref=%s\n' "$RELEASE_REF_INPUT"
            printf 'provider=%s\n' "$RELEASE_PROVIDER_INPUT"
            printf 'mode=%s\n' "$RELEASE_MODE_INPUT"
            printf 'release_profile=%s\n' "$release_profile"
            printf 'run_release_soak=%s\n' "$run_release_soak"
            printf 'rerun_group=%s\n' "$RELEASE_RERUN_GROUP_INPUT"
            printf 'live_suite_filter=%s\n' "$RELEASE_LIVE_SUITE_FILTER_INPUT"
            printf 'cross_os_suite_filter=%s\n' "$RELEASE_CROSS_OS_SUITE_FILTER_INPUT"
            printf 'qa_live_matrix_enabled=%s\n' "$qa_live_matrix_enabled"
            printf 'qa_live_telegram_enabled=%s\n' "$qa_live_telegram_enabled"
            printf 'qa_live_discord_enabled=%s\n' "$qa_live_discord_enabled"
            printf 'qa_live_whatsapp_enabled=%s\n' "$qa_live_whatsapp_enabled"
            printf 'qa_live_slack_enabled=%s\n' "$qa_live_slack_enabled"
            printf 'release_package_spec=%s\n' "$RELEASE_PACKAGE_SPEC_INPUT"
            printf 'package_acceptance_package_spec=%s\n' "$RELEASE_PACKAGE_ACCEPTANCE_PACKAGE_SPEC_INPUT"
            printf 'codex_plugin_spec=%s\n' "$codex_plugin_spec"
          } >> "$GITHUB_OUTPUT"

      - name: Summarize validated ref
        env:
          RELEASE_REF: ${{ inputs.ref }}
          RELEASE_SHA: ${{ steps.ref.outputs.sha }}
          RELEASE_REF_FAST_PATH: ${{ steps.fast_ref.outputs.fast }}
          RELEASE_PROVIDER: ${{ inputs.provider }}
          RELEASE_MODE: ${{ inputs.mode }}
          RELEASE_PROFILE: ${{ steps.inputs.outputs.release_profile }}
          RUN_RELEASE_SOAK: ${{ steps.inputs.outputs.run_release_soak }}
          RELEASE_RERUN_GROUP: ${{ inputs.rerun_group }}
          RELEASE_LIVE_SUITE_FILTER: ${{ inputs.live_suite_filter }}
          RELEASE_CROSS_OS_SUITE_FILTER: ${{ inputs.cross_os_suite_filter }}
          RELEASE_PACKAGE_SPEC: ${{ inputs.release_package_spec }}
          PACKAGE_ACCEPTANCE_PACKAGE_SPEC: ${{ inputs.package_acceptance_package_spec }}
          CODEX_PLUGIN_SPEC: ${{ steps.inputs.outputs.codex_plugin_spec }}
        run: |
          {
            echo "## Release checks"
            echo
            echo "- Requested ref: \`${RELEASE_REF}\`"
            echo "- Validated SHA: \`${RELEASE_SHA}\`"
            echo "- Ref resolution fast path: \`${RELEASE_REF_FAST_PATH}\`"
            echo "- Cross-OS provider: \`${RELEASE_PROVIDER}\`"
            echo "- Cross-OS mode: \`${RELEASE_MODE}\`"
            echo "- Release profile: \`${RELEASE_PROFILE}\`"
            echo "- Release soak lanes: \`${RUN_RELEASE_SOAK}\`"
            echo "- Rerun group: \`${RELEASE_RERUN_GROUP}\`"
            if [[ -n "${RELEASE_LIVE_SUITE_FILTER// }" ]]; then
              echo "- Live suite filter: \`${RELEASE_LIVE_SUITE_FILTER}\`"
            fi
            if [[ -n "${RELEASE_CROSS_OS_SUITE_FILTER// }" ]]; then
              echo "- Cross-OS suite filter: \`${RELEASE_CROSS_OS_SUITE_FILTER}\`"
            fi
            echo "- QA live lanes: Matrix \`${{ steps.inputs.outputs.qa_live_matrix_enabled }}\`, Telegram \`${{ steps.inputs.outputs.qa_live_telegram_enabled }}\`, Discord \`${{ steps.inputs.outputs.qa_live_discord_enabled }}\`, WhatsApp \`${{ steps.inputs.outputs.qa_live_whatsapp_enabled }}\`, Slack \`${{ steps.inputs.outputs.qa_live_slack_enabled }}\`"
            if [[ -n "${RELEASE_PACKAGE_SPEC// }" ]]; then
              echo "- Release package spec: \`${RELEASE_PACKAGE_SPEC}\`"
            fi
            if [[ -n "${PACKAGE_ACCEPTANCE_PACKAGE_SPEC// }" ]]; then
              echo "- Package Acceptance package spec: \`${PACKAGE_ACCEPTANCE_PACKAGE_SPEC}\`"
            elif [[ -n "${RELEASE_PACKAGE_SPEC// }" ]]; then
              echo "- Package Acceptance package spec: \`${RELEASE_PACKAGE_SPEC}\`"
            else
              echo "- Package Acceptance package spec: prepared release artifact"
            fi
            if [[ -n "${CODEX_PLUGIN_SPEC// }" ]]; then
              echo "- Codex plugin spec: \`${CODEX_PLUGIN_SPEC}\`"
            else
              echo "- Codex plugin spec: packed from selected ref"
            fi
            if [[ "$RUN_RELEASE_SOAK" == "true" ]]; then
              echo "- This run will execute blocking release validation plus exhaustive live/Docker soak coverage."
            else
              echo "- This run will execute blocking release validation. Exhaustive live/Docker soak lanes are skipped unless \`run_release_soak=true\`, \`release_profile=full\`, or \`rerun_group=live-e2e\` is selected."
            fi
          } >> "$GITHUB_STEP_SUMMARY"

  prepare_release_package:
    name: Prepare release package artifact
    needs: [resolve_target]
    if: contains(fromJSON('["all","cross-os","package"]'), needs.resolve_target.outputs.rerun_group) || (needs.resolve_target.outputs.rerun_group == 'live-e2e' && needs.resolve_target.outputs.live_suite_filter == '')
    runs-on: ubuntu-24.04
    timeout-minutes: 15
    permissions:
      contents: read
      packages: write
    outputs:
      artifact_name: ${{ steps.artifact.outputs.name }}
      package_sha256: ${{ steps.package.outputs.sha256 }}
      package_version: ${{ steps.package.outputs.package_version }}
      source_sha: ${{ steps.package.outputs.source_sha }}
    steps:
      - name: Checkout trusted workflow ref
        uses: actions/checkout@v6
        with:
          persist-credentials: true
          ref: ${{ github.ref_name }}
          fetch-depth: 0

      - name: Set artifact metadata
        id: artifact
        run: echo "name=release-package-under-test" >> "$GITHUB_OUTPUT"

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

      - name: Resolve release package artifact
        id: package
        shell: bash
        env:
          PACKAGE_REF: ${{ needs.resolve_target.outputs.revision }}
          RELEASE_PACKAGE_SPEC: ${{ needs.resolve_target.outputs.release_package_spec }}
        run: |
          set -euo pipefail
          source_args=(--source ref --package-ref "$PACKAGE_REF")
          package_label="ref:${PACKAGE_REF}"
          if [[ -n "${RELEASE_PACKAGE_SPEC// }" ]]; then
            source_args=(--source npm --package-spec "$RELEASE_PACKAGE_SPEC")
            package_label="$RELEASE_PACKAGE_SPEC"
          fi
          node scripts/resolve-openclaw-package-candidate.mjs \
            "${source_args[@]}" \
            --output-dir .artifacts/docker-e2e-package \
            --output-name openclaw-current.tgz \
            --metadata .artifacts/docker-e2e-package/package-candidate.json \
            --github-output "$GITHUB_OUTPUT"
          digest="$(node -p "JSON.parse(require('fs').readFileSync('.artifacts/docker-e2e-package/package-candidate.json', 'utf8')).sha256")"
          version="$(node -p "JSON.parse(require('fs').readFileSync('.artifacts/docker-e2e-package/package-candidate.json', 'utf8')).version")"
          source_sha="$(node -p "JSON.parse(require('fs').readFileSync('.artifacts/docker-e2e-package/package-candidate.json', 'utf8')).packageSourceSha")"
          echo "source_sha=$source_sha" >> "$GITHUB_OUTPUT"
          {
            echo "## Release package artifact"
            echo
            echo "- Artifact: \`release-package-under-test\`"
            echo "- Package: \`$package_label\`"
            echo "- SHA-256: \`$digest\`"
            echo "- Version: \`$version\`"
            echo "- Source SHA: \`$source_sha\`"
          } >> "$GITHUB_STEP_SUMMARY"

      - name: Upload release package artifact
        uses: actions/upload-artifact@v7
        with:
          name: release-package-under-test
          path: |
            .artifacts/docker-e2e-package/openclaw-current.tgz
            .artifacts/docker-e2e-package/package-candidate.json
          retention-days: 14
          if-no-files-found: error

  install_smoke_release_checks:
    needs: [resolve_target]
    if: contains(fromJSON('["all","install-smoke"]'), needs.resolve_target.outputs.rerun_group)
    permissions:
      contents: read
      packages: write
    uses: ./.github/workflows/install-smoke.yml
    with:
      ref: ${{ needs.resolve_target.outputs.revision }}
      run_bun_global_install_smoke: true

  cross_os_release_checks:
    needs: [resolve_target, prepare_release_package]
    if: contains(fromJSON('["all","cross-os"]'), needs.resolve_target.outputs.rerun_group)
    permissions: read-all
    uses: ./.github/workflows/openclaw-cross-os-release-checks-reusable.yml
    with:
      advisory: ${{ startsWith(github.ref, 'refs/heads/tideclaw/alpha/') }}
      ref: ${{ needs.resolve_target.outputs.revision }}
      provider: ${{ needs.resolve_target.outputs.provider }}
      mode: ${{ needs.resolve_target.outputs.mode }}
      suite_filter: ${{ needs.resolve_target.outputs.cross_os_suite_filter }}
      candidate_artifact_name: ${{ needs.prepare_release_package.outputs.artifact_name }}
      candidate_file_name: openclaw-current.tgz
      candidate_version: ${{ needs.prepare_release_package.outputs.package_version }}
      candidate_source_sha: ${{ needs.prepare_release_package.outputs.source_sha }}
      openai_model: openai/gpt-5.5
      ubuntu_runner: ubuntu-24.04
      windows_runner: windows-2025
      macos_runner: macos-26
    secrets:
      OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
      ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
      MINIMAX_API_KEY: ${{ secrets.MINIMAX_API_KEY }}
      OPENCLAW_DISCORD_SMOKE_BOT_TOKEN: ${{ secrets.OPENCLAW_DISCORD_SMOKE_BOT_TOKEN }}
      OPENCLAW_DISCORD_SMOKE_GUILD_ID: ${{ secrets.OPENCLAW_DISCORD_SMOKE_GUILD_ID }}
      OPENCLAW_DISCORD_SMOKE_CHANNEL_ID: ${{ secrets.OPENCLAW_DISCORD_SMOKE_CHANNEL_ID }}

  live_repo_e2e_release_checks:
    name: Run repo/live E2E validation
    needs: [resolve_target]
    if: needs.resolve_target.outputs.rerun_group == 'live-e2e' || (needs.resolve_target.outputs.rerun_group == 'all' && needs.resolve_target.outputs.run_release_soak == 'true')
    permissions:
      actions: read
      contents: read
      packages: write
      pull-requests: read
    uses: ./.github/workflows/openclaw-live-and-e2e-checks-reusable.yml
    with:
      advisory: ${{ startsWith(github.ref, 'refs/heads/tideclaw/alpha/') }}
      ref: ${{ needs.resolve_target.outputs.revision }}
      include_repo_e2e: true
      include_release_path_suites: false
      include_openwebui: false
      include_live_suites: true
      release_test_profile: ${{ needs.resolve_target.outputs.release_profile }}
      live_suite_filter: ${{ needs.resolve_target.outputs.live_suite_filter }}
    secrets: &live_e2e_release_secrets
      OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
      OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
      ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
      ANTHROPIC_API_KEY_OLD: ${{ secrets.ANTHROPIC_API_KEY_OLD }}
      ANTHROPIC_API_TOKEN: ${{ secrets.ANTHROPIC_API_TOKEN }}
      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 }}

  docker_e2e_release_checks:
    name: Run Docker release-path validation
    needs: [resolve_target, prepare_release_package]
    if: (needs.resolve_target.outputs.rerun_group == 'live-e2e' || (needs.resolve_target.outputs.rerun_group == 'all' && needs.resolve_target.outputs.run_release_soak == 'true')) && needs.resolve_target.outputs.live_suite_filter == ''
    permissions:
      actions: read
      contents: read
      packages: write
      pull-requests: read
    uses: ./.github/workflows/openclaw-live-and-e2e-checks-reusable.yml
    with:
      advisory: ${{ startsWith(github.ref, 'refs/heads/tideclaw/alpha/') }}
      ref: ${{ needs.resolve_target.outputs.revision }}
      include_repo_e2e: false
      include_release_path_suites: true
      include_openwebui: ${{ needs.resolve_target.outputs.release_profile != 'beta' }}
      include_live_suites: false
      release_test_profile: ${{ needs.resolve_target.outputs.release_profile }}
      package_artifact_name: ${{ needs.prepare_release_package.outputs.artifact_name }}
      codex_plugin_spec: ${{ needs.resolve_target.outputs.codex_plugin_spec }}
    secrets: *live_e2e_release_secrets

  package_acceptance_release_checks:
    name: Run package acceptance
    needs: [resolve_target, prepare_release_package]
    if: contains(fromJSON('["all","package"]'), needs.resolve_target.outputs.rerun_group)
    permissions:
      actions: read
      contents: read
      packages: write
      pull-requests: read
    uses: ./.github/workflows/package-acceptance.yml
    with:
      advisory: false
      workflow_ref: ${{ github.ref_name }}
      source: ${{ (needs.resolve_target.outputs.package_acceptance_package_spec != '' || needs.resolve_target.outputs.release_package_spec != '') && 'npm' || 'artifact' }}
      package_spec: ${{ needs.resolve_target.outputs.package_acceptance_package_spec || needs.resolve_target.outputs.release_package_spec || 'openclaw@beta' }}
      artifact_name: ${{ needs.prepare_release_package.outputs.artifact_name }}
      package_sha256: ${{ (needs.resolve_target.outputs.package_acceptance_package_spec == '' && needs.resolve_target.outputs.release_package_spec == '') && needs.prepare_release_package.outputs.package_sha256 || '' }}
      suite_profile: custom
      docker_lanes: doctor-switch update-channel-switch skill-install update-corrupt-plugin upgrade-survivor published-upgrade-survivor root-managed-vps-upgrade update-restart-auth plugins-offline plugin-update plugin-binding-command-escape
      published_upgrade_survivor_baselines: ${{ needs.resolve_target.outputs.run_release_soak == 'true' && 'last-stable-4 2026.4.23 2026.5.2 2026.4.15' || '' }}
      published_upgrade_survivor_scenarios: ${{ needs.resolve_target.outputs.run_release_soak == 'true' && 'reported-issues' || '' }}
      telegram_mode: mock-openai
      telegram_scenarios: telegram-help-command,telegram-commands-command,telegram-tools-compact-command,telegram-whoami-command,telegram-status-command,telegram-other-bot-command-gating,telegram-context-command,telegram-mentioned-message-reply,telegram-long-final-reuses-preview,telegram-mention-gating
    secrets:
      OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
      OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }}
      ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
      ANTHROPIC_API_KEY_OLD: ${{ secrets.ANTHROPIC_API_KEY_OLD }}
      ANTHROPIC_API_TOKEN: ${{ secrets.ANTHROPIC_API_TOKEN }}
      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_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
      OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}

  qa_lab_parity_lane_release_checks:
    name: Run QA Lab parity lane (${{ matrix.lane }})
    needs: [resolve_target]
    if: contains(fromJSON('["all","qa","qa-parity"]'), needs.resolve_target.outputs.rerun_group)
    continue-on-error: true
    runs-on: ubuntu-24.04
    timeout-minutes: 30
    permissions:
      contents: read
    strategy:
      fail-fast: false
      matrix:
        include:
          - lane: candidate
            output_dir: openai-candidate
          - lane: baseline
            output_dir: anthropic-baseline
    env:
      QA_PARITY_CONCURRENCY: "1"
      OPENCLAW_QA_TRANSPORT_READY_TIMEOUT_MS: "180000"
      OPENAI_API_KEY: ""
      ANTHROPIC_API_KEY: ""
      OPENCLAW_LIVE_OPENAI_KEY: ""
      OPENCLAW_LIVE_ANTHROPIC_KEY: ""
      OPENCLAW_LIVE_GEMINI_KEY: ""
      OPENCLAW_LIVE_SETUP_TOKEN_VALUE: ""
      OPENCLAW_BUILD_PRIVATE_QA: "1"
      OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1"
    steps:
      - name: Checkout selected ref
        uses: actions/checkout@v6
        with:
          persist-credentials: true
          ref: ${{ needs.resolve_target.outputs.revision }}
          fetch-depth: 1

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

      - name: Build private QA runtime
        env:
          NODE_OPTIONS: --max-old-space-size=8192
        run: pnpm build

      - name: Run parity lane
        env:
          QA_PARITY_LANE: ${{ matrix.lane }}
          QA_PARITY_OUTPUT_DIR: ${{ matrix.output_dir }}
        run: |
          set -euo pipefail

          case "${QA_PARITY_LANE}" in
            candidate)
              model="${OPENCLAW_CI_OPENAI_MODEL}"
              alt_model="openai/gpt-5.5-alt"
              ;;
            baseline)
              model="anthropic/claude-opus-4-8"
              alt_model="anthropic/claude-sonnet-4-6"
              ;;
            *)
              echo "Unknown QA parity lane: ${QA_PARITY_LANE}" >&2
              exit 1
              ;;
          esac

          pnpm openclaw qa suite \
            --provider-mode mock-openai \
            --parity-pack agentic \
            --concurrency "${QA_PARITY_CONCURRENCY}" \
            --model "${model}" \
            --alt-model "${alt_model}" \
            --output-dir ".artifacts/qa-e2e/${QA_PARITY_OUTPUT_DIR}"

      - name: Upload parity lane artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: release-qa-parity-${{ matrix.lane }}-${{ needs.resolve_target.outputs.revision }}
          path: .artifacts/qa-e2e/
          retention-days: 14
          if-no-files-found: warn

  qa_lab_parity_report_release_checks:
    name: Run QA Lab parity report
    needs: [resolve_target, qa_lab_parity_lane_release_checks]
    if: contains(fromJSON('["all","qa","qa-parity"]'), needs.resolve_target.outputs.rerun_group)
    continue-on-error: true
    runs-on: ubuntu-24.04
    timeout-minutes: 20
    permissions:
      contents: read
      actions: read
    env:
      OPENCLAW_BUILD_PRIVATE_QA: "1"
      OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1"
    steps:
      - name: Checkout selected ref
        uses: actions/checkout@v6
        with:
          persist-credentials: true
          ref: ${{ needs.resolve_target.outputs.revision }}
          fetch-depth: 1

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

      - name: Download parity lane artifacts
        uses: actions/download-artifact@v8
        with:
          pattern: release-qa-parity-*-${{ needs.resolve_target.outputs.revision }}
          path: .artifacts/qa-e2e/
          merge-multiple: true

      - name: Build private QA runtime
        env:
          NODE_OPTIONS: --max-old-space-size=8192
        run: pnpm build

      - name: Generate parity report
        run: |
          pnpm openclaw qa parity-report \
            --repo-root . \
            --candidate-summary .artifacts/qa-e2e/openai-candidate/qa-suite-summary.json \
            --baseline-summary .artifacts/qa-e2e/anthropic-baseline/qa-suite-summary.json \
            --candidate-label "${OPENCLAW_CI_OPENAI_MODEL}" \
            --baseline-label anthropic/claude-opus-4-8 \
            --output-dir .artifacts/qa-e2e/parity

      - name: Upload parity artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: release-qa-parity-${{ needs.resolve_target.outputs.revision }}
          path: .artifacts/qa-e2e/
          retention-days: 14
          if-no-files-found: warn

  qa_lab_runtime_parity_release_checks:
    name: Run QA Lab runtime parity lane
    needs: [resolve_target]
    if: contains(fromJSON('["all","qa","qa-parity"]'), needs.resolve_target.outputs.rerun_group)
    continue-on-error: true
    runs-on: blacksmith-8vcpu-ubuntu-2404
    timeout-minutes: 30
    permissions:
      contents: read
    env:
      QA_PARITY_CONCURRENCY: "1"
      OPENCLAW_QA_TRANSPORT_READY_TIMEOUT_MS: "180000"
      OPENAI_API_KEY: ""
      ANTHROPIC_API_KEY: ""
      OPENCLAW_LIVE_OPENAI_KEY: ""
      OPENCLAW_LIVE_ANTHROPIC_KEY: ""
      OPENCLAW_LIVE_GEMINI_KEY: ""
      OPENCLAW_LIVE_SETUP_TOKEN_VALUE: ""
      OPENCLAW_BUILD_PRIVATE_QA: "1"
      OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1"
    steps:
      - name: Checkout selected ref
        uses: actions/checkout@v6
        with:
          persist-credentials: true
          ref: ${{ needs.resolve_target.outputs.revision }}
          fetch-depth: 1

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

      - name: Build private QA runtime
        env:
          NODE_OPTIONS: --max-old-space-size=8192
        run: pnpm build

      - name: Run runtime parity lane
        id: runtime_parity_lane
        run: |
          set -euo pipefail
          pnpm openclaw qa suite \
            --provider-mode mock-openai \
            --parity-pack agentic \
            --concurrency "${QA_PARITY_CONCURRENCY}" \
            --model "${OPENCLAW_CI_OPENAI_MODEL}" \
            --alt-model "openai/gpt-5.5-alt" \
            --runtime-pair openclaw,codex \
            --output-dir ".artifacts/qa-e2e/runtime-parity"

      - name: Run standard runtime parity tier
        if: ${{ always() && steps.runtime_parity_lane.outcome != 'skipped' && steps.runtime_parity_lane.outcome != 'cancelled' }}
        run: |
          set -euo pipefail
          pnpm openclaw qa suite \
            --provider-mode mock-openai \
            --runtime-parity-tier standard \
            --concurrency "${QA_PARITY_CONCURRENCY}" \
            --model "${OPENCLAW_CI_OPENAI_MODEL}" \
            --alt-model "openai/gpt-5.5-alt" \
            --runtime-pair openclaw,codex \
            --output-dir ".artifacts/qa-e2e/runtime-parity-standard"

      - name: Run soak runtime parity tier
        id: runtime_parity_soak_lane
        if: ${{ always() && needs.resolve_target.outputs.run_release_soak == 'true' && steps.runtime_parity_lane.outcome != 'skipped' && steps.runtime_parity_lane.outcome != 'cancelled' }}
        run: |
          set -euo pipefail
          pnpm openclaw qa suite \
            --provider-mode mock-openai \
            --runtime-parity-tier soak \
            --concurrency "${QA_PARITY_CONCURRENCY}" \
            --model "${OPENCLAW_CI_OPENAI_MODEL}" \
            --alt-model "openai/gpt-5.5-alt" \
            --runtime-pair openclaw,codex \
            --output-dir ".artifacts/qa-e2e/runtime-parity-soak"

      - name: Generate runtime parity report
        if: always()
        run: |
          set -euo pipefail
          pnpm openclaw qa parity-report \
            --repo-root . \
            --runtime-axis \
            --summary .artifacts/qa-e2e/runtime-parity/qa-suite-summary.json \
            --output-dir .artifacts/qa-e2e/runtime-parity-report

      - name: Generate standard runtime parity report
        if: always()
        run: |
          set -euo pipefail
          pnpm openclaw qa parity-report \
            --repo-root . \
            --runtime-axis \
            --summary .artifacts/qa-e2e/runtime-parity-standard/qa-suite-summary.json \
            --output-dir .artifacts/qa-e2e/runtime-parity-standard-report

      - name: Generate soak runtime parity report
        if: ${{ always() && needs.resolve_target.outputs.run_release_soak == 'true' && steps.runtime_parity_soak_lane.outcome != 'skipped' && steps.runtime_parity_soak_lane.outcome != 'cancelled' }}
        run: |
          set -euo pipefail
          summary=".artifacts/qa-e2e/runtime-parity-soak/qa-suite-summary.json"
          if [[ ! -f "$summary" ]]; then
            echo "No soak runtime parity summary was produced."
            exit 0
          fi
          pnpm openclaw qa parity-report \
            --repo-root . \
            --runtime-axis \
            --summary "$summary" \
            --output-dir .artifacts/qa-e2e/runtime-parity-soak-report

      - name: Upload runtime parity artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: release-qa-runtime-parity-${{ needs.resolve_target.outputs.revision }}
          path: .artifacts/qa-e2e/
          retention-days: 14
          if-no-files-found: warn

  runtime_tool_coverage_release_checks:
    name: Enforce QA Lab runtime tool coverage
    needs: [resolve_target, qa_lab_runtime_parity_release_checks]
    if: always() && contains(fromJSON('["all","qa","qa-parity"]'), needs.resolve_target.outputs.rerun_group)
    runs-on: ubuntu-24.04
    timeout-minutes: 15
    permissions:
      contents: read
      actions: read
    env:
      OPENCLAW_BUILD_PRIVATE_QA: "1"
      OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1"
    steps:
      - name: Checkout selected ref
        uses: actions/checkout@v6
        with:
          persist-credentials: true
          ref: ${{ needs.resolve_target.outputs.revision }}
          fetch-depth: 1

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

      - name: Download runtime parity artifacts
        uses: actions/download-artifact@v8
        with:
          name: release-qa-runtime-parity-${{ needs.resolve_target.outputs.revision }}
          path: .artifacts/qa-e2e/

      - name: Enforce standard runtime tool coverage
        run: |
          set -euo pipefail
          pnpm openclaw qa coverage \
            --repo-root . \
            --tools \
            --summary .artifacts/qa-e2e/runtime-parity-standard/qa-suite-summary.json \
            --output .artifacts/qa-e2e/runtime-parity-standard-report/qa-runtime-tool-coverage-report.md

      - name: Upload runtime tool coverage artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: release-qa-runtime-tool-coverage-${{ needs.resolve_target.outputs.revision }}
          path: .artifacts/qa-e2e/runtime-parity-standard-report/
          retention-days: 14
          if-no-files-found: warn

  qa_live_matrix_release_checks:
    name: Run QA Lab live Matrix lane
    needs: [resolve_target]
    if: contains(fromJSON('["all","qa","qa-live"]'), needs.resolve_target.outputs.rerun_group) && needs.resolve_target.outputs.qa_live_matrix_enabled == 'true'
    continue-on-error: true
    runs-on: ubuntu-24.04
    timeout-minutes: 60
    permissions:
      contents: read
      pull-requests: read
    environment: qa-live-shared
    env:
      OPENCLAW_BUILD_PRIVATE_QA: "1"
      OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1"
    steps:
      - name: Checkout selected ref
        uses: actions/checkout@v6
        with:
          persist-credentials: true
          ref: ${{ needs.resolve_target.outputs.revision }}
          fetch-depth: 1

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

      - name: Build private QA runtime
        env:
          NODE_OPTIONS: --max-old-space-size=8192
        run: pnpm build

      - name: Run Matrix live lane
        id: run_lane
        shell: bash
        env:
          OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
          OPENCLAW_QA_MATRIX_CANARY_TIMEOUT_MS: "90000"
          OPENCLAW_QA_MATRIX_NO_REPLY_WINDOW_MS: "3000"
        run: |
          set -euo pipefail

          output_dir=".artifacts/qa-e2e/matrix-live-release-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
          echo "output_dir=${output_dir}" >> "$GITHUB_OUTPUT"

          matrix_args=(
            --repo-root . \
            --provider-mode mock-openai \
            --model mock-openai/gpt-5.5 \
            --alt-model mock-openai/gpt-5.5-alt \
            --profile fast \
            --fast
          )
          if pnpm openclaw qa matrix --help 2>/dev/null | grep -F -q -- "--fail-fast"; then
            matrix_args+=(--fail-fast)
          fi

          for attempt in 1 2; do
            attempt_output_dir="${output_dir}/attempt-${attempt}"
            if pnpm openclaw qa matrix --output-dir "${attempt_output_dir}" "${matrix_args[@]}"; then
              exit 0
            fi
            if [[ "${attempt}" == "2" ]]; then
              exit 1
            fi
            echo "Matrix live lane failed on attempt ${attempt}; retrying once..." >&2
            sleep 10
          done

      - name: Upload Matrix QA artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: release-qa-live-matrix-${{ needs.resolve_target.outputs.revision }}
          path: .artifacts/qa-e2e/
          retention-days: 14
          if-no-files-found: warn

  qa_live_telegram_release_checks:
    name: Run QA Lab live Telegram lane
    needs: [resolve_target]
    if: contains(fromJSON('["all","qa","qa-live"]'), needs.resolve_target.outputs.rerun_group) && needs.resolve_target.outputs.qa_live_telegram_enabled == 'true'
    continue-on-error: true
    runs-on: ubuntu-24.04
    timeout-minutes: 60
    permissions:
      contents: read
      pull-requests: read
    environment: qa-live-shared
    env:
      OPENCLAW_BUILD_PRIVATE_QA: "1"
      OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1"
    steps:
      - name: Checkout selected ref
        uses: actions/checkout@v6
        with:
          persist-credentials: true
          ref: ${{ needs.resolve_target.outputs.revision }}
          fetch-depth: 1

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

      - name: Validate required QA credential env
        env:
          OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
          OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
        shell: bash
        run: |
          set -euo pipefail

          require_var() {
            local key="$1"
            if [[ -z "${!key:-}" ]]; then
              echo "Missing required ${key}." >&2
              exit 1
            fi
          }

          require_var OPENCLAW_QA_CONVEX_SITE_URL
          require_var OPENCLAW_QA_CONVEX_SECRET_CI

      - name: Build private QA runtime
        env:
          NODE_OPTIONS: --max-old-space-size=8192
        run: pnpm build

      - name: Run Telegram live lane
        id: run_lane
        shell: bash
        env:
          OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
          OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
          OPENCLAW_QA_CREDENTIAL_ACQUIRE_TIMEOUT_MS: "1800000"
          OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
          OPENCLAW_QA_TELEGRAM_CAPTURE_CONTENT: "1"
        run: |
          set -euo pipefail

          output_dir=".artifacts/qa-e2e/telegram-live-release-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
          echo "output_dir=${output_dir}" >> "$GITHUB_OUTPUT"

          for attempt in 1 2; do
            attempt_output_dir="${output_dir}/attempt-${attempt}"
            if pnpm openclaw qa telegram \
              --repo-root . \
              --output-dir "${attempt_output_dir}" \
              --provider-mode mock-openai \
              --model mock-openai/gpt-5.5 \
              --alt-model mock-openai/gpt-5.5-alt \
              --fast \
              --credential-source convex \
              --credential-role ci; then
              exit 0
            fi
            if [[ "${attempt}" == "2" ]]; then
              exit 1
            fi
            echo "Telegram live lane failed on attempt ${attempt}; retrying once..." >&2
            sleep 10
          done

      - name: Upload Telegram QA artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: release-qa-live-telegram-${{ needs.resolve_target.outputs.revision }}
          path: .artifacts/qa-e2e/
          retention-days: 14
          if-no-files-found: warn

  qa_live_discord_release_checks:
    name: Run QA Lab live Discord lane
    needs: [resolve_target]
    if: contains(fromJSON('["all","qa","qa-live"]'), needs.resolve_target.outputs.rerun_group) && needs.resolve_target.outputs.qa_live_discord_enabled == 'true' && vars.OPENCLAW_RELEASE_QA_DISCORD_LIVE_CI_ENABLED == 'true'
    continue-on-error: true
    runs-on: ubuntu-24.04
    timeout-minutes: 60
    permissions:
      contents: read
      pull-requests: read
    environment: qa-live-shared
    env:
      OPENCLAW_BUILD_PRIVATE_QA: "1"
      OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1"
    steps:
      - name: Checkout selected ref
        uses: actions/checkout@v6
        with:
          persist-credentials: true
          ref: ${{ needs.resolve_target.outputs.revision }}
          fetch-depth: 1

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

      - name: Validate required QA credential env
        env:
          OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
          OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
        shell: bash
        run: |
          set -euo pipefail

          require_var() {
            local key="$1"
            if [[ -z "${!key:-}" ]]; then
              echo "Missing required ${key}." >&2
              exit 1
            fi
          }

          require_var OPENCLAW_QA_CONVEX_SITE_URL
          require_var OPENCLAW_QA_CONVEX_SECRET_CI

      - name: Build private QA runtime
        env:
          NODE_OPTIONS: --max-old-space-size=8192
        run: pnpm build

      - name: Run Discord live lane
        id: run_lane
        shell: bash
        env:
          OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
          OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
          OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
          OPENCLAW_QA_DISCORD_CAPTURE_CONTENT: "1"
        run: |
          set -euo pipefail

          output_dir=".artifacts/qa-e2e/discord-live-release-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
          echo "output_dir=${output_dir}" >> "$GITHUB_OUTPUT"

          for attempt in 1 2; do
            attempt_output_dir="${output_dir}/attempt-${attempt}"
            if pnpm openclaw qa discord \
              --repo-root . \
              --output-dir "${attempt_output_dir}" \
              --provider-mode mock-openai \
              --model mock-openai/gpt-5.5 \
              --alt-model mock-openai/gpt-5.5-alt \
              --fast \
              --credential-source convex \
              --credential-role ci; then
              exit 0
            fi
            if [[ "${attempt}" == "2" ]]; then
              exit 1
            fi
            echo "Discord live lane failed on attempt ${attempt}; retrying once..." >&2
            sleep 10
          done

      - name: Upload Discord QA artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: release-qa-live-discord-${{ needs.resolve_target.outputs.revision }}
          path: .artifacts/qa-e2e/
          retention-days: 14
          if-no-files-found: warn

  qa_live_whatsapp_release_checks:
    name: Run QA Lab live WhatsApp lane
    needs: [resolve_target]
    if: contains(fromJSON('["all","qa","qa-live"]'), needs.resolve_target.outputs.rerun_group) && needs.resolve_target.outputs.qa_live_whatsapp_enabled == 'true' && vars.OPENCLAW_RELEASE_QA_WHATSAPP_LIVE_CI_ENABLED == 'true'
    continue-on-error: true
    runs-on: ubuntu-24.04
    timeout-minutes: 60
    concurrency:
      group: qa-live-whatsapp-shared
      cancel-in-progress: false
    permissions:
      contents: read
      pull-requests: read
    environment: qa-live-shared
    env:
      OPENCLAW_BUILD_PRIVATE_QA: "1"
      OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1"
    steps:
      - name: Checkout selected ref
        uses: actions/checkout@v6
        with:
          persist-credentials: true
          ref: ${{ needs.resolve_target.outputs.revision }}
          fetch-depth: 1

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

      - name: Validate required QA credential env
        env:
          OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
          OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
        shell: bash
        run: |
          set -euo pipefail

          require_var() {
            local key="$1"
            if [[ -z "${!key:-}" ]]; then
              echo "Missing required ${key}." >&2
              exit 1
            fi
          }

          require_var OPENCLAW_QA_CONVEX_SITE_URL
          require_var OPENCLAW_QA_CONVEX_SECRET_CI

      - name: Build private QA runtime
        env:
          NODE_OPTIONS: --max-old-space-size=8192
        run: pnpm build

      - name: Run WhatsApp live lane
        id: run_lane
        shell: bash
        env:
          OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
          OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
          OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
          OPENCLAW_QA_WHATSAPP_CAPTURE_CONTENT: "1"
        run: |
          set -euo pipefail

          output_dir=".artifacts/qa-e2e/whatsapp-live-release-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
          echo "output_dir=${output_dir}" >> "$GITHUB_OUTPUT"

          for attempt in 1 2; do
            attempt_output_dir="${output_dir}/attempt-${attempt}"
            if pnpm openclaw qa whatsapp \
              --repo-root . \
              --output-dir "${attempt_output_dir}" \
              --provider-mode mock-openai \
              --model mock-openai/gpt-5.5 \
              --alt-model mock-openai/gpt-5.5-alt \
              --fast \
              --credential-source convex \
              --credential-role ci; then
              exit 0
            fi
            if [[ "${attempt}" == "2" ]]; then
              exit 1
            fi
            echo "WhatsApp live lane failed on attempt ${attempt}; retrying once..." >&2
            sleep 10
          done

      - name: Upload WhatsApp QA artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: release-qa-live-whatsapp-${{ needs.resolve_target.outputs.revision }}
          path: .artifacts/qa-e2e/
          retention-days: 14
          if-no-files-found: warn

  qa_live_slack_release_checks:
    name: Run QA Lab live Slack lane
    needs: [resolve_target]
    if: contains(fromJSON('["all","qa","qa-live"]'), needs.resolve_target.outputs.rerun_group) && needs.resolve_target.outputs.qa_live_slack_enabled == 'true' && vars.OPENCLAW_RELEASE_QA_SLACK_LIVE_CI_ENABLED == 'true'
    continue-on-error: true
    runs-on: ubuntu-24.04
    timeout-minutes: 60
    permissions:
      contents: read
      pull-requests: read
    environment: qa-live-shared
    env:
      OPENCLAW_BUILD_PRIVATE_QA: "1"
      OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1"
    steps:
      - name: Checkout selected ref
        uses: actions/checkout@v6
        with:
          persist-credentials: true
          ref: ${{ needs.resolve_target.outputs.revision }}
          fetch-depth: 1

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

      - name: Validate required QA credential env
        env:
          OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
          OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
        shell: bash
        run: |
          set -euo pipefail

          require_var() {
            local key="$1"
            if [[ -z "${!key:-}" ]]; then
              echo "Missing required ${key}." >&2
              exit 1
            fi
          }

          require_var OPENCLAW_QA_CONVEX_SITE_URL
          require_var OPENCLAW_QA_CONVEX_SECRET_CI

      - name: Build private QA runtime
        env:
          NODE_OPTIONS: --max-old-space-size=8192
        run: pnpm build

      - name: Run Slack live lane
        id: run_lane
        shell: bash
        env:
          OPENCLAW_QA_CONVEX_SITE_URL: ${{ secrets.OPENCLAW_QA_CONVEX_SITE_URL }}
          OPENCLAW_QA_CONVEX_SECRET_CI: ${{ secrets.OPENCLAW_QA_CONVEX_SECRET_CI }}
          OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1"
          OPENCLAW_QA_SLACK_CAPTURE_CONTENT: "1"
        run: |
          set -euo pipefail

          output_dir=".artifacts/qa-e2e/slack-live-release-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
          echo "output_dir=${output_dir}" >> "$GITHUB_OUTPUT"

          for attempt in 1 2; do
            attempt_output_dir="${output_dir}/attempt-${attempt}"
            if pnpm openclaw qa slack \
              --repo-root . \
              --output-dir "${attempt_output_dir}" \
              --provider-mode mock-openai \
              --model mock-openai/gpt-5.5 \
              --alt-model mock-openai/gpt-5.5-alt \
              --fast \
              --credential-source convex \
              --credential-role ci; then
              exit 0
            fi
            if [[ "${attempt}" == "2" ]]; then
              exit 1
            fi
            echo "Slack live lane failed on attempt ${attempt}; retrying once..." >&2
            sleep 10
          done

      - name: Upload Slack QA artifacts
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: release-qa-live-slack-${{ needs.resolve_target.outputs.revision }}
          path: .artifacts/qa-e2e/
          retention-days: 14
          if-no-files-found: warn

  summary:
    name: Verify release checks
    needs:
      - prepare_release_package
      - install_smoke_release_checks
      - cross_os_release_checks
      - live_repo_e2e_release_checks
      - docker_e2e_release_checks
      - package_acceptance_release_checks
      - qa_lab_parity_lane_release_checks
      - qa_lab_parity_report_release_checks
      - qa_lab_runtime_parity_release_checks
      - runtime_tool_coverage_release_checks
      - qa_live_matrix_release_checks
      - qa_live_telegram_release_checks
      - qa_live_discord_release_checks
      - qa_live_whatsapp_release_checks
      - qa_live_slack_release_checks
    if: always()
    runs-on: ubuntu-24.04
    permissions: {}
    timeout-minutes: 5
    steps:
      - name: Verify release check results
        shell: bash
        env:
          WORKFLOW_REF: ${{ github.ref }}
        run: |
          set -euo pipefail
          failed=0
          tideclaw_alpha=false
          if [[ "${WORKFLOW_REF}" =~ ^refs/heads/tideclaw/alpha/[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{4}Z$ ]]; then
            tideclaw_alpha=true
          fi
          for item in \
            "prepare_release_package=${{ needs.prepare_release_package.result }}" \
            "install_smoke_release_checks=${{ needs.install_smoke_release_checks.result }}" \
            "cross_os_release_checks=${{ needs.cross_os_release_checks.result }}" \
            "live_repo_e2e_release_checks=${{ needs.live_repo_e2e_release_checks.result }}" \
            "docker_e2e_release_checks=${{ needs.docker_e2e_release_checks.result }}" \
            "package_acceptance_release_checks=${{ needs.package_acceptance_release_checks.result }}" \
            "qa_lab_parity_lane_release_checks=${{ needs.qa_lab_parity_lane_release_checks.result }}" \
            "qa_lab_parity_report_release_checks=${{ needs.qa_lab_parity_report_release_checks.result }}" \
            "qa_lab_runtime_parity_release_checks=${{ needs.qa_lab_runtime_parity_release_checks.result }}" \
            "runtime_tool_coverage_release_checks=${{ needs.runtime_tool_coverage_release_checks.result }}" \
            "qa_live_matrix_release_checks=${{ needs.qa_live_matrix_release_checks.result }}" \
            "qa_live_telegram_release_checks=${{ needs.qa_live_telegram_release_checks.result }}" \
            "qa_live_discord_release_checks=${{ needs.qa_live_discord_release_checks.result }}" \
            "qa_live_whatsapp_release_checks=${{ needs.qa_live_whatsapp_release_checks.result }}" \
            "qa_live_slack_release_checks=${{ needs.qa_live_slack_release_checks.result }}"
          do
            name="${item%%=*}"
            result="${item#*=}"
            if [[ "$result" != "success" && "$result" != "skipped" ]]; then
              if [[ "$tideclaw_alpha" == "true" ]]; then
                case "$name" in
                  prepare_release_package|install_smoke_release_checks|package_acceptance_release_checks) ;;
                  *)
                    echo "::warning::${name} ended with ${result}; Tideclaw alpha treats non-package-safety release-check lanes as advisory."
                    continue
                    ;;
                esac
              fi
              if [[ "$name" == qa_* ]]; then
                echo "::warning::${name} ended with ${result}; QA release-check lanes are advisory and do not block release validation."
                continue
              fi
              echo "::error::${name} ended with ${result}"
              failed=1
            fi
          done
          exit "$failed"
