Files
wehub-resource-sync 426e9eeabd
Benchmark Bridge Tests / benchmark (bunx @biomejs/biome check packages/lifeops-bench/src, benchmark-lint) (push) Waiting to run
Benchmark Bridge Tests / benchmark (bunx vitest run --config packages/lifeops-bench/vitest.config.ts --root packages/lifeops-bench --passWithNoTests, benchmark-tests) (push) Waiting to run
Build Agent Image / build-and-push (push) Waiting to run
Chat shell gestures / Chat shell gesture + parity e2e (push) Waiting to run
ci / test (push) Waiting to run
ci / lint-and-format (push) Waiting to run
ci / build (push) Waiting to run
ci / dev-startup (push) Waiting to run
Cloud Gateway Discord / Test (push) Waiting to run
Cloud Gateway Webhook / Test (push) Waiting to run
Cloud Tests / lint-and-types (push) Waiting to run
Cloud Tests / unit-tests (push) Waiting to run
Cloud Tests / integration-tests (push) Waiting to run
Cloud Tests / e2e-tests (push) Blocked by required conditions
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
Deploy Apps Worker (Product 2) / Determine environment (push) Waiting to run
Deploy Apps Worker (Product 2) / Deploy apps worker to apps-control host (${{ needs.determine-env.outputs.environment }}) (push) Blocked by required conditions
Deploy Eliza Provisioning Worker / Determine environment (push) Waiting to run
Deploy Eliza Provisioning Worker / Deploy worker to Hetzner host (${{ needs.determine-env.outputs.environment }} @ ${{ needs.determine-env.outputs.deployment_sha }}) (push) Blocked by required conditions
Dev Smoke / Classify changed paths (push) Waiting to run
Dev Smoke / bun run dev onboarding chat (push) Blocked by required conditions
Dev Smoke / Vite HMR dependency-level smoke (push) Blocked by required conditions
Electrobun Submodule Guard / electrobun gitlink is fetchable (push) Waiting to run
gitleaks / gitleaks (push) Waiting to run
Markdown Links / Relative Markdown Links (push) Waiting to run
Publish @elizaos/example-code / check_npm (push) Waiting to run
Publish @elizaos/example-code / publish_npm (push) Blocked by required conditions
Publish @elizaos/plugin-elizacloud / verify_version (push) Waiting to run
Publish @elizaos/plugin-elizacloud / publish_npm (push) Blocked by required conditions
Quality (Extended) / Homepage Build (PR smoke) (push) Waiting to run
Quality (Extended) / Comment-only diff guard (push) Waiting to run
Quality (Extended) / Format + Type Safety Ratchet (push) Waiting to run
Quality (Extended) / Develop Gate (secret scan + UI determinism) (push) Waiting to run
Quality (Extended) / Develop Gate (lint) (push) Waiting to run
Sandbox Live Smoke / Sandbox live smoke (push) Waiting to run
Snap Build & Test / Build Snap (amd64) (push) Waiting to run
Snap Build & Test / Build Snap (arm64) (push) Waiting to run
supply-chain / sbom (push) Waiting to run
supply-chain / vulnerability-scan (push) Waiting to run
Build, Push & Deploy to Phala Cloud / build-and-push (push) Waiting to run
Test Packaging / Validate Packaging Configs (push) Waiting to run
Test Packaging / PyPI on Python ${{ matrix.python }} (push) Waiting to run
Test Packaging / Pack & Test JS Tarballs (push) Waiting to run
Test Packaging / elizaos CLI global-install smoke (node + bun) (push) Waiting to run
UI Fixture E2E / ui-fixture-e2e (push) Waiting to run
UI Fixture E2E / fixture-e2e (push) Waiting to run
UI Story Gate / story-gate (push) Waiting to run
vault-ci / test (macos-latest) (push) Waiting to run
vault-ci / test (ubuntu-latest) (push) Waiting to run
vault-ci / test (windows-latest) (push) Waiting to run
vault-ci / app-core wiring tests (push) Waiting to run
verify-patches / verify patches/CHECKSUMS.sha256 (push) Waiting to run
Voice Benchmark Smoke / voice-emotion fixture smoke (push) Waiting to run
Voice Benchmark Smoke / voiceagentbench fixture smoke (push) Waiting to run
Voice Benchmark Smoke / voicebench-quality unit smoke (push) Waiting to run
Voice Benchmark Smoke / voicebench TypeScript unit (no audio) (push) Waiting to run
Voice Benchmark Smoke / voice bench smoke summary (push) Blocked by required conditions
Windows CI / windows ([bun run --cwd packages/app-core test bun run --cwd packages/elizaos test bun run --cwd packages/cloud/shared test], app-and-cli) (push) Waiting to run
Windows CI / windows ([bun run --cwd packages/scenario-runner test bun run --cwd packages/vault test bun run --cwd packages/security test bun run --cwd plugins/plugin-coding-tools test], framework-packages) (push) Waiting to run
Windows CI / windows ([bun run --cwd plugins/plugin-elizacloud test bun run --cwd plugins/plugin-discord test bun run --cwd plugins/plugin-anthropic test bun run --cwd plugins/plugin-openai test bun run --cwd plugins/plugin-app-control test bun run --cwd plugins/pl… (push) Waiting to run
Windows CI / windows ([node packages/scripts/run-turbo.mjs run build --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/agent --concurrency=4 node packages/scripts/run-bash-linux-only.mjs scripts/verify-riscv64-buildpaths.sh node packages/scripts/run… (push) Waiting to run
Windows CI / windows ([node packages/scripts/run-turbo.mjs run typecheck --filter=@elizaos/core --filter=@elizaos/shared --filter=@elizaos/cloud-shared --concurrency=4 bun run --cwd packages/core test bun run --cwd packages/shared test], core-runtime, 75) (push) Waiting to run
Test Packaging / Build & Test PyPI Package (push) Waiting to run
Voice Workbench / headless workbench (mocked backends) (push) Has been cancelled
Voice Workbench / real acoustic lane (nightly, provisioned only) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:43:05 +08:00

926 lines
42 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: Scenario PR E2E
# Secret-free opt-in scenario runner smoke. The required zero-key PR gate
# lives in test.yml; this workflow owns the additional scenario-heavy and
# browser matrix coverage that is not already run by the required gate.
on:
# Reusable entry for the scheduled exhaustive develop lane (#12342).
workflow_call:
# Heavy family moved off per-PR push (#14051 Tier A): PR runs are opt-in via
# the `ci:full` label (job-level gate on `changes` below). Unlabeled PRs
# skip every job instantly and consume zero runners.
pull_request:
branches: [main]
types: [opened, synchronize, reopened, ready_for_review, labeled]
push:
branches: [develop]
schedule:
# Nightly heavy lane (#14051): 07:00 UTC.
- cron: "0 7 * * *"
workflow_dispatch:
concurrency:
group: scenario-pr-e2e-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
CI: "true"
BUN_VERSION: "canary"
NODE_VERSION: "24.15.0"
NODE_OPTIONS: "--max-old-space-size=4096"
TEST_LANE: "pr"
ELIZA_LIVE_TEST: "0"
SCENARIO_USE_LLM_PROXY: "1"
CEREBRAS_API_KEY: ""
OPENAI_API_KEY: ""
ANTHROPIC_API_KEY: ""
GROQ_API_KEY: ""
OPENROUTER_API_KEY: ""
GOOGLE_GENERATIVE_AI_API_KEY: ""
XAI_API_KEY: ""
NVIDIA_API_KEY: ""
ELIZAOS_CLOUD_API_KEY: ""
permissions:
contents: read
jobs:
changes:
name: Classify changed paths
# #14051: PRs only run this heavy family when explicitly opted in with the
# `ci:full` label. Every downstream job needs this one, so an unlabeled PR
# skips the whole workflow without touching a runner.
if: github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'ci:full')
# Path classifier is a git-diff + node script: no self-hosted resources.
# Keep it on GitHub-hosted so a drained hetzner fleet cannot leave it
# queued indefinitely and pile up runs (#13617/#8501).
runs-on: ${{ fromJSON(vars.HETZNER_FLEET_ONLINE == 'false' && '["ubuntu-24.04"]' || '["self-hosted","hetzner-robot"]') }}
timeout-minutes: 10
outputs:
run_scenario_pr: ${{ steps.filter.outputs.run_scenario_pr }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
fetch-depth: 0
submodules: false
- name: Setup Node.js for path gate
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
with:
node-version: ${{ env.NODE_VERSION }}
- name: Determine affected CI surface
id: filter
shell: bash
env:
PR_LABELS: ${{ github.event_name == 'pull_request' && join(github.event.pull_request.labels.*.name, ',') || '' }}
run: |
set -euo pipefail
node packages/scripts/ci-path-gate.mjs \
--config scenario-pr \
--event "${{ github.event_name }}" \
--base "${{ github.event.pull_request.base.sha }}" \
--head "${{ github.event.pull_request.head.sha }}" \
--labels "$PR_LABELS" \
--output "$GITHUB_OUTPUT" \
--summary "$GITHUB_STEP_SUMMARY"
scenario-unit-coverage:
name: Zero-Key unit + UI coverage
needs: changes
if: needs.changes.outputs.run_scenario_pr == 'true'
runs-on: ${{ fromJSON(vars.HETZNER_FLEET_ONLINE == 'false' && '["ubuntu-24.04"]' || '["self-hosted","hetzner-robot"]') }}
timeout-minutes: 30
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
submodules: false
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup workspace dependencies
uses: ./.github/actions/setup-bun-workspace
with:
bun-version: ${{ env.BUN_VERSION }}
install-command: bun install --ignore-scripts --no-frozen-lockfile
install-native-deps: "false"
skip-avatar-clone: "true"
no-vision-deps: "true"
- name: Ensure generated shared i18n data
run: node packages/app-core/scripts/ensure-shared-i18n-data.mjs
- name: Scenario runner unit coverage
run: bun run --cwd packages/scenario-runner test -- src/executor.test.ts src/runtime-factory.test.ts src/scenario-pr-workflow.test.ts src/__tests__/deterministic-action-coverage.test.ts
- name: Real local agent provisioning (no model, no secret)
run: bun run --cwd packages/app-core test:local-provisioning
# Real local chat through the full pipeline — real runtime + real
# conversation routes + real message handling + real history, with a
# deterministic in-process model (no provider key, no llama). Unlike the
# ui-smoke api-stub (which fakes the whole endpoint), this exercises the
# real chat machinery, so it gates every PR with genuinely-real local chat.
- name: Real local chat pipeline (no model key, no llama)
run: bun run --cwd packages/app-core test:local-chat
app-browser-core:
name: Zero-Key app browser core
needs: changes
if: needs.changes.outputs.run_scenario_pr == 'true'
runs-on: ${{ fromJSON(vars.HETZNER_FLEET_ONLINE == 'false' && '["ubuntu-24.04"]' || '["self-hosted","hetzner-robot"]') }}
timeout-minutes: 25
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
submodules: false
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup workspace dependencies
uses: ./.github/actions/setup-bun-workspace
with:
bun-version: ${{ env.BUN_VERSION }}
install-command: bun install --ignore-scripts --no-frozen-lockfile
install-native-deps: "false"
skip-avatar-clone: "true"
no-vision-deps: "true"
- name: Ensure generated shared i18n data
run: node packages/app-core/scripts/ensure-shared-i18n-data.mjs
- name: Install Playwright browsers
run: bunx playwright install --with-deps chromium
- name: Actual app onboarding-to-home browser coverage
run: bun run --cwd packages/app test:e2e test/ui-smoke/onboarding-to-home.spec.ts --project=chromium
- name: Mobile-viewport onboarding-to-home browser coverage
run: bun run --cwd packages/app test:e2e test/ui-smoke/onboarding-to-home-mobile.spec.ts --project=chromium
- name: Actual app voice self-test browser coverage
run: bun run --cwd packages/app test:e2e test/ui-smoke/voice-selftest-e2e.spec.ts test/ui-smoke/voice-desktop-selftest.spec.ts --project=chromium
- name: Actual app voice workbench browser coverage
# Spec names track the #11442 browser-honest rescope renames
# (diarization->attribution-unavailable, eot->fragmented-turn-wiring, …).
run: bun run --cwd packages/app test:e2e test/ui-smoke/voice-workbench-agent-room-metadata.spec.ts test/ui-smoke/voice-workbench-attribution-unavailable.spec.ts test/ui-smoke/voice-workbench-fragmented-turn-wiring.spec.ts test/ui-smoke/voice-workbench-participant-sequence.spec.ts test/ui-smoke/voice-workbench-participant-voice-metadata.spec.ts test/ui-smoke/voice-workbench-response-state-sse.spec.ts test/ui-smoke/voice-workbench-speaker-label-metadata.spec.ts test/ui-smoke/voice-workbench-transcript-propagation.spec.ts test/ui-smoke/voice-workbench-turn-detail-metadata.spec.ts test/ui-smoke/voice-workbench-turn-pauses.spec.ts --project=chromium
- name: Actual app real-audio voice button browser coverage
run: bun run --cwd packages/app test:e2e test/ui-smoke/voice-realaudio.spec.ts test/ui-smoke/transcript-realaudio.spec.ts --project=chromium-voice-mic
- name: Upload app browser core artifacts
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: scenario-pr-app-browser-core
path: |
packages/app/playwright-report/
packages/app/test-results/
if-no-files-found: ignore
retention-days: 3
# Keep the full browser quality gate, but split app slices into their own jobs
# so developers get useful PR feedback without waiting on one serial browser queue.
app-browser-view-lifecycle:
name: Zero-Key app browser view lifecycle
needs: changes
if: needs.changes.outputs.run_scenario_pr == 'true'
runs-on: ${{ fromJSON(vars.HETZNER_FLEET_ONLINE == 'false' && '["ubuntu-24.04"]' || '["self-hosted","hetzner-robot"]') }}
timeout-minutes: 30
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
submodules: false
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup workspace dependencies
uses: ./.github/actions/setup-bun-workspace
with:
bun-version: ${{ env.BUN_VERSION }}
install-command: bun install --ignore-scripts --no-frozen-lockfile
install-native-deps: "false"
skip-avatar-clone: "true"
no-vision-deps: "true"
- name: Ensure generated shared i18n data
run: node packages/app-core/scripts/ensure-shared-i18n-data.mjs
- name: Install Playwright browsers
run: bunx playwright install --with-deps chromium
- name: Actual app plugin view browser coverage
run: bun run --cwd packages/app test:e2e test/ui-smoke/plugin-views-visual.spec.ts test/ui-smoke/plugin-views-interaction.spec.ts --project=chromium
- name: Actual app plugin view lifecycle browser coverage
run: bun run --cwd packages/app test:e2e test/ui-smoke/plugin-views-lifecycle.spec.ts --project=chromium
- name: Actual app agent-driven view switching browser coverage
run: bun run --cwd packages/app test:e2e test/ui-smoke/view-switching-chat-e2e.spec.ts --project=chromium
- name: Actual app agent bridge inventory browser coverage
run: bun run --cwd packages/app test:e2e test/ui-smoke/browser-skills-agent-bridge.spec.ts test/ui-smoke/plugin-view-agent-bridge-inventory.spec.ts test/ui-smoke/shell-view-agent-bridge-inventory.spec.ts --project=chromium
- name: Actual app core navigation matrix browser coverage
run: bun run --cwd packages/app test:e2e test/ui-smoke/view-switching-core-matrix.spec.ts --project=chromium
- name: Actual app generated-audio + file-share browser coverage
run: bun run --cwd packages/app test:e2e test/ui-smoke/chat-generated-audio.spec.ts test/ui-smoke/files-view-share-journey.spec.ts --project=chromium
- name: Upload app browser view lifecycle artifacts
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: scenario-pr-app-browser-view-lifecycle
path: |
packages/app/playwright-report/
packages/app/test-results/
if-no-files-found: ignore
retention-days: 3
app-browser-all-pages:
name: Zero-Key app browser all-pages
needs: changes
if: needs.changes.outputs.run_scenario_pr == 'true'
runs-on: ${{ fromJSON(vars.HETZNER_FLEET_ONLINE == 'false' && '["ubuntu-24.04"]' || '["self-hosted","hetzner-robot"]') }}
timeout-minutes: 35
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
submodules: false
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup workspace dependencies
uses: ./.github/actions/setup-bun-workspace
with:
bun-version: ${{ env.BUN_VERSION }}
install-command: bun install --ignore-scripts --no-frozen-lockfile
install-native-deps: "false"
skip-avatar-clone: "true"
no-vision-deps: "true"
- name: Ensure generated shared i18n data
run: node packages/app-core/scripts/ensure-shared-i18n-data.mjs
- name: Install Playwright browsers
run: bunx playwright install --with-deps chromium
- name: Actual app all-pages render + click-safety browser coverage
run: bun run --cwd packages/app test:e2e test/ui-smoke/all-pages-clicksafe.spec.ts test/ui-smoke/builtin-views-visual.spec.ts test/ui-smoke/documents-view.spec.ts --project=chromium
- name: Upload app browser all-pages artifacts
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: scenario-pr-app-browser-all-pages
path: |
packages/app/playwright-report/
packages/app/test-results/
if-no-files-found: ignore
retention-days: 3
app-browser-feature-interactions:
name: Zero-Key app browser feature interactions
needs: changes
if: needs.changes.outputs.run_scenario_pr == 'true'
runs-on: ${{ fromJSON(vars.HETZNER_FLEET_ONLINE == 'false' && '["ubuntu-24.04"]' || '["self-hosted","hetzner-robot"]') }}
timeout-minutes: 55
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
submodules: false
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup workspace dependencies
uses: ./.github/actions/setup-bun-workspace
with:
bun-version: ${{ env.BUN_VERSION }}
install-command: bun install --ignore-scripts --no-frozen-lockfile
install-native-deps: "false"
skip-avatar-clone: "true"
no-vision-deps: "true"
- name: Ensure generated shared i18n data
run: node packages/app-core/scripts/ensure-shared-i18n-data.mjs
- name: Install Playwright browsers
run: bunx playwright install --with-deps chromium
- name: Actual app feature interaction browser coverage
run: bun run --cwd packages/app test:e2e test/ui-smoke/apps-utility-interactions.spec.ts test/ui-smoke/apps-model-training-interactions.spec.ts test/ui-smoke/apps-comms-device-interactions.spec.ts test/ui-smoke/apps-diagnostics-interactions.spec.ts test/ui-smoke/apps-builtin-pages-interactions.spec.ts test/ui-smoke/settings-sections-interactions.spec.ts test/ui-smoke/settings-mobile-load.spec.ts test/ui-smoke/apps-personal-assistant-decomposed-interactions.spec.ts test/ui-smoke/apps-personal-assistant-feed-interactions.spec.ts test/ui-smoke/vault-modal-interactions.spec.ts test/ui-smoke/desktop-workspace-interactions.spec.ts test/ui-smoke/settings-audit-capture.spec.ts test/ui-smoke/settings-chat-control.spec.ts test/ui-smoke/routing-matrix-dispatch.spec.ts test/ui-smoke/chat-overlay-controls-interactions.spec.ts test/ui-smoke/task-widget-in-chat.spec.ts test/ui-smoke/chat-attachment.spec.ts test/ui-smoke/chat-3d-model.spec.ts test/ui-smoke/chat-large-paste.spec.ts test/ui-smoke/chat-clear-swipe.spec.ts test/ui-smoke/files-view.spec.ts test/ui-smoke/files-view-crud.spec.ts test/ui-smoke/conversation-management.spec.ts test/ui-smoke/chat-cloud-routed.spec.ts test/ui-smoke/slash-commands.spec.ts test/ui-smoke/model-download-deferral.spec.ts test/ui-smoke/home-widget-priority.spec.ts test/ui-smoke/settings-background.spec.ts --project=chromium
- name: Upload app browser feature interaction artifacts
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: scenario-pr-app-browser-feature-interactions
path: |
packages/app/playwright-report/
packages/app/test-results/
if-no-files-found: ignore
retention-days: 3
app-browser-cloud-keyless:
name: Zero-Key app browser cloud keyless
needs: changes
if: needs.changes.outputs.run_scenario_pr == 'true'
runs-on: ${{ fromJSON(vars.HETZNER_FLEET_ONLINE == 'false' && '["ubuntu-24.04"]' || '["self-hosted","hetzner-robot"]') }}
timeout-minutes: 35
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
submodules: false
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup workspace dependencies
uses: ./.github/actions/setup-bun-workspace
with:
bun-version: ${{ env.BUN_VERSION }}
install-command: bun install --ignore-scripts --no-frozen-lockfile
install-native-deps: "false"
skip-avatar-clone: "true"
no-vision-deps: "true"
- name: Ensure generated shared i18n data
run: node packages/app-core/scripts/ensure-shared-i18n-data.mjs
- name: Install Playwright browsers
run: bunx playwright install --with-deps chromium
- name: Actual app cloud keyless browser coverage
run: bun run --cwd packages/app test:e2e test/ui-smoke/cloud-provisioning-startup.spec.ts test/ui-smoke/cloud-agent-lifecycle.spec.ts test/ui-smoke/cloud-wallet-import.spec.ts test/ui-smoke/live-agent-chat.spec.ts test/ui-smoke/remote-capability-view.spec.ts --project=chromium
- name: Upload app browser cloud keyless artifacts
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: scenario-pr-app-browser-cloud-keyless
path: |
packages/app/playwright-report/
packages/app/test-results/
if-no-files-found: ignore
retention-days: 3
app-browser-ratcheted:
name: Zero-Key app browser ratcheted
needs: changes
if: needs.changes.outputs.run_scenario_pr == 'true'
runs-on: ${{ fromJSON(vars.HETZNER_FLEET_ONLINE == 'false' && '["ubuntu-24.04"]' || '["self-hosted","hetzner-robot"]') }}
timeout-minutes: 55
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
submodules: false
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup workspace dependencies
uses: ./.github/actions/setup-bun-workspace
with:
bun-version: ${{ env.BUN_VERSION }}
install-command: bun install --ignore-scripts --no-frozen-lockfile
install-native-deps: "false"
skip-avatar-clone: "true"
no-vision-deps: "true"
- name: Ensure generated shared i18n data
run: node packages/app-core/scripts/ensure-shared-i18n-data.mjs
- name: Install Playwright browsers
run: bunx playwright install --with-deps chromium
- name: Actual app ratcheted keyless browser coverage
run: bun run --cwd packages/app test:e2e test/ui-smoke/ai-qa-capture.spec.ts test/ui-smoke/android-system-apps.spec.ts test/ui-smoke/apps-session.spec.ts test/ui-smoke/apps-session-direct-a.spec.ts test/ui-smoke/apps-session-direct-b.spec.ts test/ui-smoke/auth-startup.spec.ts test/ui-smoke/automations.spec.ts test/ui-smoke/browser-workspace.spec.ts test/ui-smoke/character-editor.spec.ts test/ui-smoke/wallet-inventory.spec.ts test/ui-smoke/workflow-editor.spec.ts test/ui-smoke/computer-use.spec.ts test/ui-smoke/connectors.spec.ts test/ui-smoke/first-run-startup.spec.ts test/ui-smoke/model-download-deferral.spec.ts test/ui-smoke/history-navigation.spec.ts test/ui-smoke/orchestrator-gui-workbench.spec.ts test/ui-smoke/reset-returns-to-onboarding.spec.ts test/ui-smoke/tutorial-chat.spec.ts test/ui-smoke/warming-shell-startup.spec.ts test/ui-smoke/runtime-configurability.spec.ts test/ui-smoke/perf-load-kpi.spec.ts test/ui-smoke/perf-interaction-kpi.spec.ts test/ui-smoke/perf-reduced-motion.spec.ts test/ui-smoke/screenshare-gui-interactions.spec.ts test/ui-smoke/task-coordinator-gui-interactions.spec.ts test/ui-smoke/titlebar-navigation.spec.ts test/ui-smoke/ui-smoke.spec.ts --project=chromium
- name: Upload app browser ratcheted artifacts
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: scenario-pr-app-browser-ratcheted
path: |
packages/app/playwright-report/
packages/app/test-results/
if-no-files-found: ignore
retention-days: 3
# Directory-driven catch-all (issue #9943). The slice jobs above hand-name
# their specs for parallelism; this job runs every OTHER ui-smoke spec — any
# spec not hand-named in a slice and not in the checked-in deny-list
# (packages/app/test/ui-smoke/.pr-deny-list.json). That makes any NEW spec land
# on the PR path by default; the only way to exclude one is to record it in the
# deny-list with a category and a reason. The spec set is emitted by
# packages/app/scripts/ui-smoke-pr-specs.mjs and the wiring is enforced by
# packages/app/test/ui-smoke-coverage.test.ts.
app-browser-auto-discovered:
name: Zero-Key app browser auto-discovered specs
needs: changes
if: needs.changes.outputs.run_scenario_pr == 'true'
runs-on: ${{ fromJSON(vars.HETZNER_FLEET_ONLINE == 'false' && '["ubuntu-24.04"]' || '["self-hosted","hetzner-robot"]') }}
timeout-minutes: 35
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
submodules: false
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup workspace dependencies
uses: ./.github/actions/setup-bun-workspace
with:
bun-version: ${{ env.BUN_VERSION }}
install-command: bun install --ignore-scripts --no-frozen-lockfile
install-native-deps: "false"
skip-avatar-clone: "true"
no-vision-deps: "true"
- name: Ensure generated shared i18n data
run: node packages/app-core/scripts/ensure-shared-i18n-data.mjs
- name: Install Playwright browsers
run: bunx playwright install --with-deps chromium
- name: Actual app auto-discovered ui-smoke browser coverage
run: |
set -euo pipefail
specs="$(node packages/app/scripts/ui-smoke-pr-specs.mjs --list-auto)"
if [ -z "$specs" ]; then
echo "No auto-discovered ui-smoke specs to run (all covered by named slices or denied)."
exit 0
fi
echo "Auto-discovered ui-smoke specs: $specs"
bun run --cwd packages/app test:e2e $specs --project=chromium
- name: Upload app browser auto-discovered artifacts
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: scenario-pr-app-browser-auto-discovered
path: |
packages/app/playwright-report/
packages/app/test-results/
if-no-files-found: ignore
retention-days: 3
# The real-touch device matrix (#10104 Tier-2, descends from #9943/#9950):
# the ui-smoke config has always defined touch-enabled projects — Pixel 7
# `mobile-chromium` (hasTouch, real CDP touch specs) and the `dashboard-*`
# portrait/landscape/iPad viewports — but no workflow ever ran them, so every
# "swipe" gated on PRs executed only as desktop mouse, and the unwatched
# mobile lane rotted (15/16 red when first re-run). Two jobs so each lane
# fails independently and boots its own live stack.
app-browser-touch-dashboard:
name: Zero-Key app browser dashboard device matrix
needs: changes
if: needs.changes.outputs.run_scenario_pr == 'true'
runs-on: ${{ fromJSON(vars.HETZNER_FLEET_ONLINE == 'false' && '["ubuntu-24.04"]' || '["self-hosted","hetzner-robot"]') }}
timeout-minutes: 40
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
submodules: false
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup workspace dependencies
uses: ./.github/actions/setup-bun-workspace
with:
bun-version: ${{ env.BUN_VERSION }}
install-command: bun install --ignore-scripts --no-frozen-lockfile
install-native-deps: "false"
skip-avatar-clone: "true"
no-vision-deps: "true"
- name: Ensure generated shared i18n data
run: node packages/app-core/scripts/ensure-shared-i18n-data.mjs
- name: Install Playwright browsers
run: bunx playwright install --with-deps chromium
# The assertion-grade dashboard specs (browser-workspace, character-editor,
# wallet-inventory, workflow-editor) across mobile-portrait/-landscape,
# iPad portrait (all hasTouch), and 1440×900 desktop.
- name: Dashboard device-matrix browser coverage (portrait/landscape/iPad/desktop)
run: bun run --cwd packages/app test:e2e --project=dashboard-mobile-portrait --project=dashboard-mobile-landscape --project=dashboard-ipad-portrait --project=dashboard-desktop-landscape
- name: Upload dashboard device-matrix artifacts
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: scenario-pr-app-browser-touch-dashboard
path: |
packages/app/playwright-report/
packages/app/test-results/
if-no-files-found: ignore
retention-days: 3
app-browser-touch-mobile:
name: Zero-Key app browser Pixel-7 real-touch lane
needs: changes
if: needs.changes.outputs.run_scenario_pr == 'true'
runs-on: ${{ fromJSON(vars.HETZNER_FLEET_ONLINE == 'false' && '["ubuntu-24.04"]' || '["self-hosted","hetzner-robot"]') }}
timeout-minutes: 45
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
submodules: false
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup workspace dependencies
uses: ./.github/actions/setup-bun-workspace
with:
bun-version: ${{ env.BUN_VERSION }}
install-command: bun install --ignore-scripts --no-frozen-lockfile
install-native-deps: "false"
skip-avatar-clone: "true"
no-vision-deps: "true"
- name: Ensure generated shared i18n data
run: node packages/app-core/scripts/ensure-shared-i18n-data.mjs
- name: Install Playwright browsers
run: bunx playwright install --with-deps chromium
# Pixel 7 (hasTouch, isMobile) lane: the decomposed personal-assistant
# views + the real-CDP-touch chat gesture/fuzz specs at the WebView
# viewport that ships on Capacitor iOS/Android.
- name: Pixel-7 real-touch browser coverage
run: bun run --cwd packages/app test:e2e --project=mobile-chromium
- name: Upload Pixel-7 real-touch artifacts
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: scenario-pr-app-browser-touch-mobile
path: |
packages/app/playwright-report/
packages/app/test-results/
if-no-files-found: ignore
retention-days: 3
# The real-WebKit lane (#10104/#10722): every prior browser job runs Chromium
# only, while the shipped app spends most of its life inside WebKit (every
# Capacitor iOS WebView, macOS WKWebView). WebKit-only differences are real —
# e.g. foreignObject canvas uploads still taint in WebKit but no longer in
# Chromium, and WebKit does not bypass the app service worker under route
# interception the way Chromium does. This job runs the `desktop-webkit` project
# (Desktop Safari profile)
# over the assertion-grade dashboard specs + shell smoke + input-modality
# spec. Note: the install step below uses `--with-deps` because this runner
# is ubuntu; on a macOS runner `--with-deps` must be omitted (no apt).
app-browser-webkit:
name: Zero-Key app browser WebKit lane
needs: changes
if: needs.changes.outputs.run_scenario_pr == 'true'
runs-on: ${{ fromJSON(vars.HETZNER_FLEET_ONLINE == 'false' && '["ubuntu-24.04"]' || '["self-hosted","hetzner-robot"]') }}
timeout-minutes: 40
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
submodules: false
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup workspace dependencies
uses: ./.github/actions/setup-bun-workspace
with:
bun-version: ${{ env.BUN_VERSION }}
install-command: bun install --ignore-scripts --no-frozen-lockfile
install-native-deps: "false"
skip-avatar-clone: "true"
no-vision-deps: "true"
- name: Ensure generated shared i18n data
run: node packages/app-core/scripts/ensure-shared-i18n-data.mjs
- name: Install Playwright browsers (WebKit)
run: bunx playwright install --with-deps webkit
- name: Real-WebKit dashboard + shell + input-modality browser coverage
run: bun run --cwd packages/app test:e2e --project=desktop-webkit
- name: Upload WebKit lane artifacts
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: scenario-pr-app-browser-webkit
path: |
packages/app/playwright-report/
packages/app/test-results/
if-no-files-found: ignore
retention-days: 3
app-accounts-ui:
name: Zero-Key accounts UI e2e (real API + pool + disk)
needs: changes
if: needs.changes.outputs.run_scenario_pr == 'true'
runs-on: ${{ fromJSON(vars.HETZNER_FLEET_ONLINE == 'false' && '["ubuntu-24.04"]' || '["self-hosted","hetzner-robot"]') }}
timeout-minutes: 30
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
submodules: false
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup workspace dependencies
uses: ./.github/actions/setup-bun-workspace
with:
bun-version: ${{ env.BUN_VERSION }}
install-command: bun install --ignore-scripts --no-frozen-lockfile
install-native-deps: "false"
skip-avatar-clone: "true"
no-vision-deps: "true"
- name: Ensure generated shared i18n data
run: node packages/app-core/scripts/ensure-shared-i18n-data.mjs
- name: Install Playwright browsers (Chromium)
run: bunx playwright install --with-deps chromium
- name: Accounts UI browser e2e — real AccountList + real accounts routes + real AccountPool
run: bun run --cwd packages/app test:e2e:accounts-ui
- name: Upload accounts-ui evidence artifacts
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: scenario-pr-app-accounts-ui
path: ${{ runner.temp }}/evidence/10722-accounts-ui-e2e/
if-no-files-found: ignore
retention-days: 3
app-walkthrough-mock:
name: Zero-Key full-walkthrough (mock lane)
needs: changes
if: needs.changes.outputs.run_scenario_pr == 'true'
runs-on: ${{ fromJSON(vars.HETZNER_FLEET_ONLINE == 'false' && '["ubuntu-24.04"]' || '["self-hosted","hetzner-robot"]') }}
timeout-minutes: 45
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
submodules: false
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup workspace dependencies
uses: ./.github/actions/setup-bun-workspace
with:
bun-version: ${{ env.BUN_VERSION }}
install-command: bun install --ignore-scripts --no-frozen-lockfile
install-native-deps: "false"
skip-avatar-clone: "true"
no-vision-deps: "true"
- name: Ensure generated shared i18n data
run: node packages/app-core/scripts/ensure-shared-i18n-data.mjs
- name: Install Playwright browsers
run: bunx playwright install --with-deps chromium
- name: Install ffmpeg (recording stitch)
run: sudo apt-get update && sudo apt-get install -y ffmpeg
# Drives the REAL in-chat onboarding (greeting → runtime CHOICE →
# provider → one POST /api/first-run) and all 8 tutorial frames, then
# stitches the ordered NN-*.png frames into one step-labeled mp4 per
# viewport. Keyless: the lane forces ELIZA_UI_SMOKE_FORCE_STUB=1; the PR
# env blanks every provider key, so `--skip-review` (no vision verdicts).
- name: Drive + record the in-chat onboarding + tutorial walkthrough
run: bun run --cwd packages/app test:e2e:walkthrough -- --skip-review
- name: Upload walkthrough screenshots + stitched recording + verdicts
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: scenario-pr-app-walkthrough-mock
path: |
reports/walkthrough/
e2e-recordings/app/walkthrough/
packages/app/test/ui-smoke/walkthrough/WALKTHROUGH_VERDICTS.md
if-no-files-found: ignore
retention-days: 7
app-diagnostics:
name: Zero-Key app diagnostics
needs: changes
if: needs.changes.outputs.run_scenario_pr == 'true'
runs-on: ${{ fromJSON(vars.HETZNER_FLEET_ONLINE == 'false' && '["ubuntu-24.04"]' || '["self-hosted","hetzner-robot"]') }}
timeout-minutes: 10
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
submodules: false
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
with:
node-version: ${{ env.NODE_VERSION }}
# The required test.yml gate owns the app-diagnostics suite commands. Keep
# this status name alive as a real delegation check so rulesets and the
# scenario aggregate do not point at a deleted job, without running the
# same diagnostics suites twice on PRs (#13402).
- name: Validate zero-key command ownership delegation
run: node packages/scripts/ci-zero-key-command-ownership-contract.mjs
scenario-runner-e2e:
name: Zero-Key scenario runner E2E
needs: changes
if: needs.changes.outputs.run_scenario_pr == 'true'
runs-on: ${{ fromJSON(vars.HETZNER_FLEET_ONLINE == 'false' && '["ubuntu-24.04"]' || '["self-hosted","hetzner-robot"]') }}
timeout-minutes: 35
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
with:
submodules: false
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
with:
node-version: ${{ env.NODE_VERSION }}
- name: Setup workspace dependencies
uses: ./.github/actions/setup-bun-workspace
with:
bun-version: ${{ env.BUN_VERSION }}
install-command: bun install --ignore-scripts --no-frozen-lockfile
install-native-deps: "false"
skip-avatar-clone: "true"
no-vision-deps: "true"
- name: Ensure generated shared i18n data
run: node packages/app-core/scripts/ensure-shared-i18n-data.mjs
# packages/scripts has no package.json, so packages/scripts/__tests__ is
# outside workspace test discovery (run-all-tests.mjs never sees it). This
# job used to enumerate individual files here, which left every unlisted
# suite dead on arrival — most of the directory never ran anywhere
# (#15846). Sweep the whole directory so a new test file there always has
# a lane. The sweep still owns every guard the per-file steps named:
# test-task-pool, the vacuous-green runner guard (#13620/#12342), the
# agent-image workflow + build:core drift contracts and the plugin-build
# driver self-test (#10200), the scripts-inventory smoke, the real/live
# guarded-suite manifest gate (#9310 §E), the UI fixture-runner
# CI-coverage ratchet (#9310 §3.16), and the ENFORCED e2e-coverage
# ship-gate (#8802 — baseline green; route-manifest lockstep, zero-test
# plugins, and no-blocking-gaps ratchets fail the build on regression).
# `--conditions=eliza-source`: several suites (e2e-coverage among them)
# scan workspace SOURCE that reaches @elizaos/core, which under bun's
# default `bun` export condition resolves to unbuilt dist on this
# --ignore-scripts install. The source condition resolves those workspace
# packages to src (same as the matrix-report step below), so the sweep
# runs before build:core (#15759).
- name: packages/scripts test sweep (all __tests__ suites)
env:
E2E_COVERAGE_GATE_ENFORCE: "1"
run: bun test --conditions=eliza-source packages/scripts/__tests__/
# Per-plugin keyless-e2e coverage gate (issue #8801). The surface matrix
# above proves app-facing routes/views; this ratchet proves each plugin
# with user-facing capabilities has a deterministic, credential-free
# scenario or an explicit baseline entry.
# Source condition for the same reason as the ship-gate step: this test
# imports inventory.ts, which resolves plugin source → @elizaos/core (#15759).
- name: Per-plugin keyless e2e coverage self-test
run: bun test --conditions=eliza-source packages/scripts/e2e-coverage/check-e2e-coverage.test.ts
# #15616: pass/fail classifier for the live cloud chat smokes
# (hetzner-e2e-chat, live-cloud-provision-smoke). packages/scripts is
# outside workspace test discovery, so keep this explicit or canned
# failure replies can silently start passing the nightly again.
- name: Bridge chat-reply verdict classifier
run: bun test packages/scripts/cloud/admin/bridge-reply-verdict.test.ts
- name: Per-plugin keyless e2e coverage gate
run: bun run audit:e2e-coverage
# #14549: parallel-certification compose generator drift gate + GPU queue
# state machine + orchestrator degradation. docker/certification is
# outside workspace test discovery, so keep this explicit or the
# committed compose.yml can silently drift from the test-runner's plan.
- name: Parallel-certification compose + queue tests
run: bun test docker/certification
- name: E2E coverage matrix report
if: always()
run: bun --conditions=eliza-source packages/scripts/e2e-coverage/write-coverage-matrix-report.ts --report-dir reports/coverage
- name: Build workspace packages for scenario resolution
run: bun run build:core && bunx turbo run build --filter=@elizaos/plugin-github
- name: Upload scenario report
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: scenario-pr-deterministic-report
path: |
reports/scenarios/pr-deterministic/
reports/scenarios/pr-deterministic-corpus/
reports/scenarios/pr-deterministic-orchestrator/
reports/scenarios/pr-deterministic-lifeops/
reports/scenarios/catalog-inventory/
reports/coverage/
if-no-files-found: ignore
retention-days: 3
deterministic-scenario:
name: Zero-Key Deterministic E2E
needs:
- changes
- scenario-unit-coverage
- app-browser-core
- app-browser-view-lifecycle
- app-browser-all-pages
- app-browser-feature-interactions
- app-browser-cloud-keyless
- app-browser-ratcheted
- app-browser-auto-discovered
- app-browser-touch-dashboard
- app-browser-touch-mobile
- app-browser-webkit
- app-accounts-ui
- app-walkthrough-mock
- app-diagnostics
- scenario-runner-e2e
if: ${{ !cancelled() && always() && needs.changes.outputs.run_scenario_pr == 'true' }}
runs-on: ${{ fromJSON(vars.HETZNER_FLEET_ONLINE == 'false' && '["ubuntu-24.04"]' || '["self-hosted","hetzner-robot"]') }}
steps:
- name: Check deterministic E2E slices
shell: bash
run: |
set -u
bad=0
for pair in \
"scenario-unit-coverage:${{ needs.scenario-unit-coverage.result }}" \
"app-browser-core:${{ needs.app-browser-core.result }}" \
"app-browser-view-lifecycle:${{ needs.app-browser-view-lifecycle.result }}" \
"app-browser-all-pages:${{ needs.app-browser-all-pages.result }}" \
"app-browser-feature-interactions:${{ needs.app-browser-feature-interactions.result }}" \
"app-browser-cloud-keyless:${{ needs.app-browser-cloud-keyless.result }}" \
"app-browser-ratcheted:${{ needs.app-browser-ratcheted.result }}" \
"app-browser-auto-discovered:${{ needs.app-browser-auto-discovered.result }}" \
"app-browser-touch-dashboard:${{ needs.app-browser-touch-dashboard.result }}" \
"app-browser-touch-mobile:${{ needs.app-browser-touch-mobile.result }}" \
"app-browser-webkit:${{ needs.app-browser-webkit.result }}" \
"app-accounts-ui:${{ needs.app-accounts-ui.result }}" \
"app-walkthrough-mock:${{ needs.app-walkthrough-mock.result }}" \
"app-diagnostics:${{ needs.app-diagnostics.result }}" \
"scenario-runner-e2e:${{ needs.scenario-runner-e2e.result }}"; do
name="${pair%%:*}"
result="${pair##*:}"
echo "$name: $result"
if [ "$result" != "success" ]; then
echo "::error title=Scenario PR E2E::$name finished with $result"
bad=1
fi
done
if [ "$bad" -ne 0 ]; then
exit 1
fi
echo "All deterministic E2E slices passed."