name: ci on: push: branches: [main] pull_request: concurrency: group: ci-${{ github.ref }} cancel-in-progress: true jobs: web: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - uses: pnpm/action-setup@v4 with: { version: 11.21.0 } - uses: actions/setup-node@v5 with: { node-version: 22, cache: pnpm } # Asserts the toolchain matches what package.json pins, rather than # discovering a mismatch three steps later as an unrelated build error. - name: preflight run: | test "$(pnpm -v)" = "11.21.0" || { echo "pnpm $(pnpm -v) != 11.21.0"; exit 1; } - run: CI=true pnpm install --frozen-lockfile - run: pnpm typecheck - run: pnpm check - run: pnpm test - run: pnpm build - run: node scripts/bundle-budget.mjs # The prerender pass writes a real HTML file per route. Crawlers do not # run JavaScript, so without these every shared link previews as the # homepage — assert the baked tags actually landed. - name: prerendered head is real run: | test -f dist/demos/wordle/index.html || { echo "no prerendered demo route"; exit 1; } grep -q 'og:title' dist/demos/wordle/index.html || { echo "og tags missing"; exit 1; } grep -qv 'PIG Demo — RL environments you can play' dist/demos/wordle/index.html \ || { echo "demo route kept the homepage title"; exit 1; } test -f dist/404.html || { echo "no 404.html"; exit 1; } # A blob-backed worker is blocked in production and nowhere else: the # site's CSP has no worker-src, so it falls back to default-src 'self'. # The failure is silent — the solver simply never boots. - name: no inline workers run: | ! grep -rqE "createObjectURL|blob:" dist/assets/*.js \ || { echo "a blob: URL reached the bundle; CSP will block it in prod"; exit 1; } python: runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - uses: astral-sh/setup-uv@v6 with: { enable-cache: true } - run: uv sync --all-packages # Rebuild the word lists from their committed sources and assert the # output is byte-identical. If it is not, every downstream number — # the conformance digest included — is describing a different game. - name: word lists rebuild identically run: | uv run python envs/wordle_five/words/build_words.py git diff --exit-code envs/wordle_five/words/*.json - run: uv run pytest envs/wordle_five/tests -q - run: uv run python envs/probe.py # The cross-language gate. Both halves score all 21.2M (guess, answer) # pairs; the digests must match each other and the committed value. - uses: pnpm/action-setup@v4 with: { version: 11.21.0 } - uses: actions/setup-node@v5 with: { node-version: 22, cache: pnpm } - run: CI=true pnpm install --frozen-lockfile - run: pnpm conformance # Every committed fixture must replay through the Python engine and # reproduce its own recorded rewards. A fixture that cannot be # regenerated is a claim with no receipt behind it. - run: uv run python envs/verify_fixtures.py