Testing#

GeoJAX uses deterministic numerical tests, executable documentation, and clean package installation checks. A release should pass the complete matrix rather than only the maintainer’s active Python environment.

Current environment#

Check style and run both JAX precision modes before committing:

make quality
make test
make test-float32

Both commands execute the full test suite with branch coverage. Coverage below 85 percent fails the run. GEOJAX_TEST_X64 is set by these targets so tests do not silently inherit a developer’s JAX configuration.

Invariant assertions keep their original strict float64 tolerances. In float32, tests add a small dtype-aware allowance for decomposition roundoff and avoid perturbations below machine resolution. This preserves the mathematical assertion instead of expecting float32 arithmetic to reproduce a float64 residual.

Numerical stability#

Every public geometry is exercised with unbatched, nested-batch, and broadcast-base inputs. The stability suite differentiates exponential maps at zero tangents, logarithms and squared distances at coincident points, and SPD matrix functions at repeated eigenvalues. Directional finite differences independently check representative JVPs away from cut loci.

Contract tests additionally project zero, noisy, indefinite, and rank-deficient ambient inputs and require the repaired value to pass membership. Malformed event dimensions must fail before an operation can silently run on a different manifold. Float32 tests explicitly check open-ball margins and the active spectral floors used by SPD and fixed-rank repairs.

Second-order tests verify known Riemannian Hessian identities, including the sphere shape-operator term, and require unsupported automatic conversions to fail with an explicit request for rhess_vec.

Genuine singularities have separate regression tests. In particular, a spherical antipode retains a finite distance but an explicitly nonfinite logarithm and transport.

The learning release contract compiles complete deterministic-autoencoder steps with spherical and hyperbolic latents. It requires decreasing reconstruction loss, finite encoder gradients, and valid manifold points after training. Learning-helper tests also combine vector-valued interpolation times with batched endpoints and reject proxy distances or logarithms where the public helper promises an exact geodesic operation.

The release suite enforces two branch-aware coverage thresholds: at least 85% repository-wide and at least 95% for geojax.learning. Both reports come from the same complete run, so adapter failures, statistical edge cases, and optional-integration boundaries remain part of the release contract.

Supported matrix#

Install the development dependencies and run:

python -m pip install -e ".[dev]"
make test-matrix

The first run downloads managed CPython interpreters through tox-uv. Subsequent runs reuse those interpreters and isolated tox environments. Tox uses managed interpreters even when a matching conda or system Python happens to be active, making the matrix independent of a developer’s base environment. Missing versions are errors; they are never silently skipped. The supported minor versions also live in .python-versions, so uv python install can prepare all of them directly.

Each tox environment builds a wheel, changes to an isolated temporary working directory, clears pytest’s source-tree pythonpath, and asserts that import geojax resolves inside that environment. The matrix therefore tests the installed artifact rather than accidentally importing the checkout. Installed module contents must also match the source exactly.

The runner starts a fresh process for each test file, so JAX compilation caches cannot accumulate across the complete suite. It records the collected tests, execution results, timings, and source hashes, then combines coverage before enforcing the global and learning thresholds. Every test file is required; an unexplained empty collection, incomplete run, failure, or timeout fails the environment. Each file has a 600-second wall limit enforced by its parent process. A timed-out worker receives a stack-snapshot request before termination. Background traceback timers are disabled: a CPython watchdog was observed blocking pytest after a completed test. Reports are retained in timestamped subdirectories under .tox/verification/<environment>/.

For a faster laptop run with bounded and coverage-safe concurrency:

make test-matrix-parallel

The default is two workers. Override it only when the machine has enough CPU and memory, for example make test-matrix-parallel TOX_PARALLEL=3.

The release-blocking matrix is pinned and covers:

Python

Dependencies

JAX precision

3.11

JAX 0.6.0 and NumPy 1.26.4

float32, float64

3.11

JAX 0.10.2 and NumPy 2.4.4

float32, float64

3.12

JAX 0.11.0 and NumPy 2.4.4

float32, float64

3.13

JAX 0.11.0 and NumPy 2.4.4

float32, float64

3.14

JAX 0.11.0 and NumPy 2.4.4

float32, float64

The lower-bound environments guard the oldest runtime versions promised by pyproject.toml. Stable environments pin JAX, JAXlib, NumPy, SciPy, ml-dtypes, opt-einsum, pytest, and coverage tooling, preventing a new upstream release from changing an otherwise identical release check. Update these pins deliberately, then run the complete matrix before merging the change. Coverage data is stored separately for every environment and run, so sequential and modestly parallel runs have the same isolation guarantees.

GitHub CI runs all ten pinned combinations above with the same complete-suite runner and uploads the reports even when a job fails. It also runs quality checks, rebuilds the documentation, and installs both generated package formats outside the checkout.

Completed correctness audit#

The 25 September 2026 audit of commit b7361be passed all ten complete installed-wheel environments: 11,465 test executions passed, with 15 expected skips. Branch-aware coverage exceeded the 85% global and 95% learning thresholds in every environment. A separate 140-test supplement passed with JAX 0.11.2 and the real optional OTT backend, with no skips.

Independent mathematical and statistical cross-checks passed, and all 25 documentation notebooks and 97 code cells executed successfully. This validation used macOS ARM64 CPU; GPU and TPU execution remain untested. The complete audit report records the corrections, reproducible evidence, and remaining numerical and statistical limitations.

Documentation#

make website

This executes every MyST Markdown tutorial from a clean Sphinx environment, treats Sphinx warnings and execution errors as build failures, and audits rendered mathematics and local references. jupyter_execute/ and .jupyter_cache/ are transient: the build deletes both after the HTML audit succeeds. The .md tutorial is always the maintained source.

Release candidate#

make release-check

The release target requires the complete tox matrix, rebuilds every tutorial, creates clean wheel and source archives, applies Twine’s strict metadata validation, and installs both artifacts from a temporary directory. It first requires a clean commit carrying the annotated version tag, then checks the source again after documentation generation and before packaging. Tutorial execution can regenerate tracked figures, so those changes must be reviewed and committed before tagging the release. The target prints the SHA-256 digest of each artifact. It does not upload or publish anything.