Skip to content

fix(ci): sync package-lock with noto-emoji and update fixtures to contract v2 #47

fix(ci): sync package-lock with noto-emoji and update fixtures to contract v2

fix(ci): sync package-lock with noto-emoji and update fixtures to contract v2 #47

Workflow file for this run

name: "Native Golden — Shader Logic, Cross-Platform & WASM Parity"
# Runs on every PR and push that touches the compositor, shaders, contracts,
# CLI, or the WASM crate.
#
# What this job proves:
# ✅ WGSL shaders compile and run on Metal, DX12, Vulkan, and WebGPU.
# ✅ Compositor math is self-consistent (same-machine determinism).
# ✅ Any shader regression produces a measurable pixel delta and fails CI.
# ⚠️ Windows and Linux runners have NO dedicated GPU — wgpu uses software
# rasterizers (WARP / Lavapipe / SwiftShader). The adapter name in each
# job summary confirms what actually ran. Green = shader portability,
# NOT real hardware GPU parity.
#
# Hardware validation (what this does NOT replace):
# See docs/native-architecture.md §Hardware Validation Log.
#
# Tolerances:
# Native cross-backend (software vs Metal reference): 4 per-channel
# WASM vs native (same runner, SwiftShader vs Lavapipe): 8 per-channel
on:
push:
branches: [main, develop, master, "feat/**"]
paths:
- "src-tauri/src/wgpu_compositor/**"
- "src-tauri/src/shaders/**"
- "src-tauri/src/native_core/**"
- "crates/clypra-native-cli/**"
- "crates/clypra-native-core/**"
- "crates/clypra-render-wasm/**"
- ".github/workflows/native-golden.yml"
pull_request:
paths:
- "src-tauri/src/wgpu_compositor/**"
- "src-tauri/src/shaders/**"
- "src-tauri/src/native_core/**"
- "crates/clypra-native-cli/**"
- "crates/clypra-native-core/**"
- "crates/clypra-render-wasm/**"
- ".github/workflows/native-golden.yml"
permissions:
contents: read
env:
CLYPRA_ALLOW_FALLBACK_GPU: "1"
WGPU_ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER: "1"
jobs:
golden:
name: "Golden (${{ matrix.platform.name }})"
runs-on: ${{ matrix.platform.os }}
strategy:
fail-fast: false
matrix:
platform:
- name: "macOS Metal"
os: macos-latest
backend: Metal
- name: "Windows DX12"
os: windows-latest
backend: DX12
- name: "Linux Vulkan"
os: ubuntu-24.04
backend: Vulkan
steps:
- name: Checkout
uses: actions/checkout@v4
# ── Rust toolchain ────────────────────────────────────────────────────
- name: Setup Rust (native)
uses: dtolnay/rust-toolchain@stable
- name: Rust cache
uses: Swatinem/rust-cache@v2
with:
workspaces: |
src-tauri
crates/clypra-native-cli
crates/clypra-native-core
crates/clypra-render-wasm
# ── Platform-specific GPU setup (Linux) ───────────────────────────────
- name: Install Vulkan + Mesa Lavapipe (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update -qq
sudo apt-get install -y --no-install-recommends \
libvulkan1 mesa-vulkan-drivers vulkan-tools libasound2-dev \
libgl1-mesa-dri libegl1-mesa-dev
echo "VK_ICD_FILENAMES=/usr/share/vulkan/icd.d/lvp_icd.x86_64.json" >> "$GITHUB_ENV"
echo "VK_DRIVER_FILES=/usr/share/vulkan/icd.d/lvp_icd.x86_64.json" >> "$GITHUB_ENV"
echo "LIBGL_ALWAYS_SOFTWARE=1" >> "$GITHUB_ENV"
# ── Build clypra-native-cli ───────────────────────────────────────────
- name: Build clypra-native-cli
run: cargo build --release
working-directory: crates/clypra-native-cli
# ── Render fixtures ───────────────────────────────────────────────────
- name: Render minimal fixture
run: |
mkdir -p ../../artifacts
cargo run --release -- render \
fixtures/minimal-request.json \
../../artifacts/minimal-${{ matrix.platform.backend }}.png \
2>&1 | tee /tmp/render-minimal.log
GPU_LINE=$(grep "^GPU:" /tmp/render-minimal.log || echo "GPU: unknown")
echo "GPU_INFO=${GPU_LINE}" >> "$GITHUB_ENV"
working-directory: crates/clypra-native-cli
shell: bash
- name: Render raster fixture
run: |
cargo run --release -- render \
fixtures/raster-request.json \
../../artifacts/raster-${{ matrix.platform.backend }}.png \
2>/dev/null
working-directory: crates/clypra-native-cli
shell: bash
# ── Diff — native platforms vs Metal reference ─────────────────────────
- name: Diff minimal (vs Metal reference, tol=4)
id: diff_minimal
run: |
cargo run --release -- diff \
../../artifacts/minimal-${{ matrix.platform.backend }}.png \
fixtures/minimal-expected.png \
4 | tee ../../artifacts/diff-minimal-${{ matrix.platform.backend }}.json
working-directory: crates/clypra-native-cli
shell: bash
continue-on-error: true
- name: Diff raster (vs Metal reference, tol=4)
id: diff_raster
run: |
cargo run --release -- diff \
../../artifacts/raster-${{ matrix.platform.backend }}.png \
fixtures/raster-expected.png \
4 | tee ../../artifacts/diff-raster-${{ matrix.platform.backend }}.json
working-directory: crates/clypra-native-cli
shell: bash
continue-on-error: true
# ── Job summary ───────────────────────────────────────────────────────
- name: Write job summary
if: always()
run: |
echo "## Golden — ${{ matrix.platform.name }}" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "**Adapter:** \`${GPU_INFO:-unknown}\`" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
if echo "${GPU_INFO}" | grep -qiE "llvmpipe|software|warp|basic render|lavapipe|cpu"; then
echo "> ⚠️ **Software rasterizer.** Validates shader portability only — not real hardware parity." >> "$GITHUB_STEP_SUMMARY"
else
echo "> ✅ **Hardware GPU detected.**" >> "$GITHUB_STEP_SUMMARY"
fi
DIFF_SUFFIX="${{ matrix.platform.backend }}"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "| Fixture | maxChannelError | differing_pixels | mean_error | result |" >> "$GITHUB_STEP_SUMMARY"
echo "|---------|----------------|-----------------|------------|--------|" >> "$GITHUB_STEP_SUMMARY"
TOL="4"
for fixture in minimal raster; do
diff_file="artifacts/diff-${fixture}-${DIFF_SUFFIX}.json"
if [ -f "$diff_file" ]; then
max=$(python3 -c "import json; d=json.load(open('$diff_file')); print(d['maxChannelError'])" 2>/dev/null || echo "?")
dp=$(python3 -c "import json; d=json.load(open('$diff_file')); print(d['differingPixels'])" 2>/dev/null || echo "?")
mean=$(python3 -c "import json; d=json.load(open('$diff_file')); print(round(d['meanChannelError'],4))" 2>/dev/null || echo "?")
result="✅"
if [ "$max" != "?" ] && [ "$max" -gt "$TOL" ] 2>/dev/null; then result="❌"; fi
else
max="N/A"; dp="N/A"; mean="N/A"; result="⚠️ render failed"
fi
echo "| $fixture | $max | $dp | $mean | $result |" >> "$GITHUB_STEP_SUMMARY"
done
shell: bash
# ── Enforce tolerance ─────────────────────────────────────────────────
- name: Enforce minimal diff
if: ${{ steps.diff_minimal.outcome == 'failure' }}
run: |
echo "::error::minimal fixture exceeds tolerance for ${{ matrix.platform.name }}"
exit 1
shell: bash
- name: Enforce raster diff
if: ${{ steps.diff_raster.outcome == 'failure' }}
run: |
echo "::error::raster fixture exceeds tolerance for ${{ matrix.platform.name }}"
exit 1
shell: bash
# ── Upload artifacts ──────────────────────────────────────────────────
- name: Upload rendered PNGs and diff reports
if: always()
uses: actions/upload-artifact@v4
with:
name: golden-${{ matrix.platform.backend }}
path: artifacts/
retention-days: 30