Repository navigation
CI: a nightly job tests each runtime's newest upstream release and records the result - #13
Open
IsuraManchanayake wants to merge 12 commits into
Open
IsuraManchanayake wants to merge 12 commits into
IsuraManchanayake wants to merge 12 commits into
Conversation
…cords the result Each adapter installs on its own only the upstream versions it was built and tested against, so those lists go stale as llama.cpp and MLX release. The job picks the newest upstream release the recipe does not list (scripts/nightly_runtimes.py), installs it untested, and runs the adapter's tests on it: llama.cpp on macos-14 and ubuntu-24.04 with a small GGUF for the model tests, MLX on macos-14 with the worker built as a release ships it. A llama.cpp build that passes arrives as a PR adding it to the recipe with the size and SHA-256 GitHub lists for each of its assets, the same asset names the previous tested build carries; one that fails opens an issue with the run attached. An MLX version is pinned by hand, wheel by wheel, so its result is an issue either way. workflow_dispatch tests a named release instead of the newest.
…Python recipe::install leaves two site-packages: the bundled interpreter's under python/ and the environment's under env/, where mlx and mlx-lm went. The job took the first find found, which can be the bare interpreter's, and built its test executables against whatever Python PyO3 picked on the runner. Now SUPERFLUID_MLX_VENV names env/, checked by importing mlx and mlx-lm from it, and PYO3_PYTHON names the install's Python 3.12.
An MLX version that passes the adapter's tests arrives the same way a llama.cpp build does: as a PR adding it to the adapter's recipe, built from pip's report of the environment it resolved on the runner, every wheel with the size and SHA-256 PyPI lists for it. The issue stays for a version that fails, which includes one needing a newer Python than the adapter ships.
A dry-run resolution made after the install could name other versions or wheels than the environment installed moments before, and the recipe would pin those as tested. The report now comes from a real install into the test environment, which the tests then run on.
This was referenced Oct 15, 2026
- A listing that fails (issues disabled, no permission) was read as an open issue and the run recorded nothing: every listing check now stops with a clear error. - The MLX test executable, built against the install's Python, links @rpath/libpython with no rpath into the install: the install's lib directory is named for dyld. - Hosted runners share GitHub's unauthenticated API rate limit, and the worker's plan of an untested build hit it: the kit sends GITHUB_TOKEN for api.github.com when set, and the plan step has the job's token. - A runtime has one open issue; a later build that fails too is noted on it instead of opening one a day. Seen on the fork: https://github.com/IsuraManchanayake/superfluid/actions/runs/38715098729
…e adapter runs on pip on a runner or machine newer than macOS 14 resolves the mlx and mlx-metal wheels built for its own macOS, which an older Mac cannot install. The recording script now pins, for a wheel with a macOS tag, the same wheel built for the oldest macOS at or above 14 that PyPI offers, with the size and digest PyPI lists for it.
2 of 3 tasks
The hosted macos-14 runner's GPU is virtualized: llama.cpp takes its fallback Metal kernels there, a 40-token prompt costs seconds, a padded batch answers a zero logit row, and a batched round differs from solo decode past the tests' bound, whatever the build; and with 2 GB free the adapter keeps one shared pool where the tests expect a buffer per lane. The leg now asks for a self-hosted Apple silicon runner and keeps the toolchain that runner has.
The runner's PATH is its owner's shell's at start, which need not name ~/.cargo/bin; the first run on a Mac died in fifteen seconds on 'cargo: command not found'.
…stup Swatinem/rust-cache's save step removes every regular file in ~/.cargo/bin that cargo did not install during the job: on a hosted runner that is nothing of value, on a developer's Mac it was rustup itself. A self-hosted runner keeps its work directory between jobs and needs no cache.
…e file Its key is the workflow file's hash, so every edit to the workflow missed the cache and the post step uploaded the model from the runner: on a laptop, minutes at a megabyte a second.
This branch has not been deployed
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.
What changed
A scheduled workflow installs the newest upstream llama.cpp build and MLX version untested, through each adapter's own
plan --untestedandinstall, and runs the adapter's tests on it: llama.cpp on macos-14 and ubuntu-24.04 with a small GGUF, MLX on macos-14 in the install's own environment and against its own Python. A release that passes arrives as a PR adding it to the adapter's recipe (scripts/nightly_runtimes.py <runtime> append): for llama.cpp with the size and SHA-256 GitHub lists for each asset, for MLX with the environment pip installed for the tests, every wheel with the size and SHA-256 PyPI lists for it, read from a realpip install --report. One that fails opens an issue with the run attached.workflow_dispatchtests a named release.A schedule fires only from the default branch, so the job needs merging to
mainand the Actions setting that lets workflows open pull requests.The llama.cpp macOS leg runs on a self-hosted Apple silicon runner (
[self-hosted, macOS, ARM64]), not the hosted macos-14. On a self-hosted runner the job keeps the machine's toolchain (rustup's bin directory on the job's PATH, the toolchain action skipped), runs no rust-cache and uses no model cache, since the machine keeps its work directory and the model between jobs.Why
The tested lists in the recipes are what
superfluid compatdeclares and what a release installs on its own; without a job they fall behind upstream, and a human types digests. See the new section "How an upstream release becomes a tested one" in docs/models/runtimes.md.The hosted macos-14 runner cannot pass the adapter's real-model tests on any build: its virtualized GPU takes llama.cpp's fallback Metal kernels, where a batched round differs from solo decode past the tests' bound and a padded batch answers a zero logit row, and its 7 GB leaves the adapter one shared pool where the tests expect a buffer per lane. The failures were bit-identical across runs (https://github.com/IsuraManchanayake/superfluid/actions/runs/38725440780, https://github.com/IsuraManchanayake/superfluid/actions/runs/38739018175); the same suite passes on real Apple silicon, which is what a tested build has to mean for a Mac. rust-cache stays on hosted runners because its save step deletes every regular file in
~/.cargo/binthat cargo did not install during the job, rustup included on a developer's Mac (https://github.com/IsuraManchanayake/superfluid/actions/runs/38744781241/job/116457149024); the model cache too, since its key is the workflow file's hash and every edit re-uploaded 386 MB from the runner.How it was tested
pickandappendrun locally against GitHub and PyPI: b11630 and 0.32.4 picked; a llama.cpp entry appended with 15 of 16 assets; an MLX entry rebuilt from a pip report of the recipe's own 0.32.2 environment reproduces the recipe byte for byte; a digest PyPI does not list, a report that resolved another mlx, a missing report and an already tested version are refused with the recipe untouched.runblock passesbash -n.main, five dispatches. The first three found a listing failure read as "already open", the MLX test binary's missing libpython rpath and GitHub's unauthenticated rate limit on hosted runners, all fixed here. It then found llama.cpp b11642's new context-parameter layout (Llamacpp: the b11642 layout of llama_context_params beside the older one, and exports in host memory on a CPU-only host #17) and MLX 0.32's cache API (Mlx: the shim drives mlx-lm 0.32's caches, whose state carries everything, beside 0.31's #18), both real. With a MacBook Pro as the self-hosted runner it recorded b11658 end to end: https://github.com/IsuraManchanayake/superfluid/actions/runs/38751331332 opened llamacpp: tested with b11658 IsuraManchanayake/superfluid#15 with the entry.Reviewed in the fork as IsuraManchanayake#4, #5 and #14.
cargo clippy --all-targets -- -D warningscargo test