From 2f39e15e88547b80e7b5f7883bda1bf1f7810c22 Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Tue, 28 Jul 2026 18:28:29 +0200 Subject: [PATCH] =?UTF-8?q?fix(ci):=20the=20shader=20drift=20gate=20never?= =?UTF-8?q?=20ran=20=E2=80=94=20dash=20has=20no=20process=20substitution?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `diff <(spirv-dis …) <(spirv-dis …)` is bash syntax, and Gitea's runner executes a step's `run:` under `sh -e`. dash rejected the script at PARSE time, so the gate compared nothing — and, being step 2 of the `rust` job, it took Format, Clippy, Build, Test, the feature-gated encode backends, the C ABI harness and the committed-header check down with it. Every one of those has been skipped on the 35 commits between the gate landing (143a707f) and this one. A gate that cannot run looks exactly like a gate that passes, which is the precise failure mode it was written to prevent. Disassemble to files instead. That is dash-clean without depending on whether act_runner honours a `shell: bash` override, which is the other way to fix it and the more fragile one. Verified in CI's own container (ubuntu:resolute, glslang 16.2.0, spirv-tools 2026.1) by running the step body extracted from this YAML under `sh -e`: it passes on the current tree, and — the half worth checking — it still FAILS on a deliberately corrupted blob, so it is not passing vacuously. Co-Authored-By: Claude Opus 5 (1M context) --- .gitea/workflows/ci.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 92e53e93..4fafe9d7 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -31,14 +31,22 @@ jobs: # or failing test. Recompile each shader and diff the disassembly. Filtering OpSourceExtension # (+ --no-header) is exactly what absorbs the shaderc-vs-glslang generator difference; every # instruction, ID and constant must match. + # + # Disassemble to FILES rather than `diff <(…) <(…)`: Gitea's runner executes a step's `run:` + # under `sh -e`, not bash, and dash has no process substitution — the shell rejected the + # script at PARSE time, so the gate never compared anything. Worse, it took the whole `rust` + # job with it: Format, Clippy, Build, Test and every gate below were skipped on each of the + # 35 commits between the gate landing (143a707f) and this fix. A gate that cannot run is + # indistinguishable from one that passes, which is exactly the failure it exists to prevent. - name: Shader SPIR-V drift gate (pf-zerocopy) run: | apt-get install -y --no-install-recommends glslang-tools spirv-tools for s in rgb2nv12_buf cursor_blend; do d=crates/pf-zerocopy/src/imp glslangValidator -V "$d/$s.comp" -o "/tmp/$s.spv" >/dev/null - diff <(spirv-dis --no-header "$d/$s.spv" | grep -v OpSourceExtension) \ - <(spirv-dis --no-header "/tmp/$s.spv" | grep -v OpSourceExtension) \ + spirv-dis --no-header "$d/$s.spv" | grep -v OpSourceExtension > "/tmp/$s.committed" + spirv-dis --no-header "/tmp/$s.spv" | grep -v OpSourceExtension > "/tmp/$s.rebuilt" + diff "/tmp/$s.committed" "/tmp/$s.rebuilt" \ || { echo "::error::$d/$s.spv is stale — rebuild it from $s.comp"; exit 1; } done