Uh oh!
There was an error while loading. Please reload this page.
feat(container): lean pixi-based two-stage container with multi-arch support - #466
Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
lmoresi
left a comment
There was a problem hiding this comment.
Adversarial review
The two-stage structure itself held up under attack (see the cleared list), but three findings block merge:
- CRITICAL —
import gmshis broken on linux-aarch64, the PR's headline platform. Conda-forgegmsh-4.15.2ships the app/library only — no Python module; that lives in the separatepython-gmshpackage, which is absent from the lock. linux-64/osx-arm64 stayed green only because pygmsh drags the pypi gmsh wheel back in; no such wheel exists for linux-aarch64, so the solver silently downgraded pygmsh to 7.1.12 and locked no gmsh Python module at all. The arm64 container cannot build a single mesh. Fix: add condapython-gmsh(the old environment.yaml listed both) and re-solve the lock; verifyimport gmshin the linux-aarch64 env. - MAJOR — no green container build exists for the PR head. The only build attempt ran on f814251 and died at
pixi install -e runtime(aarch64 unsupported); the fix commit 47ffb64 was never build-tested. The workflow has nopull_requesttrigger, so merging is the first real test — and it pushes to theghcr :developmenttag. One demonstrated green build of the actual head (forkworkflow_dispatchis enough) before merge. - MAJOR — no
.dockerignore, andCOPY . .runs afterpixi install -e runtime: the documented localpodman build .uploads the multi-GB host.pixi/andbuild/as context and merges the host's.pixi/envs/*over the freshly installed runtime env — a wrong-arch clobber for anyone who has built natively (as the PR author has). CI is unaffected (clean checkout); local builds are the trap. Exclude.pixi/buildor add a.dockerignore.
Minor: environment.yaml's new header calls itself the runtime reference but still says petsc=3.24 while the lock ships 3.25.3 — wrong on exactly the pin that caused #355; lock churn on development now triggers full dual-arch rebuilds with arm64 under QEMU and no build cache configured; curl pixi.sh/install.sh | sh is unpinned; the runtime image still carries the full compiler toolchain, so "lean" is relative.
Attacks that failed: no pip install -e anywhere (the only -e is pixi's env selector); two-stage copy is path-identical so rpaths and the UW3 .so survive; kernelspec copied; workflow secrets/permissions sane (GITHUB_TOKEN, packages:write, no per-PR trigger); pixi.lock internally consistent (petsc==petsc4py==3.25.3, numpy 2.4.6 < 2.5, python 3.12, identical across envs/platforms); dev-env pixi tasks untouched.
Not run: an actual container build (runtime boot, OSMesa render, QEMU arm64 duration unverified).
Also for the record: #355 is already closed by #356; this PR supersedes #356's mechanism (environment.yaml stops being a build input) but doesn't close anything.
…sc ver Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Brings in 12 upstream commits (solver/physics changes). No conflicts: upstream does not touch container/, pixi.toml, pixi.lock, or .dockerignore. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds cache-from/cache-to (type=gha, mode=max) to the buildx step so repeated linux/arm64 builds under QEMU reuse cached layers instead of re-solving and re-compiling from scratch each time. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
jcgraciosa
commented
Aug 5, 2026
Thanks for the review. All five issues addressed, plus two additional fixes:
Compiler toolchain in the runtime image is acknowledged, deferred to a follow-up PR. Noted on #355/#356 - this PR improves on #356's approach: environment.yaml is no longer a build input (but still useful as human readable record); pixi.lock drives the container instead, eliminating version drift between the container and the Binder environment. Underworld development team with AI support from Claude Code |
lmoresi
left a comment
There was a problem hiding this comment.
Re-verification at head 5392b0b — all five findings CLEARED
| # | Finding | Status |
|---|---|---|
| 1 | CRITICAL: no gmsh Python module on linux-aarch64 | VERIFIED — gmsh + python-gmsh both in [dependencies]; lock re-solved with python-gmsh-4.15.2 in every env × platform incl. runtime/linux-aarch64; zero pypi gmsh wheels remain in the lock, so the papering-over mechanism is gone rather than masked. |
| 2 | MAJOR: no green container build | VERIFIED — fork run 30968087225 at exactly this head: linux/amd64 and linux/arm64 both complete builder 11/11 + runtime 9/9 with manifests exported; the only error is the expected permission_denied pushing upstream ghcr from a fork token. |
| 3 | MAJOR: no .dockerignore | VERIFIED — excludes .pixi/, build/, .git/, docs_legacy/, pycache; Containerfile COPY --exclude as belt-and-braces. |
| 4 | environment.yaml petsc mismatch | VERIFIED — petsc/petsc4py=3.25 + "not a build input" header; lock ships 3.25.3 across platforms. |
| 5 | unpinned pixi install | VERIFIED — PIXI_VERSION=0.63.2. |
Extras sane: the GHA build cache (type=gha,mode=max + actions: write) also answers our lock-churn/QEMU-rebuild complaint; workflow triggers correctly re-keyed to pixi.toml/pixi.lock. The merge of development is clean — the diff vs development touches exactly six packaging files, no src/ or tests/. test_uw3 red at head was the known #461 MANA-NIC flake (it fired twice, logged on the issue); the re-run at this head is green.
For the record, non-blocking residuals: pygmsh resolves 7.1.12 on linux-aarch64 vs 7.1.17 elsewhere (harmless — nothing in src/ imports pygmsh); no import gmsh smoke ran inside the built arm64 image (mechanism matches the old working micromamba container); linux-64 default/dev envs grow ~110 packages from conda gmsh's dep tree (inherent to the aarch64-correct fix).
Underworld development team with AI support from Claude Code
Some Azure runners advertise an InfiniBand verbs device (mana_0) that UCX cannot open; MPI_Init aborts inside the import smoke test before any underworld3 code runs. Four hits in a week across #466/#526/#527 (issues #461/#528), each fixed by re-rolling the runner lottery. A single-node CI runner needs only shared memory and TCP, so pin the transports at the workflow level - it covers the smoke test and every pytest batch alike. Underworld development team with AI support from Claude Code
Uh oh!
There was an error while loading. Please reload this page.
Summary
container/Containerfileto a pixi two-stage build, fixing PETScversion drift between the container and Binder (root cause of the v3.1.0
container build failure)
linux/arm64support for native performance on ARM64 machines(Apple Silicon Macs and ARM64 Linux servers/cloud instances)
gmshfrom PyPI to conda-forge — restores the originalenvironment.yamlapproach and was required to unblock arm64 support(PyPI gmsh has no
linux-aarch64wheels)Details
Containerfile: Two-stage build (builder: pixi install + compile UW3;
runtime: copy env + Mesa apt packages). Drops
vtk-osmesa; uses conda-forgevtk+ Mesa instead — same as Binder, works on amd64 and arm64.pixi.toml/pixi.lock: Added
linux-aarch64platform and target sections.gmshmoved to[dependencies](conda-forge).environment.yaml: Marked as human-readable reference only.
Testing
pixi install -e runtime: linux/arm64 ✓, linux/amd64 ✓, osx-arm64 ✓Underworld development team with AI support from Claude Code