The timestep as a transaction: model.step, a run transcript you can watch and publish, and eight silent defects #1518
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
| name: test_uw3 | |
| # Build + test on every PR / push to main / development. | |
| # | |
| # Uses pixi (with the committed pixi.lock) for a deterministic, fast install | |
| # rather than micromamba + environment.yaml, which had been backtracking for | |
| # 60+ minutes on conda-forge solves and timing the runner out before tests | |
| # could start. The pixi.lock matches what local development uses, so CI now | |
| # runs against the same dependency state developers see. | |
| on: | |
| push: | |
| branches: | |
| - main | |
| - development | |
| - Quick_Start_Docs | |
| pull_request: | |
| workflow_dispatch: | |
| env: | |
| # Some Azure runners carry a MANA NIC whose InfiniBand verbs device UCX | |
| # advertises but cannot open: uct_iface_open(ud_verbs/mana_0) fails inside | |
| # MPI_Init, so `import underworld3` dies before any UW3 code runs (issues | |
| # #461/#528 — four hits in the first week of 2026-08, each costing a manual | |
| # re-roll). A single-node CI runner needs only shared memory and TCP, so pin | |
| # the UCX transports and retire the whole flake class. | |
| UCX_TLS: tcp,sm,self | |
| # Distribute the serial batches across worker processes. This was held back | |
| # until #567 was fixed: worker counts change which files share a process, and | |
| # a units test that switched the units system on at import time then reached | |
| # a module-scoped fixture in the point-locator suite before anything reset it. | |
| # That is fixed at source in tests/conftest.py, and the whole suite is green | |
| # at 4, 8 and 16 workers. | |
| # | |
| # 4 is the vCPU count of the runner. Do NOT try to detect it: the first | |
| # attempt derived the count inside the job, got 1, and ran xdist with a single | |
| # worker — a spawn and a fresh underworld3 import per batch, parallelising | |
| # nothing, for 52m37s. The MPI batches are unaffected either way; they run | |
| # their own mpirun. | |
| WORKERS: 4 | |
| jobs: | |
| test: | |
| runs-on: ubuntu-latest | |
| # The suite has outgrown 60 minutes. Measured 2026-08-15: the SERIAL phase | |
| # alone is ~55 min (three batches at 14-15 min each), so the parallel phase | |
| # - which runs last - was being cut off mid-run and reported as a failure | |
| # that looked like a test failure. Any addition at all pushed a run over. | |
| # This is a stop-gap that unblocks landing work; the durable fix is to split | |
| # the batches across parallel jobs so wall-clock stops tracking total test | |
| # time. See the CI-runtime issue for that. | |
| timeout-minutes: 120 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install pixi from lockfile | |
| uses: prefix-dev/setup-pixi@v0.9.4 | |
| with: | |
| # Use the env that matches local development for tests. | |
| # `dev` = conda-petsc + runtime + dev features (pytest, jupyter, etc.) | |
| environments: dev | |
| # Hard-fail if pixi.lock disagrees with pixi.toml — never re-solve | |
| # silently in CI; that's exactly the failure mode we're escaping. | |
| frozen: true | |
| cache: true | |
| - name: Build UW3 | |
| # `pixi run -e dev build` invokes the build task from pixi.toml, | |
| # which is `pip install . --no-build-isolation` (non-editable — | |
| # editable installs are project policy violation, see CLAUDE.md). | |
| run: pixi run -e dev build | |
| # Import smoke test: a hard crash during `import underworld3` (segfault | |
| # / abort in a compiled module, e.g. from a poisoned env cache) kills | |
| # pytest BEFORE its first stdout flush, so every batch below fails with | |
| # zero output and the run is undiagnosable from the log (this happened | |
| # on PR #394 — a runner-side flake that cost a full debug round-trip). | |
| # This 5-second step makes any import-time crash loud and localised: | |
| # faulthandler prints the native traceback here rather than nothing | |
| # there. | |
| - name: Import smoke test (faulthandler) | |
| run: pixi run -e dev python -u -X faulthandler -c "import faulthandler; faulthandler.enable(); import underworld3; print('import OK', underworld3.__version__)" | |
| - name: Run tests | |
| run: pixi run -e dev ./scripts/test.sh --p 2 |