Summary
The visual-test schedule run is failing before the game ever starts. The failure happens in the workflow's Ensure visual-test label exists preflight step, not in the Vulkan/SDL/screenshot pipeline the diagnose prompt describes. There is no build-output.log for this run because the game command at .github/workflows/visual-test.yml:81 was skipped.
Workflow run: https://github.com/OpenStaticFish/ZigCraft/actions/runs/29809988559 (also reproduced on the previous scheduled run 29725595085, which used the same head SHA 8945da9).
Error output from the failing step
Step name in the Actions UI: Ensure visual-test label exists.
Observed step outcome:
Process completed with exit code 1.
Observed step state (from the run page):
Ensure visual-test label exists failure
Setup Lavapipe Vulkan skipped
Run menu screenshot capture skipped
Upload build log artifact skipped
Stop headless Wayland compositor skipped
Run opencode failure diagnosis failure
Weston itself started cleanly at 1280x720 and was terminated by the cleanup step after the preflight failure; weston.log contains no compositor error.
Diagnosis
The failure originates in .github/workflows/visual-test.yml:55-68, specifically the second guard and create at .github/workflows/visual-test.yml:62-65:
if ! gh label list --json name --jq '.[].name' | grep -q '^run-visual-test$'; then
gh label create "run-visual-test" \
--description "Run deterministic visual regression workflow on a PR" \
--color "E06C75"
fi
gh label list returns at most 30 labels by default. The repository currently has 41 labels (curl https://api.github.com/repos/OpenStaticFish/ZigCraft/labels?per_page=100). With the default ordering, visual-test is at position 38 and run-visual-test is at position 35 — both outside the first-page window, so neither guard sees them, both gh label create calls fire, and GitHub rejects the second one because run-visual-test already exists. That duplicate-create rejection is what produces exit code 1.
This is purely a workflow-side preflight failure. None of the rendering paths referenced in the diagnose prompt were reached:
initContext in modules/engine-graphics/src/rhi_vulkan.zig
- headless
createSwapchain path in modules/engine-graphics/src/vulkan_swapchain.zig:127-174
- menu selection in
src/game/app.zig:268-276
HomeScreen.init in modules/game-ui/src/screens/home.zig:33-41
captureFrame in modules/engine-graphics/src/rhi_vulkan.zig:415-420
requestCapture / recordCapture / completeCapture in modules/engine-graphics/src/vulkan/screenshot.zig
Therefore the Vulkan instance/device, swapchain, shader, HomeScreen, and screenshot readback code paths have not been exercised by these failures; they remain unverified until the workflow actually reaches the game step.
Side note on the diagnose prompt
The current visual-test.yml invokes zig build run -Dscreenshot-path=screenshot.png -Dskip-present=true (line 81), not -Dscreenshot-path=screenshot.ppm as .github/prompts/visual-test-diagnose.md describes. PNG is supported by detectScreenshotFormat in modules/engine-graphics/src/vulkan/screenshot.zig:262-267; PPM is not. If the workflow is ever changed to write a .ppm, requestCapture would log screenshot: unsupported image path 'screenshot.ppm' (use .png, .jpg, .jpeg, .gif, or .webp) and the game would never capture a frame. Either keep the workflow on .png, add a PPM encoder to screenshot.zig, or update the diagnose prompt to match the actual command.
Failure origin
- File:
.github/workflows/visual-test.yml
- Step:
Ensure visual-test label exists
- Failing command:
gh label create "run-visual-test" at .github/workflows/visual-test.yml:63
- Trigger: unpaginated
gh label list guard at .github/workflows/visual-test.yml:62 (and the symmetric guard for visual-test at lines 57-61)
- Head SHA:
8945da9ecb9944048dd94f70a88b63733dcc1a9e (feat: ship high-detail live world map (#943))
Suggested fix
Make the label setup idempotent without depending on a paginated gh label list query. Either pass --force to gh label create, or check each label with gh label view first. Increasing the --limit is fragile because the label count will keep growing.
- name: Ensure visual-test labels exist
run: |
gh label create "visual-test" \
--description "Issues from automated visual regression tests" \
--color "E06C75" \
--force
gh label create "run-visual-test" \
--description "Run deterministic visual regression workflow on a PR" \
--color "E06C75" \
--force
env:
GH_TOKEN: ${{ secrets.OPENCODE_PAT }}
After the fix, please re-run visual-test on dev so we can finally exercise the headless Lavapipe + screenshot path and confirm the actual rendering pipeline (which this issue has not been able to validate).
Summary
The
visual-testschedule run is failing before the game ever starts. The failure happens in the workflow'sEnsure visual-test label existspreflight step, not in the Vulkan/SDL/screenshot pipeline the diagnose prompt describes. There is nobuild-output.logfor this run because the game command at.github/workflows/visual-test.yml:81was skipped.Workflow run: https://github.com/OpenStaticFish/ZigCraft/actions/runs/29809988559 (also reproduced on the previous scheduled run
29725595085, which used the same head SHA8945da9).Error output from the failing step
Step name in the Actions UI:
Ensure visual-test label exists.Observed step outcome:
Observed step state (from the run page):
Weston itself started cleanly at 1280x720 and was terminated by the cleanup step after the preflight failure;
weston.logcontains no compositor error.Diagnosis
The failure originates in
.github/workflows/visual-test.yml:55-68, specifically the second guard and create at.github/workflows/visual-test.yml:62-65:gh label listreturns at most 30 labels by default. The repository currently has 41 labels (curl https://api.github.com/repos/OpenStaticFish/ZigCraft/labels?per_page=100). With the default ordering,visual-testis at position 38 andrun-visual-testis at position 35 — both outside the first-page window, so neither guard sees them, bothgh label createcalls fire, and GitHub rejects the second one becauserun-visual-testalready exists. That duplicate-create rejection is what producesexit code 1.This is purely a workflow-side preflight failure. None of the rendering paths referenced in the diagnose prompt were reached:
initContextinmodules/engine-graphics/src/rhi_vulkan.zigcreateSwapchainpath inmodules/engine-graphics/src/vulkan_swapchain.zig:127-174src/game/app.zig:268-276HomeScreen.initinmodules/game-ui/src/screens/home.zig:33-41captureFrameinmodules/engine-graphics/src/rhi_vulkan.zig:415-420requestCapture/recordCapture/completeCaptureinmodules/engine-graphics/src/vulkan/screenshot.zigTherefore the Vulkan instance/device, swapchain, shader, HomeScreen, and screenshot readback code paths have not been exercised by these failures; they remain unverified until the workflow actually reaches the game step.
Side note on the diagnose prompt
The current
visual-test.ymlinvokeszig build run -Dscreenshot-path=screenshot.png -Dskip-present=true(line 81), not-Dscreenshot-path=screenshot.ppmas.github/prompts/visual-test-diagnose.mddescribes. PNG is supported bydetectScreenshotFormatinmodules/engine-graphics/src/vulkan/screenshot.zig:262-267; PPM is not. If the workflow is ever changed to write a.ppm,requestCapturewould logscreenshot: unsupported image path 'screenshot.ppm' (use .png, .jpg, .jpeg, .gif, or .webp)and the game would never capture a frame. Either keep the workflow on.png, add a PPM encoder toscreenshot.zig, or update the diagnose prompt to match the actual command.Failure origin
.github/workflows/visual-test.ymlEnsure visual-test label existsgh label create "run-visual-test"at.github/workflows/visual-test.yml:63gh label listguard at.github/workflows/visual-test.yml:62(and the symmetric guard forvisual-testat lines 57-61)8945da9ecb9944048dd94f70a88b63733dcc1a9e(feat: ship high-detail live world map (#943))Suggested fix
Make the label setup idempotent without depending on a paginated
gh label listquery. Either pass--forcetogh label create, or check each label withgh label viewfirst. Increasing the--limitis fragile because the label count will keep growing.After the fix, please re-run
visual-testondevso we can finally exercise the headless Lavapipe + screenshot path and confirm the actual rendering pipeline (which this issue has not been able to validate).