fix: pin the vision test's LFM2.5 model to an immutable revision - #141
Conversation
Points at bfc2462, which brings two things: - SharpAI/mlx-swift-lm#48 — glm_moe_dsa / deepseek_v3_2 load and run with dense attention (stage 1 of #111). GLM-5.2 is DeepSeek V3.2, whose indexer is inert below index_topk (2048), so output is exact for the first 2048 positions of context and diverges beyond them. That is enough to exercise --stream-experts against the 308GB checkpoint, which is what the issue actually asks for. - SharpAI/mlx-swift-lm#47 — the all-KV-shared assistant regression tests, which had not been picked up by a bump yet. #48 also generalises a latent trap in DeepseekV3.sanitize, which dropped `model.layers.61` by string literal. That number is just numHiddenLayers; on GLM-5.2's 78 layers it would have deleted a real layer while keeping the MTP block. Verified past the registry: pointing the binary at a glm_moe_dsa config constructs the model and fails only on absent weights — Key model.embed_tokens.weight not found in DeepseekV32Model.DeepseekV3ModelInner.Embedding so the architecture is reachable end to end, not merely registered. No real weights have been run: the smallest glm_moe_dsa checkpoint is 308GB. Refs #111 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Dependency Automation has failed all 12 times it has run since 2026-04-27 —
it has never once succeeded. Every failure is the same:
##[error]Input 'token' not supplied. Unable to continue.
The Create Pull Request step reads secrets.SWIFTLM_PR_TOKEN, which is not set
in this repository. The dispatch side is fine: mlx-swift-lm's auto_release
does hold a token that can dispatch cross-repo, so the event arrives and the
job runs, does its work, and dies at the last step.
Rather than add the secret, stop trying to open the PR. A workflow needs a
personal access token to open one usefully because GitHub does not start
workflow runs for events raised by GITHUB_TOKEN — a bot-opened PR would arrive
with no checks at all, permanently pending rather than green, and release.yml
gates releases on CI concluding successfully. A pushed branch plus a compare
link in the job summary costs one click and gets real CI, because the PR event
is then the human's.
Keeping a human in that loop is not a consolation prize. Bumps here have
needed a pointer check, an umbrella build and a smoke test before they were
trustworthy; this does the mechanical part and leaves the judgement.
Three further problems fixed while in here:
- The mlx-swift branch ran `swift package update mlx-swift`, which does
nothing: both dependencies are `.package(path: "./…")` local paths backed by
submodules, and SwiftPM takes whatever is on disk for a path dependency. It
could only ever have produced an empty commit. Both are now handled the same
way, as the pointer move they are.
- client_payload was interpolated straight into run blocks, so a crafted
new_tag would have been executed rather than compared. Values are now
validated (source_repo against an allowlist, new_tag against a plain-tag
pattern) and passed through the environment. Verified rejecting
`b554; rm -rf /`, `$(whoami)`, `b554 && curl evil.sh`, `../../../etc/passwd`,
`-x` and empty, while accepting b554, b459 and v1.2.3.
- A re-dispatch for a tag already checked out produced an empty commit; that
case now reports and stops.
Exercised against the real submodule: an already-current tag (b500) takes the
no-op path, a nonexistent tag (b99999) fails with a clear message, and a real
older tag (b497) computes bfc2462 → b320bc4.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Main went red at 19:28 today with nothing changed on our side — the merge that
preceded it touched only a workflow file. The failing job was
integration_matrix (vision), and it reproduced on re-run, so it was not a flake.
LiquidAI republished LFM2.5-VL-450M-MLX-4bit at 19:23, five minutes earlier.
The new revision's chat template is one brace short of valid:
old: {{- bos_token -}}
new: {- bos_token -}}
Every request against it returns HTTP 500,
`parser('Unexpected token type: closeExpression')`. Confirmed by reproducing
locally against the new revision, then restoring that single brace in a copy —
same weights, same request, HTTP 200 with identical token counts. The fault is
upstream, not a compatibility gap on our side, and no code change here would be
the right response to a malformed template.
CI never noticed the substitution because the vision job did not prefetch this
model at all: the server fetched it mid-test and resolved the floating id to
whatever was newest. So the job's result depended on what a third party
published that afternoon.
Pins the revision, prefetches it, and teaches ci-download-models.sh a
`repo@revision` spec so any model can be pinned the same way. The test resolves
the pinned snapshot on disk and falls back to the floating id with a printed
note, so a local run without a prefetch still works but cannot quietly test a
different revision than CI did.
The test-vision.sh edit rotates the job's model cache key, so CI re-downloads
rather than restoring a cache that now holds the broken revision.
Verified: the vision test passes locally with the pin, both cases; the
`repo@revision` split parses correctly for pinned and unpinned specs; the
fallback path triggers and warns when the pinned snapshot is absent.
Worth reporting upstream — LiquidAI's template is broken for every consumer,
not just this repository.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The first version of the revision-pinning change assembled the optional `--revision` flag into an array and expanded it unconditionally. The runners are macOS, which ships bash 3.2, where expanding an *empty* array under `set -u` is an unbound-variable error rather than expanding to nothing. Every unpinned download therefore failed, which took out every job that prefetches a model — speculative-decoding, dflash, ssd-draft-memory-guard — while the pinned path would have worked fine. Spelled the two calls out instead. Verified by running the script under /bin/bash 3.2 with `set -u` for both shapes: unpinned resolves to the current snapshot, `repo@revision` resolves to the pinned one. CI caught this, which is the system working; worth noting the local `bash -n` syntax check could not have, since the failure is a runtime expansion. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Reported upstream: LiquidAI/LFM2.5-VL-450M-MLX-4bit#1. Status as of now: still unfixed. The repo is on Two things worth recording here that came out of checking upstream after this PR merged: The blast radius is exactly one repo. All 15 LiquidAI MLX repos were edited in a 13-minute window (19:14–19:27) to add the same It is worse for No BOS token, a literal The pin here stays regardless. When the template is fixed, re-pointing |
Main is red, and this fixes it. The release for #140 was correctly skipped by the CI gate, so nothing has shipped from a broken build.
What happened
integration_matrix (vision)failed on main at 19:28 today. The merge that preceded it (#140) touched only a workflow file, and the failure reproduced on re-run — not a flake.LiquidAI republished
LFM2.5-VL-450M-MLX-4bitat 19:23, five minutes earlier. The new revision's chat template is one brace short of valid:Every request against it returns HTTP 500:
How I confirmed it's upstream, not us
10ce3604) → HTTP 200, correct output.f19926fand ran the same request → HTTP 500, the parser error above.{, changed nothing else → HTTP 200, identical token counts (prompt_tokens: 271).Same weights, same request, one brace. The fault is upstream. No code change here is the right response to a malformed template — accepting it silently would mean rendering a literal
{- bos_token -}}into the prompt.Why CI was exposed at all
The vision job never prefetched this model. Only
Qwen2-VLwas inmatrix.models; LFM2.5 was fetched by the server mid-test, resolving the floating id to whatever was newest. The job's result depended on what a third party published that afternoon.The fix
LFM2.5-VL-450M-MLX-4bitto10ce3604…and prefetch it.ci-download-models.sharepo@revisionspec, so any model can be pinned the same way.Editing
test-vision.shalso rotates the job's model cache key, so CI re-downloads rather than restoring a cache that now holds the broken revision.Verification
repo@revisionsplit, pinned + unpinnedci.yml/ shell syntaxFollow-up worth doing separately
Report the template upstream to LiquidAI — it's broken for every consumer of that repo, not just us. I haven't opened anything on a third-party repo; that's the maintainer's call.
Also note the pin means we stop testing the current upstream revision. That's the intended trade: re-point it deliberately when someone means to test something newer, and treat the resulting failure as a real result.
🤖 Generated with Claude Code