Release Discord RTT #412
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release Discord RTT | |
| on: | |
| schedule: | |
| - cron: "45 */6 * * *" | |
| workflow_dispatch: | |
| inputs: | |
| versions: | |
| description: Space or comma separated OpenClaw versions to measure | |
| required: false | |
| default: "" | |
| type: string | |
| samples: | |
| description: Number of Discord canary RTT samples | |
| required: false | |
| default: "20" | |
| type: string | |
| rss_backfill: | |
| description: Backfill RSS onto existing Discord release rows without changing RTT values | |
| required: false | |
| default: "false" | |
| type: choice | |
| options: | |
| - "false" | |
| - "true" | |
| rss_backfill_limit: | |
| description: Maximum existing release versions to backfill in this run | |
| required: false | |
| default: "14" | |
| type: string | |
| permissions: | |
| actions: read | |
| contents: write | |
| env: | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" | |
| NODE_VERSION: "26.x" | |
| PNPM_VERSION: "11.2.2" | |
| jobs: | |
| resolve: | |
| name: Resolve OpenClaw Discord release packages | |
| runs-on: blacksmith-16vcpu-ubuntu-2404 | |
| outputs: | |
| anchor: ${{ steps.release.outputs.anchor }} | |
| matrix: ${{ steps.release.outputs.matrix }} | |
| reason: ${{ steps.release.outputs.reason }} | |
| rss_backfill: ${{ steps.release.outputs.rss_backfill }} | |
| should_run: ${{ steps.release.outputs.should_run }} | |
| steps: | |
| - name: Checkout RTT tracker | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup Node | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| - name: Resolve OpenClaw Discord packages | |
| id: release | |
| env: | |
| INPUT_VERSIONS: ${{ github.event_name == 'workflow_dispatch' && inputs.versions || '' }} | |
| INPUT_RSS_BACKFILL: ${{ github.event_name == 'workflow_dispatch' && inputs.rss_backfill || 'false' }} | |
| INPUT_RSS_BACKFILL_LIMIT: ${{ github.event_name == 'workflow_dispatch' && inputs.rss_backfill_limit || '' }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| node scripts/resolve-openclaw-discord-package.mjs | |
| - name: Report skipped package | |
| if: steps.release.outputs.should_run != 'true' | |
| run: | | |
| echo "No new Discord release versions to measure after ${{ steps.release.outputs.anchor }} (${{ steps.release.outputs.reason }})" | |
| measure: | |
| name: Measure OpenClaw Discord release RTT | |
| needs: resolve | |
| if: needs.resolve.outputs.should_run == 'true' | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 120 | |
| environment: qa-live-shared | |
| concurrency: | |
| group: release-discord-rtt-measure-${{ github.ref }}-${{ matrix.package.version }} | |
| cancel-in-progress: false | |
| strategy: | |
| fail-fast: false | |
| max-parallel: 2 | |
| matrix: | |
| package: ${{ fromJSON(needs.resolve.outputs.matrix) }} | |
| steps: | |
| - name: Checkout RTT tracker | |
| uses: actions/checkout@v7 | |
| with: | |
| path: openclaw-rtt | |
| fetch-depth: 0 | |
| - name: Checkout OpenClaw release | |
| uses: actions/checkout@v7 | |
| with: | |
| repository: openclaw/openclaw | |
| ref: ${{ matrix.package.tag }} | |
| path: openclaw | |
| fetch-depth: 1 | |
| persist-credentials: false | |
| - name: Checkout OpenClaw QA harness | |
| uses: actions/checkout@v7 | |
| with: | |
| repository: openclaw/openclaw | |
| ref: main | |
| path: openclaw-qa | |
| fetch-depth: 1 | |
| persist-credentials: false | |
| - name: Setup Node | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| - name: Setup pnpm | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| corepack enable | |
| corepack prepare "pnpm@${PNPM_VERSION}" --activate | |
| - name: Locate pnpm store | |
| id: pnpm-store | |
| working-directory: openclaw | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| echo "path=$(pnpm store path --silent)" >>"$GITHUB_OUTPUT" | |
| - name: Restore pnpm store | |
| uses: actions/cache@v6 | |
| with: | |
| path: ${{ steps.pnpm-store.outputs.path }} | |
| key: openclaw-release-discord-rtt-pnpm-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('openclaw/pnpm-lock.yaml', 'openclaw-qa/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| openclaw-release-discord-rtt-pnpm-${{ runner.os }}-${{ runner.arch }}- | |
| - name: Install OpenClaw dependencies | |
| working-directory: openclaw | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| time pnpm install --frozen-lockfile --prefer-offline --ignore-scripts=false --config.engine-strict=false --config.enable-pre-post-scripts=true --config.side-effects-cache=true | |
| - name: Install OpenClaw QA harness dependencies | |
| working-directory: openclaw-qa | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| time pnpm install --frozen-lockfile --prefer-offline --ignore-scripts=false --config.engine-strict=false --config.enable-pre-post-scripts=true --config.side-effects-cache=true | |
| - name: Patch release QA compatibility | |
| working-directory: openclaw-rtt | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| node scripts/patch-openclaw-release-qa-harness.mjs ../openclaw-qa | |
| - name: Patch Discord RTT measurement | |
| working-directory: openclaw-rtt | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| node scripts/patch-openclaw-rtt-harness.mjs ../openclaw-qa | |
| - name: Verify OpenClaw release ref | |
| working-directory: openclaw | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| version="$(node -p "require('./package.json').version")" | |
| if [[ "$version" != "${{ matrix.package.version }}" ]]; then | |
| echo "OpenClaw package version mismatch: expected ${{ matrix.package.version }}, got ${version}" >&2 | |
| exit 1 | |
| fi | |
| - name: Build OpenClaw release | |
| working-directory: openclaw | |
| env: | |
| NODE_OPTIONS: --max-old-space-size=8192 | |
| OPENCLAW_BUILD_PRIVATE_QA: "1" | |
| OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1" | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| time pnpm build | |
| - name: Build OpenClaw QA harness | |
| working-directory: openclaw-qa | |
| env: | |
| NODE_OPTIONS: --max-old-space-size=8192 | |
| OPENCLAW_BUILD_PRIVATE_QA: "1" | |
| OPENCLAW_ENABLE_PRIVATE_QA_CLI: "1" | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| time pnpm build | |
| - name: Run Discord RTT samples | |
| id: discord_rtt | |
| working-directory: openclaw | |
| 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: "180000" | |
| OPENCLAW_QA_CREDENTIAL_HTTP_TIMEOUT_MS: "60000" | |
| OPENCLAW_QA_REDACT_PUBLIC_METADATA: "1" | |
| OPENCLAW_QA_RELEASE_AUTH_RUNTIME_PATH: ${{ github.workspace }}/openclaw/dist/plugin-sdk/agent-runtime.js | |
| OPENCLAW_QA_RELEASE_PACKAGE_SPEC: ${{ matrix.package.spec }} | |
| INPUT_SAMPLES: ${{ github.event_name == 'workflow_dispatch' && inputs.samples || '20' }} | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| samples="${INPUT_SAMPLES:-20}" | |
| if ! [[ "$samples" =~ ^[1-9][0-9]*$ ]]; then | |
| echo "samples must be a positive integer, got: $samples" >&2 | |
| exit 1 | |
| fi | |
| workspace_root="${GITHUB_WORKSPACE:?}" | |
| output_root=".artifacts/qa-e2e/discord-release-rtt-${{ matrix.package.version }}-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" | |
| sample_paths="$RUNNER_TEMP/openclaw-discord-release-rtt-samples.tsv" | |
| : >"$sample_paths" | |
| echo "output_root=${output_root}" >>"$GITHUB_OUTPUT" | |
| echo "sample_paths=${sample_paths}" >>"$GITHUB_OUTPUT" | |
| for sample in $(seq 1 "$samples"); do | |
| output_dir="${output_root}/sample-${sample}" | |
| summary_path="${output_dir}/qa-evidence.json" | |
| observed_path="${output_dir}/discord-qa-observed-messages.json" | |
| metrics_path="${output_dir}/resource-metrics.env" | |
| status=1 | |
| for attempt in 1 2 3; do | |
| rm -rf "$output_dir" | |
| mkdir -p "$output_dir" | |
| # The release checkout can reactivate its shipped pnpm. Switch | |
| # back before invoking the current OpenClaw QA harness. | |
| corepack prepare "pnpm@${PNPM_VERSION}" --activate | |
| set +e | |
| ( | |
| cd "${workspace_root}/openclaw-qa" | |
| /usr/bin/time \ | |
| -f 'max_rss_kb=%M\nelapsed_seconds=%e' \ | |
| -o "${workspace_root}/openclaw/${metrics_path}" \ | |
| pnpm openclaw qa discord \ | |
| --repo-root "${workspace_root}/openclaw" \ | |
| --output-dir "${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 \ | |
| --scenario discord-canary | |
| ) | |
| status="$?" | |
| set -e | |
| { | |
| echo "sample=${sample}" | |
| echo "attempts=${attempt}" | |
| echo "exit_status=${status}" | |
| } >>"$metrics_path" | |
| if [[ -f "$summary_path" ]]; then | |
| break | |
| fi | |
| if [[ "$attempt" -lt 3 ]]; then | |
| sleep $((attempt * 15)) | |
| fi | |
| done | |
| if [[ ! -f "$summary_path" ]]; then | |
| echo "No Discord QA evidence produced for sample ${sample}." >&2 | |
| if [[ "$status" -eq 0 ]]; then | |
| status=1 | |
| fi | |
| exit "$status" | |
| fi | |
| observed_value="" | |
| if [[ -f "$observed_path" ]]; then | |
| observed_value="${PWD}/${observed_path}" | |
| fi | |
| printf '%s\t%s\t%s\n' "${PWD}/${summary_path}" "$observed_value" "${PWD}/${metrics_path}" >>"$sample_paths" | |
| done | |
| - name: Prepare Discord release import artifact | |
| working-directory: openclaw | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| import_dir="$RUNNER_TEMP/release-discord-rtt-import-${{ matrix.package.version }}" | |
| rm -rf "$import_dir" | |
| mkdir -p "$import_dir" | |
| cp -R "${{ steps.discord_rtt.outputs.output_root }}" "$import_dir/artifacts" | |
| { | |
| echo "spec=${{ matrix.package.spec }}" | |
| echo "version=${{ matrix.package.version }}" | |
| } >"$import_dir/metadata.env" | |
| - name: Upload Discord release import artifact | |
| uses: actions/upload-artifact@v7.0.1 | |
| with: | |
| name: release-discord-rtt-import-${{ matrix.package.version }} | |
| path: ${{ runner.temp }}/release-discord-rtt-import-${{ matrix.package.version }} | |
| retention-days: 14 | |
| if-no-files-found: error | |
| - name: Upload Discord RTT artifacts | |
| if: always() | |
| uses: actions/upload-artifact@v7.0.1 | |
| with: | |
| name: release-discord-rtt-${{ matrix.package.version }}-${{ github.run_id }}-${{ github.run_attempt }} | |
| path: openclaw/.artifacts/qa-e2e/discord-release-rtt-${{ matrix.package.version }}-${{ github.run_id }}-${{ github.run_attempt }} | |
| retention-days: 14 | |
| if-no-files-found: warn | |
| report: | |
| name: Import Discord release RTT reports | |
| needs: | |
| - resolve | |
| - measure | |
| if: always() && needs.resolve.outputs.should_run == 'true' && needs.measure.result != 'cancelled' | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 10 | |
| concurrency: | |
| group: rtt-report-writer-${{ github.ref }} | |
| cancel-in-progress: false | |
| steps: | |
| - name: Checkout RTT tracker | |
| uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup Node | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| - name: Download Discord release import artifacts | |
| uses: actions/download-artifact@v8.0.1 | |
| with: | |
| pattern: release-discord-rtt-import-* | |
| path: ${{ runner.temp }}/release-discord-rtt-imports | |
| - name: Import Discord release RTT results | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| git pull --rebase origin "${GITHUB_REF_NAME:-main}" | |
| import_root="$RUNNER_TEMP/release-discord-rtt-imports" | |
| shopt -s nullglob | |
| import_dirs=("$import_root"/release-discord-rtt-import-*) | |
| if [[ -f "$import_root/metadata.env" ]]; then | |
| import_dirs=("$import_root") | |
| fi | |
| if [[ "${#import_dirs[@]}" -eq 0 ]]; then | |
| echo "No Discord release RTT import artifacts downloaded." >&2 | |
| exit 1 | |
| fi | |
| get_metadata() { | |
| local metadata_path="$1" | |
| local key="$2" | |
| grep -m 1 "^${key}=" "$metadata_path" | cut -d= -f2- | |
| } | |
| for import_dir in "${import_dirs[@]}"; do | |
| metadata_path="${import_dir}/metadata.env" | |
| spec="$(get_metadata "$metadata_path" spec)" | |
| version="$(get_metadata "$metadata_path" version)" | |
| sample_paths="$RUNNER_TEMP/openclaw-discord-release-${version}-rtt-samples.tsv" | |
| : >"$sample_paths" | |
| while IFS= read -r sample_dir; do | |
| summary_path="${sample_dir}/qa-evidence.json" | |
| observed_path="${sample_dir}/discord-qa-observed-messages.json" | |
| metrics_path="${sample_dir}/resource-metrics.env" | |
| if [[ ! -f "$summary_path" || ! -f "$metrics_path" ]]; then | |
| echo "Missing Discord release artifacts under ${sample_dir}." >&2 | |
| exit 1 | |
| fi | |
| observed_value="" | |
| if [[ -f "$observed_path" ]]; then | |
| observed_value="$observed_path" | |
| fi | |
| printf '%s\t%s\t%s\n' "$summary_path" "$observed_value" "$metrics_path" >>"$sample_paths" | |
| done < <(find "${import_dir}/artifacts" -mindepth 1 -maxdepth 1 -type d -name 'sample-*' | sort -V) | |
| if [[ "${{ needs.resolve.outputs.rss_backfill }}" == "true" ]]; then | |
| node scripts/backfill-release-rss.mjs \ | |
| --family discord \ | |
| --spec "$spec" \ | |
| --version "$version" \ | |
| --sample-paths "$sample_paths" | |
| else | |
| node scripts/import-discord-rtt.mjs "$sample_paths" \ | |
| --spec "$spec" \ | |
| --version "$version" \ | |
| --provider-mode mock-openai | |
| fi | |
| done | |
| node scripts/validate.mjs | |
| node scripts/discord-rtt-summary.mjs | |
| - name: Commit result | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| git add data/channels/discord/ runs/discord/ | |
| if git diff --cached --quiet --exit-code; then | |
| echo "No Discord release RTT changes to commit." | |
| exit 0 | |
| fi | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git commit -m "data: record discord release rtt" | |
| git push || { | |
| git pull --rebase origin "${GITHUB_REF_NAME:-main}" | |
| git push | |
| } |