name: Dogfood (preflight verdict vs reality) # Runs verify-dogfood on build-affecting pushes plus manual dispatch. Each leg # launches the packaged app, captures the [preflight2] verdict, INDEPENDENTLY # verifies boot success, and asserts they agree. Mismatches (false-positive, # false-negative, or missing line) fail the leg red. The aggregator job # downloads every leg's manifest, computes per-check disagreement rates, and # writes preflight-tunings.json which the preflight module reads to silently # downgrade a chronically-noisy check. Release-readiness gate runs at the end: # blocks the v* tag until every required platform has 12 consecutive clean runs. on: # No cron: dogfood runs only on pushes to eric/lock that touch build-affecting # code (not docs/gitignore/CI-meta) plus manual dispatch, so it never spends a # full packaged-app build every 2 hours just to tick. Release-readiness now # accrues from these push/dispatch runs instead of a clock; if the consecutive- # clean streak is short before a release, fire workflow_dispatch a few times. push: branches: [eric/lock] paths: - 'electron/**' - 'frontend/**' - 'backend/**' - 'scripts/build-app**' - 'scripts/fetch-router**' - 'scripts/ci/**' - '.github/workflows/dogfood.yml' workflow_dispatch: permissions: contents: read actions: read jobs: dogfood: strategy: fail-fast: false matrix: # Windows-only. macOS legs removed: runner starvation + untriageable # mac-only failures kept the matrix red. Re-add when a Mac maintainer # owns them (and pass --require win32,darwin to verify-release-readiness). os: [windows-latest] runs-on: ${{ matrix.os }} timeout-minutes: 60 env: CSC_IDENTITY_AUTO_DISCOVERY: 'false' GOOGLE_OAUTH_CLIENT_ID: 'e2e-placeholder.apps.googleusercontent.com' GOOGLE_OAUTH_CLIENT_SECRET: 'e2e-placeholder-secret' steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20.18.1' cache: npm cache-dependency-path: | electron/package-lock.json frontend/package-lock.json - uses: actions/setup-python@v5 with: { python-version: '3.13' } # Reuse the heavy build inputs (shares keys with e2e.yml so the two warm # each other's caches); the build script skips any input already on disk. - name: Cache bundled Python env uses: actions/cache@v4 with: path: electron/python-env key: pyenv-win-${{ hashFiles('scripts/build-python-env-win.ps1', 'backend/requirements.txt') }} - name: Cache uv binaries uses: actions/cache@v4 with: path: backend/uv-bin key: uvbin-win-${{ hashFiles('scripts/build-app-win.ps1') }} - name: Cache MCP bundles uses: actions/cache@v4 with: path: backend/mcp-bundles key: mcpbundles-win-${{ hashFiles('scripts/build-app-win.ps1') }} - name: Build packaged app (Windows) shell: pwsh run: pwsh -NoProfile -File scripts/build-app-win.ps1 - name: Dogfood run (verdict vs reality cross-check) shell: bash run: node scripts/ci/verify-dogfood.js --manifest scripts/ci/dogfood-manifest.jsonl - name: Upload per-leg manifest fragment if: always() uses: actions/upload-artifact@v4 with: name: dogfood-manifest-${{ matrix.os }} path: scripts/ci/dogfood-manifest.jsonl retention-days: 90 aggregate: needs: dogfood if: always() runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: '20.18.1' } - name: Download every leg's manifest uses: actions/download-artifact@v4 with: pattern: dogfood-manifest-* path: dogfood-fragments - name: Merge into the rolling manifest shell: bash run: | touch scripts/ci/dogfood-manifest.jsonl for f in dogfood-fragments/*/dogfood-manifest.jsonl; do [ -f "$f" ] && cat "$f" >> scripts/ci/dogfood-manifest.jsonl done wc -l scripts/ci/dogfood-manifest.jsonl - name: Aggregate + auto-tune shell: bash run: node scripts/ci/dogfood-aggregator.js - name: Upload tunings (preflight reads this next build) uses: actions/upload-artifact@v4 with: name: preflight-tunings path: scripts/ci/preflight-tunings.json retention-days: 90 - name: Release readiness summary (informational; release workflow enforces it on v* tag) shell: bash run: node scripts/ci/verify-release-readiness.js || echo "Not yet ready - the v* tag will be blocked until consecutive clean runs accrue."