Skip to content

refactor(analysis): use_jax/PYAUTO_DISABLE_JAX handled inconsistently across af/ag/al #1372

Description

@Jammy2211

The bug

autofit/non_linear/analysis/analysis.py:67-69:

import os
if os.environ.get("PYAUTO_DISABLE_JAX") == "1":
    use_jax = False

A caller that explicitly passed use_jax=True is silently downgraded to the NumPy path — no warning, no record. Three lines below, the other way use_jax=True can fail to hold (JAX not installed) warns loudly in a formatted box. The env-var override is the only silent one.

Why it matters — it manufactures vacuous tests

PYAUTO_DISABLE_JAX is consumed in exactly one place (this constructor — confirmed by grep across PyAutoConf/PyAutoFit/PyAutoArray). So every workspace script that builds an Analysis(..., use_jax=True) to assert JAX behaviour instead validates the NumPy path, while presenting as a JAX test, and passes.

Observed, not theorised: autofit_workspace_test's searches/Dynesty_jax.py and Nautilus_jax.py were doing exactly this under the mode=release profile (PYAUTO_DISABLE_JAX: "1") and passing vacuously for as long as they have existed. They were only caught because a sibling, MultiStartAdam, happens to carry its own hard backend guard (multi_start_gradient/search.py:120-126) and so failed loudly instead — taking nightly-release red for five nights (autofit_workspace_test#44 / PR #45).

That is the pattern: scripts with a guard fail loudly; scripts without pass vacuously and nobody learns. This silent flip is the root cause of the class.

Plan (high level)

  • When the caller explicitly passed use_jax=True and the env var overrides it, say so loudly instead of silently downgrading.
  • Mirror the existing JAX-not-installed warning box directly below, so the two failure modes look alike.
  • Warn once per process, not once per Analysis.
  • No workspace changes here — the scripts this surfaces are a follow-up.

Plan (detailed)

In Analysis.__init__, inside the existing env-var branch: if use_jax is truthy (the parameter defaults to False, so truthiness already means "explicitly requested"), emit a loud warnings.warn mirroring the box below, then downgrade as today. Guard with a module-level flag so one process warns once.

Warn, do not raise. PYAUTO_DISABLE_JAX=1 is legitimate and deliberate — the smoke env profile uses it to run every script fast on NumPy. Raising would break every smoke run of every use_jax=True script. The warning is accurate there rather than noise: it says "this script's JAX assertions are vacuous right now", which is exactly true.

Testing

Unit tests in test_autofit/, NumPy-only (library unit tests never import JAX — and need not here: the warning fires inside the env-var branch, before the JAX-install check):

  • use_jax=True + PYAUTO_DISABLE_JAX=1 → warns; _use_jax is False
  • use_jax=True + env unset → no warning
  • use_jax=False + PYAUTO_DISABLE_JAX=1no warning (nothing was overridden)
  • two analyses in one process → exactly one warning

Why not the alternatives (considered, rejected 2026-07-15)

  • Promote MultiStartAdam into smoke_tests.txt (the question that started this): it would not have caught the bug. run_smoke.py hardcodes ENV_VARS_FILE = config/build/env_vars.yaml, so the per-PR gate never reads the release profile, which is where the missing override lived. It also cuts against "smoke tests are a small curated subset".
  • A static per-repo config guard ("every script declaring use_jax=True must resolve DISABLE_JAX=0 in env_vars_release.yaml"): the naive string-matching rule false-positivesautolens_workspace_test/scripts/imaging/simulator_use_jax_parity.py contains use_jax=True but constructs al.SimulatorImaging, which does not read the env var, so its parity assertion is perfectly valid. The correct rule ("constructs an Analysis with use_jax=True") is brittle to detect statically across subclasses. One library change covers all three workspaces and every future script, with no per-repo config.

Blast radius (measured, not estimated)

Resolved autobuild.env_config.build_env_for_script over each release profile, for every script containing use_jax=True:

repo declares use_jax=True JAX actually ON resolves to JAX OFF
autofit_workspace_test 7 6 1
autolens_workspace_test 54 50 4
autogalaxy_workspace_test 36 34 2

The 7 JAX-OFF scripts are what this warning will surface under mode=release. ~2 are false positives (the simulator_use_jax_parity.py pair — SimulatorImaging, unaffected). The rest are genuine and want triage as a follow-up:

  • autofit_workspace_test/scripts/features/latent_nan_robustness.py
  • autolens_workspace_test/scripts/imaging/visualization.py
  • autolens_workspace_test/scripts/latent/latent_nan_robustness.py
  • autogalaxy_workspace_test/scripts/imaging/visualization.py
  • autogalaxy_workspace_test/scripts/latent/latent_nan_robustness.py

latent_nan_robustness.py deliberately builds both a NumPy and a JAX analysis, so only its JAX half is vacuous — triage it, do not blindly override it.


Prompt: PyAutoMind/active/analysis_silently_swallows_use_jax_override.md
Branch: feature/analysis-loud-use-jax-override
Autonomy: supervised (bug cap) — plan recorded here per the autonomy contract; ship sign-off and merge stay human.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions