The automated visual test workflow failed at the golden-image comparison step. The screenshot capture itself works correctly, but the comparison never runs because the baseline image is invalid.
What failed
scripts/compare_visual_golden.sh exits 1 with:
Golden screenshot is effectively black (mean 0); refusing an invalid visual comparison
The check at the top of the script (require_non_black_image) aborts before any RMSE comparison:
# scripts/compare_visual_golden.sh:22-28
require_non_black_image() {
local image=$1
local label=$2
local mean
mean=$(magick "$image" -colorspace RGB -format '%[fx:mean]' info:)
if awk -v value="$mean" 'BEGIN { exit !(value <= 0.0001) }'; then
printf '%s is effectively black (mean %s); refusing an invalid visual comparison\n' "$label" "$mean" >&2
exit 1
fi
}
Verified locally with ImageMagick:
$ magick docs/visual-test/golden/menu.png -colorspace RGB -format 'mean=%[fx:mean] max=%[fx:maxima] min=%[fx:minima]\n' info:
mean=0 max=0 min=0
The committed golden docs/visual-test/golden/menu.png (332 bytes, 1920x1080, 1-bit grayscale) is a fully-black PNG.
Why this trips the workflow
.github/workflows/visual-test.yml:99-105 runs the comparison unconditionally whenever screenshot.png exists:
- name: Compare against golden image
id: golden_diff
if: steps.check_screenshot.outputs.screenshot_exists == 'true'
run: |
nix shell nixpkgs#imagemagick -c bash scripts/compare_visual_golden.sh screenshot.png docs/visual-test/golden/menu.png visual-diff.png
env:
VISUAL_DIFF_RMSE_TOLERANCE: "0.015"
The script's pre-check refuses to compare against any image whose mean pixel value is <= 0.0001 (effectively black). The committed golden hits that guard, so the job exits 1 and failure() becomes true, which triggers the diagnose step (Run opencode failure diagnosis, line 148).
A locally produced screenshot.png (rendered with the same Lavapipe + Weston + ZIGCRAFT_SAFE_RENDER=1 setup the workflow uses) renders the menu UI correctly and has mean=0.00889345 — well above the guard — so the failure is not on the capture side, only on the baseline.
Additional observation
build-output.log was not present in the workspace when the diagnose agent ran (only weston.log, an empty logs/ directory, and the existing zig-out/ from prior builds). That points at the Run menu screenshot capture step in .github/workflows/visual-test.yml:73-87 failing before the tee in .github/actions/run-with-log/action.yml:33 could create the log file, or the log having been cleaned up between steps. Either way, the actual terminal failure the workflow surfaces is the golden-image guard above, not anything inside the screenshot capture pipeline.
Suggested fix
Regenerate the baseline so it is not all-black:
- Run the capture command locally (matches the workflow):
mkdir -p /tmp/runtime-runner && chmod 700 /tmp/runtime-runner
export XDG_RUNTIME_DIR=/tmp/runtime-runner WAYLAND_DISPLAY=headless \
ZIGCRAFT_SAFE_RENDER=1 ZIGCRAFT_SMOKE_FRAMES=5 \
VK_ICD_FILENAMES=$(nix build --no-link --print-out-paths nixpkgs#mesa.drivers)/share/vulkan/icd.d/lvp_icd.x86_64.json \
VK_LAYER_PATH=$(nix build --no-link --print-out-paths nixpkgs#vulkan-validation-layers)/share/vulkan/explicit_layer.d \
VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation \
VK_LAYER_SETTINGS_PATH=$PWD/.github/vulkan/vk_layer_settings.txt
devenv shell --profile graphics -- weston --socket=headless --backend=headless-backend.so --width=1280 --height=720 &
devenv shell --profile graphics -- zig build run -Dscreenshot-path=docs/visual-test/golden/menu.png -Dskip-present=true
- Confirm the regenerated PNG is non-black (
magick ... -format '%[fx:mean]' info: returns a positive value).
- Commit the new
docs/visual-test/golden/menu.png.
If the regenerated golden is intentionally a blank output (e.g., ZIGCRAFT_SAFE_RENDER=1 + ZIGCRAFT_SKIP_WORLD_UPDATE already disables world passes and the menu preview can't seed before the capture timeout), then the test needs a different shape — either a UI-only render path that fills the frame, or skip the regression test under safe-render mode and add a non-safe-render variant for golden regeneration.
Reference
The automated visual test workflow failed at the golden-image comparison step. The screenshot capture itself works correctly, but the comparison never runs because the baseline image is invalid.
What failed
scripts/compare_visual_golden.shexits 1 with:The check at the top of the script (
require_non_black_image) aborts before any RMSE comparison:Verified locally with ImageMagick:
The committed golden
docs/visual-test/golden/menu.png(332 bytes, 1920x1080, 1-bit grayscale) is a fully-black PNG.Why this trips the workflow
.github/workflows/visual-test.yml:99-105runs the comparison unconditionally wheneverscreenshot.pngexists:The script's pre-check refuses to compare against any image whose mean pixel value is
<= 0.0001(effectively black). The committed golden hits that guard, so the job exits 1 andfailure()becomes true, which triggers the diagnose step (Run opencode failure diagnosis, line 148).A locally produced
screenshot.png(rendered with the same Lavapipe + Weston + ZIGCRAFT_SAFE_RENDER=1 setup the workflow uses) renders the menu UI correctly and hasmean=0.00889345— well above the guard — so the failure is not on the capture side, only on the baseline.Additional observation
build-output.logwas not present in the workspace when the diagnose agent ran (onlyweston.log, an emptylogs/directory, and the existingzig-out/from prior builds). That points at theRun menu screenshot capturestep in.github/workflows/visual-test.yml:73-87failing before theteein.github/actions/run-with-log/action.yml:33could create the log file, or the log having been cleaned up between steps. Either way, the actual terminal failure the workflow surfaces is the golden-image guard above, not anything inside the screenshot capture pipeline.Suggested fix
Regenerate the baseline so it is not all-black:
magick ... -format '%[fx:mean]' info:returns a positive value).docs/visual-test/golden/menu.png.If the regenerated golden is intentionally a blank output (e.g.,
ZIGCRAFT_SAFE_RENDER=1+ZIGCRAFT_SKIP_WORLD_UPDATEalready disables world passes and the menu preview can't seed before the capture timeout), then the test needs a different shape — either a UI-only render path that fills the frame, or skip the regression test under safe-render mode and add a non-safe-render variant for golden regeneration.Reference
scripts/compare_visual_golden.sh:23-29(require_non_black_imageguard).github/workflows/visual-test.yml:99-105docs/visual-test/golden/menu.png(332 B, all pixels == 0)