fix(ci): the shader drift gate never ran — dash has no process substitution

`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) <noreply@anthropic.com>
This commit is contained in:
2026-07-28 18:28:29 +02:00
co-authored by Claude Opus 5
parent 4065b5bd03
commit 2f39e15e88
+10 -2
View File
@@ -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