Conversation
Adds a dispatch-only workflow that builds opencv-contrib-python, blake3 and tiktoken on the windows-11-arm runner and attaches them, with a flat index page, to a GitHub release for pyproject's Windows ARM64 sources to consume. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NiaFTnYH9q9468Naf4PV3X
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NiaFTnYH9q9468Naf4PV3X
Windows ARM64 has no wheels for mediapipe's legacy solutions API, numba or passlib-compatible bcrypt. Face nodes import lazily and name the platform when used, the image map falls back to a PCA projection without umap-learn, password hashing calls bcrypt directly, bitsandbytes guards survive a build whose native library fails to load, and startup logs the torch build. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NiaFTnYH9q9468Naf4PV3X
check_aarch64_lock.py becomes check_platform_locks.py: the aarch64 check is unchanged, and win32/ARM64 additionally requires torch from NVIDIA's index and a win_arm64 wheel for every package in the closure. python-tests gains a 3.12-only windows-11-arm lane. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NiaFTnYH9q9468Naf4PV3X
pyproject forks the packages whose Windows ARM64 wheels start at newer versions, routes torch to NVIDIA's out-of-tree index and OpenCV, blake3 and tiktoken to the release-hosted wheel page on that platform, and enforces ARM64 wheel availability with uv's required-environments. Docs cover the native ARM64 Python request, the install options and the feature differences. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NiaFTnYH9q9468Naf4PV3X
MSVC has no __fp16 type, which the DNN Winograd kernel uses once NEON_FP16 is in the CPU baseline; pin the baseline to NEON with DOTPROD dispatch. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NiaFTnYH9q9468Naf4PV3X
Adds the win32/ARM64 resolution: torch 2.14.0+cu134 from NVIDIA's index, the release-hosted opencv/blake3/tiktoken wheels, and the ARM64-capable versions of numpy, onnx, onnxruntime, sentencepiece, bitsandbytes, cryptography and PyWavelets. Other platforms change only by bcrypt 5.0.0 replacing passlib. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NiaFTnYH9q9468Naf4PV3X
Skip the woff2 font test where brotli is absent, name the platform in the MediaPipe error only on Windows ARM64, cover transitive/extra/sdist paths in the lock checker tests, and correct the platform docs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NiaFTnYH9q9468Naf4PV3X
Pull-request runs of the wheel workflow only build and verify; publishing is dispatch-only under a concurrency group, and tags are treated as immutable because the lockfile pins the assets by hash. The closure walk now follows a package's extras even after a plain edge reached it, the ARM64 test lane skips uv's cache, and the umap fallback is a cached loader. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NiaFTnYH9q9468Naf4PV3X
The windows-arm64 lane imports the self-built wheels explicitly (tiktoken is never imported by the suite), and the platform lock checker walks the test extra the lane installs and reports edges the lock cannot resolve. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NiaFTnYH9q9468Naf4PV3X
NVIDIA's ARM64 torch dies with an access violation in torch.cuda.is_current_stream_capturing() when no CUDA device is present, which transformers calls on every forward pass. Answer False there, at app startup and in the test session. Also split the SDPA pass-through test: torch 2.14 rejects an explicit mask together with is_causal=True. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NiaFTnYH9q9468Naf4PV3X
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NiaFTnYH9q9468Naf4PV3X
lstein
marked this pull request as ready for review
September 15, 2026 04:33
lstein
requested review from
JPPhoto,
Pfannkuchensack and
blessedcoolant
as code owners
September 15, 2026 04:33
Collaborator
Author
|
Installation and testing instructions: https://claude.ai/artifact/WP7PPdt7EutshYHLi92uKj |
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.
Summary
Invoke could not be installed on Windows on ARM64 (NVIDIA's RTX Spark developer preview): every marker treated
win32as x64, the lockfile carried onlywin_amd64wheels, and several dependencies have no ARM64 build at the pinned versions. With this PR,uv sync --frozenanduv pip installon a native ARM64 Python 3.12 produce a working install with NVIDIA's torch 2.14.0+cu134 (fromhttps://pypi.nvidia.com/nvtorch_oot/), CI proves it on GitHub'swindows-11-armrunners, and every other platform resolves exactly as before apart from one deliberate change (bcrypt 5 replaces passlib).How it fits together:
pyproject.tomlforks the packages whose ARM64 wheels start at newer versions (numpy2.3,onnx1.18,onnxruntime1.24,sentencepiece0.2.2,bitsandbytes0.50.1,cryptography46.0.x,PyWavelets1.10) behindsys_platform == 'win32' and platform_machine == 'ARM64', routes torch/torchvision to NVIDIA's index there for every extra, and sets uv'srequired-environmentsso a wheel-only package without an ARM64 wheel fails at lock time.windows-11-armand publishes them, with a flatindex.html, as assets of releasewin-arm64-wheels-v1; pyproject consumes that page as a flat index and pins the exact versions so the manual--find-linkspath prefers the wheels over PyPI's sdists. Pull-request runs of that workflow only build and verify; tags are immutable in practice because the lockfile pins the assets by hash.scripts/check_aarch64_lock.pybecomesscripts/check_platform_locks.py: the aarch64 check is unchanged, and win32/ARM64 additionally requires torch from NVIDIA's registry and walks the whole dependency closure forwin_arm64wheels (uv'srequired-environmentscannot see packages that also publish an sdist).solutionsAPI on ARM64) and umap/numba (no wheel for 3.12) are excluded there; the face nodes import mediapipe lazily and name the platform when it is the cause, the image map falls back to a PCA projection, password hashing calls bcrypt directly (passlib 1.7 cannot use bcrypt >= 4.1, the first release with ARM64 wheels), the bitsandbytes guards survive a build whose native library fails to load, and startup logs the torch build and host architecture. One shim is specific to NVIDIA's build: without a CUDA device it dies with an access violation intorch.cuda.is_current_stream_capturing(), which transformers calls on every forward pass, so on such a machine the app (and the test session) make it answer False.cpython-3.12-windows-aarch64-none), the install options, and the platform's feature differences.The launcher needs a companion change (arch detection, aarch64 uv, native Python request, arm64 package build); it is prepared but not part of this PR.
pins.jsonneeds no change: the launcher's bootstrap path installs from the release's own lockfile.Related Issues / Discussions
NVIDIA RTX Spark Developer Preview: https://forums.developer.nvidia.com/t/rtx-spark-developer-preview/377106
QA Instructions
Local (Linux, worktree venv):
uv lockthenuv lock --locked: resolved; the diff vs main is the ARM64 forks plus bcrypt 3.2.2 → 5.0.0 and passlib removed (verified by parsing both locks: no other package's version or wheel list changed).uv run --no-project --with 'packaging<26' --python 3.12 scripts/check_platform_locks.py uv.lock→linux/aarch64 OK,win32/ARM64 OK(115 packages in each ARM64 universe, none without a wheel).python3 scripts/check_pins.py→ consistent.pytest tests/app/services/auth tests/app/services/image_index tests/app/routers/test_utilities.py tests/backend/image_util tests/test_imports.py tests/test_check_platform_locks.py tests/test_check_pins.py→ pass.pytest -n logical): 8250 passed; 13 failures are the same GPU tests that fail identically on an untouchedmaincheckout because both GPUs on this machine were at 99%/82% use (HIP out-of-memory intest_flux2_working_memory,test_model_cache_*,test_pid_chunked_equivalence), plus the repo-lock check that passes since the lock was regenerated.ruff check/ruff format --checkclean;pnpm -C docs build→ 326 pages, no new warnings.GitHub:
build-win-arm64-wheels: OpenCV, blake3 and tiktoken built and smoke-imported onwindows-11-arm; releasewin-arm64-wheels-v1carries the three wheels andindex.html; the publish job'suv pip compile --find-links <page>verification passed. (First OpenCV attempt failed: MSVC has no__fp16, which the DNN Winograd kernel uses onceNEON_FP16is in the CPU baseline; fixed by pinning the baseline to NEON + DOTPROD dispatch.)py3.12: windows-arm64lane installs from the lock on a native ARM64 interpreter (platform.machine() == "ARM64"asserted), imports the self-built wheels, and runs the full suite: 7,993 passed, 177 skipped, 9 xfailed in 13 minutes (the lane takes 18 minutes end to end without uv's cache). Its earlier runs surfaced four ARM64-only failures, all fixed: the stream-capture crash above (which had taken an xdist worker down and left ~2,500 tests unrun), torch 2.14 rejecting an SDPA test's explicit mask combined withis_causal=True, a frame fixture that overfloweduint8(numpy 2 no longer wraps), and a MediaPipe gate test that assumed a non-ARM64 host.Not verified (no hardware): CUDA generation on sm_121, cuDNN SDPA priority on this torch build,
cudaMallocAsyncacceptance inconfigure_torch_cuda_allocator(), bitsandbytes 0.50.2's CUDA kernels, VRAM accounting on unified memory. The docs mark the platform as a developer preview.Review
Four independent read-only reviews on the pushed diff (adversarial fresh-context; correctness/spec; architecture/operational safety/performance; tests/docs/product). Material findings resolved: the wheel workflow's pull-request trigger could republish non-reproducible wheels over the assets the lock pins by hash (an in-flight run was cancelled, publishing is now dispatch-only under a concurrency group, and wheels are verified before upload); a remaining top-level
import mediapipewould have failedtest_importson ARM64; the woff2 font test needs brotli, absent on ARM64; the checker's closure walk skipped a package's extras once a plain edge had reached it (fixed, with a fixture that fails against the old walk); the MediaPipe error attributed every import failure to the platform; the admin guide still generated password hashes with passlib; bitsandbytes guards catch(ImportError, OSError, RuntimeError)rather than everything; the ARM64 test lane no longer caches uv's store; docs wording for patchmatch, woff2 and launcher support corrected. Final blocker-only review of the candidate: no blockers, every earlier resolution confirmed at its head, and a 400-universe old-vs-new lock comparison across the non-ARM64 platforms showing no change beyond bcrypt/passlib. The three CI-driven commits after it (the stream-capture shim and three test fixes) had a separate blocker-only review.Compatibility / Rollout
$2b$12$hashes passlib produced (covered by a regression test), and new hashes use the same cost factor.pyproject.tomltogether, then re-locking; never overwrite a tag that a tagged Invoke release's lock names.Checklist
What's Newcopy (if doing a release after this PR)🤖 Generated with Claude Code
https://claude.ai/code/session_01NiaFTnYH9q9468Naf4PV3X