Merge pull request 'ci(web): add precise wasm-freshness gate; drop flawed drift heuristic' (#93) from ci/web-wasm-freshness-gate into master
Build and Deploy / build-and-push (push) Successful in 1m15s
Web WASM Freshness / freshness (push) Failing after 7m6s

This commit was merged in pull request #93.
This commit is contained in:
2026-06-22 19:03:49 +00:00
2 changed files with 97 additions and 41 deletions
+6 -41
View File
@@ -36,47 +36,12 @@ jobs:
id: meta
run: echo "sha=${GITHUB_SHA::8}" >> "$GITHUB_OUTPUT"
- name: Check wasm pkg drift
run: |
set -euo pipefail
BASE_SHA="${{ github.event.before }}"
HEAD_SHA="${{ github.sha }}"
if [ -n "$BASE_SHA" ] && git cat-file -e "$BASE_SHA^{commit}" 2>/dev/null; then
RANGE="$BASE_SHA..$HEAD_SHA"
else
RANGE="HEAD~1..HEAD"
fi
CHANGED="$(git diff --name-only "$RANGE")"
echo "Changed files:"
echo "$CHANGED"
if echo "$CHANGED" | grep -Eq '^(solitaire_wasm/|solitaire_core/|Cargo\.toml|Cargo\.lock)$|^(solitaire_wasm/|solitaire_core/)'; then
if ! echo "$CHANGED" | grep -Eq '^solitaire_server/web/pkg/solitaire_wasm\.js$|^solitaire_server/web/pkg/solitaire_wasm_bg\.wasm$'; then
echo "error: wasm/core/Cargo changed but committed web pkg artifacts are missing."
echo "Run: wasm-pack build --target web --out-dir solitaire_server/web/pkg --no-typescript solitaire_wasm"
exit 1
fi
fi
# Hard check: solitaire_web/ is the direct Bevy WASM source — any
# change there MUST rebuild canvas_bg.wasm or the binary goes stale.
if echo "$CHANGED" | grep -Eq '^solitaire_web/'; then
if ! echo "$CHANGED" | grep -Eq '^solitaire_server/web/pkg/canvas_bg\.wasm$'; then
echo "error: solitaire_web/ changed but canvas_bg.wasm not updated."
echo "Run: ./build_wasm.sh (requires wasm-bindgen-cli + wasm32-unknown-unknown target)"
exit 1
fi
fi
# Advisory notice: solitaire_engine/ and solitaire_core/ changes often
# require a Bevy WASM rebuild but are not enforced (formatting-only
# commits should not be blocked).
if echo "$CHANGED" | grep -Eq '^(solitaire_engine/|solitaire_core/)' && \
! echo "$CHANGED" | grep -Eq '^solitaire_server/web/pkg/canvas_bg\.wasm$'; then
echo "notice: solitaire_engine/core changed without a canvas_bg.wasm rebuild."
echo " If the change affects gameplay run ./build_wasm.sh before pushing."
fi
# WASM artifact freshness is enforced precisely by the dedicated
# `web-wasm-freshness` workflow (rebuild-and-diff on every PR + master
# push), which supersedes the previous changed-files heuristic here.
# That heuristic only hard-failed on direct solitaire_web/ edits and
# treated solitaire_engine/_core changes as a non-blocking notice, which
# let the whole card_game migration ship a stale pkg/.
- name: Log in to Gitea registry
uses: docker/login-action@v3
+91
View File
@@ -0,0 +1,91 @@
name: Web WASM Freshness
# Guards against the committed solitaire_server/web/pkg/ artifacts going stale.
#
# A fresh build on a pinned toolchain is byte-for-byte reproducible (verified),
# so this job rebuilds the artifacts and fails if they differ from what is
# committed. Unlike a changed-files heuristic, this catches *any* drift in the
# wasm-feeding crates — solitaire_core / _engine / _data / _sync / _wasm / _web —
# including gameplay-logic changes that do not alter the JS API surface (e.g.
# the v4->v5 save-schema change that the old heuristic let through as a
# non-blocking "notice", leaving the deployed web build stale for ~3 weeks).
#
# Tool versions are pinned to whatever produced the committed artifacts. When
# you regenerate the artifacts with a newer toolchain, bump these in lockstep:
# rust 1.95.0 · wasm-bindgen 0.2.120 · wasm-pack 0.14.0 · binaryen 130
on:
push:
branches: [master]
paths:
- 'solitaire_core/**'
- 'solitaire_engine/**'
- 'solitaire_data/**'
- 'solitaire_sync/**'
- 'solitaire_wasm/**'
- 'solitaire_web/**'
- 'solitaire_server/web/pkg/**'
- 'Cargo.toml'
- 'Cargo.lock'
- 'build_wasm.sh'
- '.gitea/workflows/web-wasm-freshness.yml'
pull_request:
paths:
- 'solitaire_core/**'
- 'solitaire_engine/**'
- 'solitaire_data/**'
- 'solitaire_sync/**'
- 'solitaire_wasm/**'
- 'solitaire_web/**'
- 'solitaire_server/web/pkg/**'
- 'Cargo.toml'
- 'Cargo.lock'
- 'build_wasm.sh'
- '.gitea/workflows/web-wasm-freshness.yml'
workflow_dispatch:
jobs:
freshness:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Rust 1.95.0 (pinned for reproducible wasm output)
uses: dtolnay/rust-toolchain@master
with:
toolchain: 1.95.0
targets: wasm32-unknown-unknown
- name: Cache cargo build
uses: Swatinem/rust-cache@v2
- name: Install wasm-bindgen-cli + wasm-pack (pinned)
uses: taiki-e/install-action@v2
with:
tool: wasm-bindgen-cli@0.2.120,wasm-pack@0.14.0
- name: Install binaryen 130 (wasm-opt, pinned)
run: |
set -euo pipefail
curl -sSL \
https://github.com/WebAssembly/binaryen/releases/download/version_130/binaryen-version_130-x86_64-linux.tar.gz \
| tar xz
echo "$PWD/binaryen-version_130/bin" >> "$GITHUB_PATH"
- name: Rebuild WASM artifacts
run: ./build_wasm.sh
- name: Fail if committed pkg differs from a fresh build
run: |
set -euo pipefail
if [ -z "$(git status --porcelain -- solitaire_server/web/pkg/)" ]; then
echo "pkg/ artifacts match a fresh build."
else
echo "::error::solitaire_server/web/pkg/ is stale — a wasm-feeding crate changed without regenerating the artifacts."
echo "Fix: run ./build_wasm.sh and commit the updated solitaire_server/web/pkg/."
git status --porcelain -- solitaire_server/web/pkg/
git diff --stat -- solitaire_server/web/pkg/
exit 1
fi