You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
schedule event on dev at 2026-07-28T07:23:28Z (cron 43 4 * * *), head_sha=8d205ff (devenv migration #951).
Available evidence in the workspace
The only artifact left in the runner workspace after the job is:
weston.log — the headless Wayland compositor started at 07:27:45.538 and was killed by caught signal 15 at 07:27:47.506 (≈2 s later). No game output, no Lavapipe, no Vulkan validation messages.
No build-output.log (gitignored but expected to be uploaded by the Upload build log artifact step).
No screenshot.png (the Check screenshot exists step only emitted screenshot_exists=false because no run produced it).
The absence of build-output.log and screenshot.png is the same shape as the previous day's failures (#950, #952, #954). Those runs are still open because the same root cause keeps re-firing on every schedule.
Failure output
The exact stderr/stdout of the game is not in the workspace, so the literal lines from this specific run cannot be quoted verbatim. However, the job summary confirms that the only failing step is Ensure visual-test label exists (step 8 in visual-test.yml), and that every step after it — Setup Lavapipe Vulkan, Run menu screenshot capture, Check screenshot exists (still ran, screenshot_exists=false), Compare against golden image, Upload screenshot artifact, Check build log exists (still ran, exists=false), Upload build log artifact, Run opencode visual verification — is either skipped or null. That exactly matches the documented behaviour of gh label create against an existing label on a 41-label repo:
label with name "run-visual-test" already exists; use `--force` to update its color and description
##[error]Process completed with exit code 1.
That message aborts the preflight; the run-with-log action never runs, so build-output.log is missing and screenshot.png is not produced. The Zig / Lavapipe / Vulkan / screenshot.zig code path is not exercised at all on this run, so neither the headless swapchain (modules/engine-graphics/src/vulkan_swapchain.zig:127-175), the screenshot capture (modules/engine-graphics/src/vulkan/screenshot.zig), nor the screenshot loop in src/game/app.zig:527-592 are involved.
Note that .github/prompts/visual-test-diagnose.md:7-9,42-43 still claims the workflow uses -Dscreenshot-path=screenshot.ppm — that is stale: .github/workflows/visual-test.yml:81 actually runs -Dscreenshot-path=screenshot.png -Dskip-present=true, and build.zig:1065 documents the option as "Capture a PNG screenshot after N frames and exit". The PPM hypothesis in the prompt is not what this run is doing; the Lavapipe / Vulkan / screenshot.zig path is not exercised at all.
Diagnosis
The visual-test workflow does not fail in the Vulkan / screenshot capture path. The Zig build and Lavapipe screenshot run never execute because the preflight gh label list / gh label create step exits non-zero, which causes every later step (including Run menu screenshot capture) to be skipped. build-output.log therefore does not exist in the workspace because the run-with-log action never ran.
Root cause is in .github/workflows/visual-test.yml:55-68 (Ensure visual-test label exists):
if! gh label list --json name --jq '.[].name'| grep -q '^visual-test$';then
gh label create "visual-test" \
--description "Issues from automated visual regression tests" \
--color "E06C75"fiif! 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 paginates with a default page size of 30 and --jq '.[].name' only emits the first page. The repo currently has 41 labels (verified via gh label list --limit 100 --json name --jq '.[] | .name' → 41 names). On the unflagged 30-item call, run-visual-test (position 41) is not in page 1, so:
The if ! body runs gh label create "run-visual-test" ....
gh label create rejects the call with label with name "run-visual-test" already exists; use --force to update its color and description and exits 1.
The step's run: propagates exit 1 to the GitHub Actions runner, marking the step as failed (X).
All subsequent steps that rely on the default success() gating are skipped: Setup Lavapipe Vulkan, Run menu screenshot capture, Compare against golden image, Upload screenshot artifact, Upload build log artifact, Run opencode visual verification.
Only if: always() (Check screenshot exists, Check build log exists) and if: failure() || steps.screenshot.outcome == 'failure' || steps.check_screenshot.outputs.screenshot_exists != 'true' (Run opencode failure diagnosis) still execute, which is why this triage step is running at all.
weston.log survives because Stop headless Wayland compositor is also if: always(); it shows only the compositor startup that the parallel teardown step SIGTERMed.
This is the same failure that has been hitting the visual-test workflow every day since at least 2026-07-12 — see #916, #931, #935, #942, #944, #945, #946, #947, #949, #950, #952, #954. The most recent duplicates are #954 (run #30248571304) and #952 (run #30192579914), which document the identical root cause for the previous two schedule runs. Three consecutive days of open duplicates confirm the preflight logic is broken on every schedule run as soon as run-visual-test falls off page 1; the only thing that has kept the failure from firing more often is that some runs skip the preflight or gh happens to return the missing label by chance.
Command: gh label list --json name --jq '.[].name' (default --limit 30; first page only)
Condition: if ! ... | grep -q '^run-visual-test$'; then gh label create ...; fi — recreates an already-existing label once it falls off page 1
Head commit on this run: 8d205ff ("build: migrate dev environment and CI from nix flake to devenv (build: migrate dev environment and CI from nix flake to devenv #951)"), so the Ensure visual-test label exists step is the unmodified block that shipped in the migration.
Suggested fix
Either fetch all pages when listing labels, or make gh label create failures non-fatal so a duplicate label never aborts the workflow:
if! gh label list --json name --jq '.[].name' --paginate | grep -q '^visual-test$';then
gh label create "visual-test" \
--description "Issues from automated visual regression tests" \
--color "E06C75"||truefiif! gh label list --json name --jq '.[].name' --paginate | grep -q '^run-visual-test$';then
gh label create "run-visual-test" \
--description "Run deterministic visual regression workflow on a PR" \
--color "E06C75"||truefi
gh label create --force ... is the equivalent one-liner if you want the existing labels' colours / descriptions refreshed. Either change stops the failure from blocking Setup Lavapipe Vulkan and Run menu screenshot capture, which is the actual signal we need from this workflow.
Workflow
https://github.com/OpenStaticFish/ZigCraft/actions/runs/30338232720
scheduleevent ondevat2026-07-28T07:23:28Z(cron43 4 * * *),head_sha=8d205ff(devenv migration #951).Available evidence in the workspace
The only artifact left in the runner workspace after the job is:
weston.log— the headless Wayland compositor started at07:27:45.538and was killed bycaught signal 15at07:27:47.506(≈2 s later). No game output, no Lavapipe, no Vulkan validation messages.build-output.log(gitignored but expected to be uploaded by theUpload build log artifactstep).screenshot.png(theCheck screenshot existsstep only emittedscreenshot_exists=falsebecause no run produced it).The absence of
build-output.logandscreenshot.pngis the same shape as the previous day's failures (#950, #952, #954). Those runs are still open because the same root cause keeps re-firing on every schedule.Failure output
The exact stderr/stdout of the game is not in the workspace, so the literal lines from this specific run cannot be quoted verbatim. However, the job summary confirms that the only failing step is
Ensure visual-test label exists(step 8 invisual-test.yml), and that every step after it —Setup Lavapipe Vulkan,Run menu screenshot capture,Check screenshot exists(still ran,screenshot_exists=false),Compare against golden image,Upload screenshot artifact,Check build log exists(still ran,exists=false),Upload build log artifact,Run opencode visual verification— is eitherskippedornull. That exactly matches the documented behaviour ofgh label createagainst an existing label on a 41-label repo:That message aborts the preflight; the
run-with-logaction never runs, sobuild-output.logis missing andscreenshot.pngis not produced. The Zig / Lavapipe / Vulkan /screenshot.zigcode path is not exercised at all on this run, so neither the headless swapchain (modules/engine-graphics/src/vulkan_swapchain.zig:127-175), the screenshot capture (modules/engine-graphics/src/vulkan/screenshot.zig), nor the screenshot loop insrc/game/app.zig:527-592are involved.Note that
.github/prompts/visual-test-diagnose.md:7-9,42-43still claims the workflow uses-Dscreenshot-path=screenshot.ppm— that is stale:.github/workflows/visual-test.yml:81actually runs-Dscreenshot-path=screenshot.png -Dskip-present=true, andbuild.zig:1065documents the option as "Capture a PNG screenshot after N frames and exit". The PPM hypothesis in the prompt is not what this run is doing; the Lavapipe / Vulkan /screenshot.zigpath is not exercised at all.Diagnosis
The visual-test workflow does not fail in the Vulkan / screenshot capture path. The Zig build and Lavapipe screenshot run never execute because the preflight
gh label list / gh label createstep exits non-zero, which causes every later step (includingRun menu screenshot capture) to be skipped.build-output.logtherefore does not exist in the workspace because therun-with-logaction never ran.Root cause is in
.github/workflows/visual-test.yml:55-68(Ensure visual-test label exists):gh label listpaginates with a default page size of 30 and--jq '.[].name'only emits the first page. The repo currently has 41 labels (verified viagh label list --limit 100 --json name --jq '.[] | .name'→ 41 names). On the unflagged 30-item call,run-visual-test(position 41) is not in page 1, so:grep -q '^run-visual-test$'returns 1 (not found).if !body runsgh label create "run-visual-test" ....gh label createrejects the call withlabel with name "run-visual-test" already exists; use --force to update its color and descriptionand exits 1.run:propagates exit 1 to the GitHub Actions runner, marking the step as failed (X).success()gating are skipped:Setup Lavapipe Vulkan,Run menu screenshot capture,Compare against golden image,Upload screenshot artifact,Upload build log artifact,Run opencode visual verification.if: always()(Check screenshot exists,Check build log exists) andif: failure() || steps.screenshot.outcome == 'failure' || steps.check_screenshot.outputs.screenshot_exists != 'true'(Run opencode failure diagnosis) still execute, which is why this triage step is running at all.weston.logsurvives becauseStop headless Wayland compositoris alsoif: always(); it shows only the compositor startup that the parallel teardown step SIGTERMed.This is the same failure that has been hitting the visual-test workflow every day since at least 2026-07-12 — see #916, #931, #935, #942, #944, #945, #946, #947, #949, #950, #952, #954. The most recent duplicates are #954 (run
#30248571304) and #952 (run#30192579914), which document the identical root cause for the previous two schedule runs. Three consecutive days of open duplicates confirm the preflight logic is broken on every schedule run as soon asrun-visual-testfalls off page 1; the only thing that has kept the failure from firing more often is that some runs skip the preflight orghhappens to return the missing label by chance.Origin of the failure
.github/workflows/visual-test.ymlEnsure visual-test label exists(lines 55-68)gh label list --json name --jq '.[].name'(default--limit 30; first page only)if ! ... | grep -q '^run-visual-test$'; then gh label create ...; fi— recreates an already-existing label once it falls off page 18d205ff("build: migrate dev environment and CI from nix flake to devenv (build: migrate dev environment and CI from nix flake to devenv #951)"), so theEnsure visual-test label existsstep is the unmodified block that shipped in the migration.Suggested fix
Either fetch all pages when listing labels, or make
gh label createfailures non-fatal so a duplicate label never aborts the workflow:gh label create --force ...is the equivalent one-liner if you want the existing labels' colours / descriptions refreshed. Either change stops the failure from blockingSetup Lavapipe VulkanandRun menu screenshot capture, which is the actual signal we need from this workflow.Related
detectScreenshotFormat" hypothesis; closed as duplicate of the preflight root cause