Merge pull request #265 from IAnMove/codex/3d-speech-productions #785
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: CI | |
| # Deterministic quality gates that must pass on every push + PR. | |
| # The clean-repo guard is the important one for a public repo: it fails | |
| # the build if mature/explicit prose or locally-generated model guides | |
| # ever leak into tracked source (see scripts/verify_clean_repo.py). | |
| # | |
| # GitHub Actions are pinned to commit SHAs (immutable). Version comments | |
| # are documentation only; do not use moving tags such as @v4 or @latest. | |
| on: | |
| push: | |
| branches: [main, development, dev] | |
| pull_request: | |
| branches: [main, development, dev] | |
| workflow_dispatch: | |
| # Measuring jobs never get write tokens. Artifact upload still works with | |
| # contents: read on this repository. Do not restore pull-request write | |
| # permission on ui-check; that is how untrusted PR code published comments. | |
| permissions: | |
| contents: read | |
| # Cancel superseded PR runs only. Pushes to development/main keep run_id so a | |
| # release or branch push is not cancelled by a later PR. | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| jobs: | |
| guard: | |
| name: Clean-repo guard + Python checks | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 20 | |
| steps: | |
| - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 | |
| - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 | |
| with: | |
| python-version: "3.10" | |
| - name: Clean-repo boundary guard | |
| run: python scripts/verify_clean_repo.py | |
| - name: Dependency install/update contract smoke | |
| run: python scripts/check_dependency_contract.py | |
| - name: Documentation links and drift | |
| run: python scripts/check_documentation_links.py | |
| - name: Visible brand and compatibility contract | |
| run: python scripts/check_brand_contract.py | |
| - name: Python syntax check (our modules) | |
| # compileall only compiles (never imports), so it needs no deps and | |
| # skips heavy vendored model code. Covers the surface we edit. | |
| run: python -m compileall -q app/services app/launch.py scripts | |
| - name: Install lightweight test dependencies | |
| run: >- | |
| python -m pip install | |
| "starlette==0.46.1" | |
| "soundfile==0.13.1" | |
| "numpy==2.2.6" | |
| "opencv-python-headless==4.12.0.88" | |
| "Pillow==11.3.0" | |
| "requests==2.32.4" | |
| "accelerate==1.12.0" | |
| "av==16.1.0" | |
| "diffusers==0.36.0" | |
| "decord==0.6.0" | |
| "einops==0.8.2" | |
| "fastapi==0.115.12" | |
| "ffmpeg-python==0.2.0" | |
| "imageio==2.37.2" | |
| "imageio-ffmpeg==0.6.0" | |
| "json_repair==0.59.5" | |
| "mmgp==3.7.6" | |
| "onnxruntime==1.23.2" | |
| "pydantic==2.10.6" | |
| "psutil==7.2.2" | |
| "pytest==8.3.5" | |
| "rembg==2.0.65" | |
| "tqdm==4.67.3" | |
| "transformers==4.57.1" | |
| "websocket-client==1.9.0" | |
| - name: Install CPU tensor test runtime | |
| run: >- | |
| python -m pip install | |
| "torch==2.7.0+cpu" | |
| "torchaudio==2.7.0+cpu" | |
| "torchvision==0.22.0+cpu" | |
| --extra-index-url https://download.pytorch.org/whl/cpu | |
| - name: Install ffmpeg for media tests | |
| run: sudo apt-get update && sudo apt-get install -y ffmpeg | |
| - name: Pytest collection | |
| run: python -m pytest --collect-only -q | |
| - name: Python test suite | |
| run: python -m pytest -q | |
| ui-check: | |
| name: UI tests + lint + type-check + build | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 | |
| - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 | |
| with: | |
| node-version: "24.18.0" | |
| check-latest: false | |
| cache: npm | |
| cache-dependency-path: ui/package-lock.json | |
| - name: Install UI deps | |
| working-directory: ui | |
| run: npm ci | |
| - name: First-party LOC and complexity ratchet | |
| env: | |
| # PRs compare with the PR base. Pushes to development/main compare | |
| # with the previous tip (github.event.before). Never fall back to | |
| # the historical dashboard: that paints merge commits red. | |
| BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }} | |
| run: | | |
| set -euo pipefail | |
| if [ -z "${BASE_SHA:-}" ] || [ "${BASE_SHA}" = "0000000000000000000000000000000000000000" ]; then | |
| echo "Cannot resolve code-health base: need pull_request.base.sha or push before" >&2 | |
| exit 2 | |
| fi | |
| set +e | |
| bash scripts/check_code_health_pr_base.sh | tee code-health.md | |
| STATUS=${PIPESTATUS[0]} | |
| set -e | |
| if [ -n "${GITHUB_STEP_SUMMARY:-}" ] && [ -s code-health.md ]; then | |
| cat code-health.md >> "$GITHUB_STEP_SUMMARY" | |
| fi | |
| exit "$STATUS" | |
| - name: Upload code-health report | |
| if: always() | |
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 | |
| with: | |
| name: code-health-report | |
| path: code-health.md | |
| if-no-files-found: ignore | |
| # Split `npm run check` so a hung runner is visible in the failing step | |
| # instead of one opaque 6-hour job (GitHub's default timeout). | |
| - name: UI tests | |
| working-directory: ui | |
| run: npm test | |
| - name: Lint with zero warnings | |
| working-directory: ui | |
| run: npm run lint -- --max-warnings=0 | |
| - name: Type-check, build and bundle budget | |
| working-directory: ui | |
| run: npm run build && npm run budget | |
| ui-e2e: | |
| name: UI E2E boot (Chromium + simulated API) | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 20 | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 | |
| - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 | |
| with: | |
| node-version: "24.18.0" | |
| check-latest: false | |
| cache: npm | |
| cache-dependency-path: ui/package-lock.json | |
| - name: Install UI deps | |
| working-directory: ui | |
| run: npm ci | |
| - name: Install Playwright Chromium | |
| working-directory: ui | |
| run: npx playwright install --with-deps chromium | |
| - name: Install Chrome for native H.264 and AAC speech export checks | |
| working-directory: ui | |
| run: npx playwright install chrome | |
| - name: UI E2E | |
| working-directory: ui | |
| run: npm run test:e2e | |
| - name: Upload Playwright artifacts | |
| # Passing speech tests also attach screenshots, native JSON and MP4 evidence. | |
| if: always() | |
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 | |
| with: | |
| name: ui-e2e-artifacts | |
| path: | | |
| ui/playwright-report | |
| ui/test-results | |
| if-no-files-found: ignore | |
| ui-speech-windows: | |
| name: Speech E2E Windows (real H.264 + AAC) | |
| runs-on: windows-2025 | |
| timeout-minutes: 15 | |
| env: | |
| # This job may not pass via the unsupported-codec assertion. | |
| HOCUSPOCUS_REQUIRE_SPEECH_AAC: "1" | |
| steps: | |
| - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 | |
| - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0 | |
| with: | |
| node-version: "24.18.0" | |
| check-latest: false | |
| cache: npm | |
| cache-dependency-path: ui/package-lock.json | |
| - name: Install UI deps | |
| working-directory: ui | |
| run: npm ci | |
| - name: Install Chromium for screen regression and Edge for native AAC | |
| working-directory: ui | |
| run: npx playwright install chromium msedge | |
| - name: Speech E2E with real export required | |
| working-directory: ui | |
| run: npm run test:e2e -- scene3d-speech.spec.ts scene3d-media-screen.spec.ts --workers=1 | |
| - name: Upload speech evidence | |
| if: always() | |
| uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 | |
| with: | |
| name: ui-speech-windows-artifacts | |
| path: | | |
| ui/playwright-report | |
| ui/test-results | |
| if-no-files-found: ignore | |
| code-health-comment: | |
| name: Code-health PR comment | |
| if: ${{ github.event_name == 'pull_request' && always() && github.event.pull_request.head.repo.full_name == github.repository }} | |
| needs: [ui-check] | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 5 | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| steps: | |
| # Publisher runs from the PR *base* tree so untrusted head code cannot | |
| # replace publish_pr_markdown.py while this job has pull-requests:write. | |
| - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 | |
| with: | |
| ref: ${{ github.event.pull_request.base.sha }} | |
| persist-credentials: false | |
| - name: Download code-health report | |
| continue-on-error: true | |
| uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 | |
| with: | |
| name: code-health-report | |
| path: . | |
| - name: Publish score comment | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: python3 scripts/publish_pr_markdown.py --file code-health.md | |
| ci-required: | |
| name: CI required | |
| if: always() | |
| needs: [guard, ui-check, ui-e2e, ui-speech-windows] | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 5 | |
| steps: | |
| - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 | |
| - name: Require successful jobs | |
| run: | | |
| python3 scripts/ci_required.py \ | |
| "Clean-repo guard + Python checks=${{ needs.guard.result }}" \ | |
| "UI tests + lint + type-check + build=${{ needs.ui-check.result }}" \ | |
| "UI E2E boot (Chromium + simulated API)=${{ needs.ui-e2e.result }}" \ | |
| "Speech E2E Windows (real H.264 + AAC)=${{ needs.ui-speech-windows.result }}" |