Workflow run
https://github.com/OpenStaticFish/ZigCraft/actions/runs/29143688205
Relevant error output
build-output.log was expected in the workspace root but was not present in this diagnosis workspace, so the exact game stdout/stderr lines could not be quoted from the run log.
The only local runtime log was weston.log, which shows the compositor started normally and was later stopped:
[06:59:01.523] weston 14.0.1
[06:59:01.523] Command line: weston --socket=headless --backend=headless-backend.so --width=1280 --height=720
[06:59:01.527] Output 'headless' enabled with head(s) headless
[06:59:03.056] caught signal 15
The deterministic error emitted by the screenshot implementation for the described command -Dscreenshot-path=screenshot.ppm is:
screenshot: unsupported image path 'screenshot.ppm' (use .png, .jpg, .jpeg, .gif, or .webp)
SCREENSHOT: Failed to capture screenshot
Diagnosis
The described visual test requests screenshot.ppm, but the Vulkan screenshot writer does not support PPM output. captureScreenshot reaches writeImage, which calls detectScreenshotFormat; that accepts .png, .jpg, .jpeg, .gif, and .webp, and only .png is implemented. A .ppm path returns null, logs the unsupported-path error, returns false, and leaves no screenshot.ppm for later conversion/checking.
There is also a repository mismatch to clean up: the current workflow uses screenshot.png in .github/workflows/visual-test.yml:81, while the diagnosis prompt still documents screenshot.ppm in .github/prompts/visual-test-diagnose.md:7 and .github/prompts/visual-test-diagnose.md:42.
Origin
modules/engine-graphics/src/vulkan/screenshot.zig:183 — writeImage
modules/engine-graphics/src/vulkan/screenshot.zig:200 — detectScreenshotFormat
modules/engine-graphics/src/rhi_vulkan.zig:409 — captureFrame
src/game/app.zig:512 — screenshot capture call site
The headless swapchain path itself looks compatible with readback: modules/engine-graphics/src/vulkan_swapchain.zig:119 creates one offscreen image and includes VK_IMAGE_USAGE_TRANSFER_SRC_BIT at modules/engine-graphics/src/vulkan_swapchain.zig:139.
Suggested fix
Prefer one format consistently. The simplest fix is to use PNG everywhere and update stale prompt/docs/scripts to match the current workflow:
command: nix develop .#ci-graphics --command zig build run -Dscreenshot-path=screenshot.png -Dskip-present=true
If PPM output is still desired, add real PPM support instead:
const ScreenshotFormat = enum {
png,
ppm,
jpeg,
gif,
webp,
};
fn detectScreenshotFormat(path: []const u8) ?ScreenshotFormat {
if (hasExtension(path, ".png")) return .png;
if (hasExtension(path, ".ppm")) return .ppm;
if (hasExtension(path, ".jpg") or hasExtension(path, ".jpeg")) return .jpeg;
if (hasExtension(path, ".gif")) return .gif;
if (hasExtension(path, ".webp")) return .webp;
return null;
}
Then route .ppm to a writePPM implementation that writes a binary P6 header and RGB rows using the same BGRA/RGBA channel handling currently used by writePNG.
Workflow run
https://github.com/OpenStaticFish/ZigCraft/actions/runs/29143688205
Relevant error output
build-output.logwas expected in the workspace root but was not present in this diagnosis workspace, so the exact game stdout/stderr lines could not be quoted from the run log.The only local runtime log was
weston.log, which shows the compositor started normally and was later stopped:The deterministic error emitted by the screenshot implementation for the described command
-Dscreenshot-path=screenshot.ppmis:Diagnosis
The described visual test requests
screenshot.ppm, but the Vulkan screenshot writer does not support PPM output.captureScreenshotreacheswriteImage, which callsdetectScreenshotFormat; that accepts.png,.jpg,.jpeg,.gif, and.webp, and only.pngis implemented. A.ppmpath returnsnull, logs the unsupported-path error, returnsfalse, and leaves noscreenshot.ppmfor later conversion/checking.There is also a repository mismatch to clean up: the current workflow uses
screenshot.pngin.github/workflows/visual-test.yml:81, while the diagnosis prompt still documentsscreenshot.ppmin.github/prompts/visual-test-diagnose.md:7and.github/prompts/visual-test-diagnose.md:42.Origin
modules/engine-graphics/src/vulkan/screenshot.zig:183—writeImagemodules/engine-graphics/src/vulkan/screenshot.zig:200—detectScreenshotFormatmodules/engine-graphics/src/rhi_vulkan.zig:409—captureFramesrc/game/app.zig:512— screenshot capture call siteThe headless swapchain path itself looks compatible with readback:
modules/engine-graphics/src/vulkan_swapchain.zig:119creates one offscreen image and includesVK_IMAGE_USAGE_TRANSFER_SRC_BITatmodules/engine-graphics/src/vulkan_swapchain.zig:139.Suggested fix
Prefer one format consistently. The simplest fix is to use PNG everywhere and update stale prompt/docs/scripts to match the current workflow:
If PPM output is still desired, add real PPM support instead:
Then route
.ppmto awritePPMimplementation that writes a binaryP6header and RGB rows using the same BGRA/RGBA channel handling currently used bywritePNG.