Repository navigation
engine-candidate: check stable-diffusion.cpp builds (engine=sd-cpp) - #47
Merged
Merged
Conversation
…backend The engine candidate check runs sd.cpp's live tests on CI runners, and a macOS runner's GPU is a paravirtual device that ggml's Metal kernels crash on. With ATOMIC_DIFFUSION_BACKEND=cpu a load starts with the same extraArgs the automatic CPU recovery uses (`--backend cpu`, cpuBackendExtraArgs); any other value, or none, changes nothing. A chosen backend is not a recovery: cpuFallback stays false. The live test sets it through ATOMIC_LIVE_SD_BACKEND=cpu. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The engine update pipeline (atomic-hatchet-pipeline) now updates the image
engine too and needs results.json for two runs: the Atomic fork's build of
a leejet tag (master-<N>-<sha7>, core_ref=main) and conf's signed mirror of
it (master-<N>-<sha7>-a<rev>) at a core release. What differs from
llama.cpp is in .github/engine-candidate/sd-cpp.json (`kind: sdcpp`):
- resolve: complete once every archive conf's mirror requires and the CPU
archive of each live platform is up once with its digest; on conf, the
staging manifest (or the live one, when that names the tag) has to name
the tag, download from conf and pin the release's sizes and sha256.
candidate.commit is the leejet tag's (git ls-remote); results.json adds
candidate.upstream_tag, atomic_rev and manifest. The pin is conf's
sdcpp-manifest.json tag_name (resolveSdcppPins, held to
parseSdcppManifest and sdcppHostChoice), fetched from conf (pin_repo).
- surface (scripts/lib/sdcpp-surface.mjs): the same report schema with
sd.cpp's checks: sd-server --help by whole aliases (--vae-format is not
--vae), --version naming the tag's commit, the install probe's markers,
the archives by backend, leejet's history between the two tags (dates of
leejet's releases, a git cache per upstream repo). Contract:
test/fixtures/sdcpp/engine-contract.json, held to src/diffusion and
src/engine-builds by test/contract/sdcpp-engine-contract.test.ts.
- live: test/live/diffusion.test.ts and the new diffusion-install.test.ts
(a manifest install: pick, download, sha256, unpack, probe; a tampered
sha256 refused; --version) on linux-x64, linux-arm64 and macos-arm64
(macos-26: the archive's minos is 26.0), CPU archives, with FLUX.2 Klein
4B Q4_K_M + Qwen3-4B-Instruct-2507 Q4_K_M + the FLUX.2 VAE (conf's catalog
files, 5.4 GB, pinned by revision and sha256) in a cache entry of their
own keyed by their hashes. SD-Turbo cannot be used: core passes
--diffusion-model, and sd.cpp then fails to read the checkpoint's version.
live_env fills the test env from what the fetch leaves (live.json);
required live tests may name platforms.
- workflow: sd-cpp in the engine choice; the core suites run on the
engine's platforms (core_matrix from resolve; the same seven jobs for
llama.cpp); the live timeout comes from the config (90 min for sd.cpp).
The live test's `not.toContain('edit')` now applies to Qwen Image 2.1
without its projector only: FLUX.2 Klein, the default family, edits.
ADR 2026-10-21-check-sdcpp-builds-with-the-engine-candidate.
Checked on macOS arm64: `npm run engine:check -- --engine sd-cpp --tag
master-883-137f740` passes (pin master-883-137f740-a36f1b1a and candidate
5/5 each, surface 0 break), 9 min; `--tag b11734` and `--engine atomic-prism
--tag prism-b10787-73bfe6c` still pass; lint, typecheck, format, coverage,
build, contract:bun. e2e: 212 pass, one fails only because the desktop app
listens on :1337 here (owner.test.ts expects no Local API Server).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rators liveModelPath joins with node:path, so on Windows the path the fetch writes has backslashes; the test expected a POSIX string and failed on both Windows runners. The expected path is now joined the same way, still compared whole. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The engine update pipeline (atomic-hatchet-pipeline) now updates stable-diffusion.cpp, the image engine (
sd-cpp). It reads onlyresults.jsonfromengine-candidate.yml, and needs it for two runs:master-<N>-<sha7>fromAtomicBot-ai/stable-diffusion.cpp,core_ref=main);master-<N>-<sha7>-a<rev>inAtomicBot-ai/atomic-chat-conf), on a core release, with the workflow started from that release's ref.Until now
engine-candidatechecked llama.cpp builds only.What changes
.github/engine-candidate/sd-cpp.json(kind: sdcpp) holds what differs, read by the same scripts:b<N>,prism-b<N>-<sha7>master-<N>-<sha7>(-a<rev>), asSDCPP_TAG_REmirror-sdcpp.ymlrequires + the CPU archive of each live platform, each up once with its digest; on conf also a manifest (staging, or the live one when it names the tag) that names the tag, downloads from conf and pins the release's sizes and sha256candidate.commitgit ls-remote);results.jsonaddscandidate.upstream_tag,atomic_rev,manifestbackends/sdcpp-manifest.jsontag_name(resolveSdcppPins↔parseSdcppManifest+sdcppHostChoice), archives from conf (pin_repo)test/fixtures/sdcpp/engine-contract.json, hand-written and held tosrc/diffusionandsrc/engine-buildsbytest/contract/sdcpp-engine-contract.test.tsscripts/lib/engine-surface.mjsscripts/lib/sdcpp-surface.mjs, the same report schema:sd-server --helpby whole aliases (--vae-formatnever counts as--vae),--versionnaming the tag's commit, the install probe's markers insd-cli --help, archives by backend, leejet's history between the two tagstest/live/diffusion.test.ts+ newtest/live/diffusion-install.test.ts(install through a manifest: pick, download, sha256, unpack, probe; a tampered sha256 refused;--version)macos-26: the archive'sminosis 26.0), CPU archives onlyLive models: FLUX.2 Klein 4B Q4_K_M, Qwen3-4B-Instruct-2507 Q4_K_M as
--llmand the FLUX.2 VAE, the files conf's diffusion catalog ships (5.4 GB, pinned by Hugging Face revision and sha256). They go into a cache entry of their own, keyed by their hashes, on a path Linux and macOS share, so one copy fits the 10 GB cache. SD-Turbo, the fork's smoke model, cannot be used: core passes--diffusion-model, and sd.cpp then cannot read the checkpoint's version (get sd version from file failed, checked on master-883).Core change:
ATOMIC_DIFFUSION_BACKEND=cpustarts every diffusion load with--backend cpu(a separate commit). The live run sets it throughATOMIC_LIVE_SD_BACKEND=cpu, because a macOS runner's paravirtual GPU crashes ggml's Metal kernels. Nothing else reads it.Workflow:
sd-cppin theenginechoice.core_matrixfrom resolve,core_runnerwhere it differs). For llama.cpp this is the same seven jobs as before; the pipeline keepssuites=all.live_timeout_minutes: 90 for sd.cpp, GitHub's 360 otherwise).live_models.Smaller changes:
live_envfills the live test env from what the fetch leaves (live.json); required live tests may nameplatforms; invocations may name abin; the upstream git cache is one folder per upstream repo. The live test'snot.toContain('edit')now applies to Qwen Image 2.1 without its projector only (FLUX.2 Klein, the default family, edits).Docs: ADR
2026-10-21-check-sdcpp-builds-with-the-engine-candidate,docs/live-tests.md("stable-diffusion.cpp builds"),test/live/README.md,docs/testing-critical-flows.md.Checked (macOS arm64)
npm run engine:check -- --engine sd-cpp --tag master-883-137f740→ PASS in 9 min:master-883-137f740-a36f1b1a5/5 and candidate 5/5 (the video block is skipped without a video model);-Mis sd-cli's only; core still emits the deprecated--qwen2vl,--clip-on-cpu,--vae-on-cpu).results.jsonvalidates against the pipeline worker'sCandidateResults.resolveon conf's mirror (repo=AtomicBot-ai/atomic-chat-conf tag=master-883-137f740-a36f1b1a) → complete, pin the same tag.--tag b11734and--engine atomic-prism --tag prism-b10787-73bfe6c→ PASS.test:coverage(floor ok), build,build:bin,test:contract:bun.test:e2e: 212 pass. One fails only on this machine: the desktop app listens on :1337, andowner.test.tsexpects no Local API Server.master-975-95b3090is not checked: neither the fork nor conf has that release yet.Not covered
not_verified).minos 26.0, so sd.cpp does not run on macOS 14/15; leejet does not print thegenerating video:line the tracker waits for (reported as text in neither tree).After merge
A core release is needed: the pipeline re-checks conf's mirror on a core release, from that release's ref, and holds an sd.cpp rollout until a release contains
.github/engine-candidate/sd-cpp.json.🤖 Generated with Claude Code