fix(config): enable JAX for the JAX-native searches scripts#45
Conversation
The mode=release profile (env_vars_release.yaml) pins PYAUTO_DISABLE_JAX=1 alongside PYAUTO_TEST_MODE=0, so searches scripts really run but on the NumPy backend. MultiStartAdam is JAX-native and hard-raises when the analysis is not JAX-traceable, so it has failed the autofit_test/searches shard — and with it nightly-release Stage 3 — every night since it landed in #43. Add the missing `set: { PYAUTO_DISABLE_JAX: "0" }` overrides, following the searches/BlackJAXNUTS precedent. Dynesty_jax and Nautilus_jax get the same treatment: they declare use_jax=True but were also absent from the overrides, so they were validating the NumPy path while presenting as JAX tests — passing vacuously, since unlike MultiStartAdam they carry no backend guard. Also stop the smoke profile bypassing MultiStartAdam. Its PYAUTO_TEST_MODE=2 skips the sampler before _fit runs, so the script passed without executing its JAX path at all — which is why the per-PR gate could not catch this and it surfaced only in mode=release. Running it costs ~6s. Verified with JAX enabled: MultiStartAdam exit 0 (recovers 50.156/25.196/9.858 vs truth 50/25/10), Dynesty_jax exit 0, Nautilus_jax exit 0, and MultiStartAdam under the smoke-resolved env exit 0. Env resolution driven through autobuild.env_config.build_env_for_script over the real configs for every scripts/searches/*.py: Nautilus.py and DynestyStatic/Dynamic.py correctly stay at DISABLE_JAX=1, confirming the substring patterns do not over-match. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The comment added in 615b229 claimed running MultiStartAdam under this profile lets "the per-PR gate" see it. That is wrong, and the wrong claim would have landed in main. Two different things are called smoke here: 1. The per-PR gate is .github/workflows/smoke_tests.yml, which runs the curated smoke_tests.txt subset. Neither MultiStartAdam nor BlackJAXNUTS is in that list, so this profile never touches it. 2. env_vars.yaml is the `smoke` env profile consumed by PyAutoHeart's workspace-validation.yml at mode=smoke, which runs every script weekly. The override lands on (2). The change is still worth keeping — the weekly sweep now really executes the JAX path instead of bypassing it, so a backend regression is caught within a week rather than at release — but on a weekly cadence, not per-PR. Correct the comment to say so, and record that the BlackJAXNUTS precedent above is likewise about the full-script-set runs. No behaviour change: comment only. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
PYAUTO_DISABLE_JAX is read in exactly one place that matters to this workspace: af.Analysis.__init__, where it forces use_jax=False. Every analysis here is af.ex.Analysis or a local subclass, and af.Analysis defaults to use_jax=False. So the "1" default was a no-op for the ~35 scripts that never opt in - they run numpy either way - and silently sabotaged the ~7 that explicitly pass use_jax=True, which are exactly the scripts written to exercise JAX. It bought no speed and cost correctness. Its only real effect was to require a hand-maintained "remember to add your script" override list. That list is the trap: a JAX-native script that forgets it does not fail loudly, it silently validates numpy and passes. Dynesty_jax and Nautilus_jax did that for as long as they have existed; MultiStartAdam only failed loudly (nightly-release red five nights, #44) because it happens to carry its own backend guard. Pin "0" and delete all five overrides, which become no-ops. This matches the sibling autofit_workspace release profile, which has always pinned "0" for the same release-fidelity reason - this repo was the inconsistent one. PR #45 fixed the symptom by adding the three missing entries; this removes the reason the list exists. Verified rather than asserted: resolved every scripts/**/*.py through autobuild.env_config.build_env_for_script under both profiles (31 change 1->0, 11 unchanged), then confirmed behaviour empirically - features/latent_nan_robustness.py (opts in; JAX half runs for the first time) exit 0, and Nautilus.py / Emcee.py / latent.py / model_composition.py all exit 0 identically under DISABLE_JAX=1 and =0. Closes #46 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fixes #44.
What broke
nightly-releasehas been red five nights running (2026-07-11 → 2026-07-15). Stage 3 dispatches PyAutoHeartworkspace-validation.ymlatmode=release, and exactly one shard fails —run_scripts (3.12, autofit_test, searches):Every other shard in that run is green. This is not the shifting perf-flake tail from the release-tail epic — it is deterministic, and it is fallout from the multi-start gradient search promotion (PyAutoFit #1370, this repo's #43).
Root cause
MultiStartAdam._fithard-guards on the backend:config/build/env_vars_release.yaml— the mode=release profile, notenv_vars.yamlwhich is the per-PR smoke gate — pinsPYAUTO_TEST_MODE: "0"(so_fitreally runs, no bypass) andPYAUTO_DISABLE_JAX: "1"(souse_jax=Trueis silently flipped to False). The guard fires. The profile re-enables JAX for exactly two patterns —jax_assertions/andsearches/BlackJAXNUTS— andsearches/MultiStartAdamwas never added.autofit_workspace/scripts/searches/mle.pyuses the same search and passes only because that workspace's release profile pinsPYAUTO_DISABLE_JAX: "0". Theautolens/autogalaxyguides construct the search but never.fit(), so they never reach the guard.Changes
Config only — no script logic, no library source, no public API.
config/build/env_vars_release.yaml— threeset: { PYAUTO_DISABLE_JAX: "0" }overrides, following thesearches/BlackJAXNUTSprecedent (this profile's header documents that overrides only everset:, neverunset:, a vardefaultspins):searches/MultiStartAdam— the blocking fix.searches/Dynesty_jax,searches/Nautilus_jax— these declareuse_jax=Truebut were also missing from the overrides, so they validated the NumPy path while presenting as JAX tests. UnlikeMultiStartAdamthey carry no backend guard, so they passed vacuously and nothing failed loudly — the same failure mode the profile's ownjax_assertions/note describes.config/build/env_vars.yaml(thesmokeenv profile) — oneunset: [PYAUTO_TEST_MODE, PYAUTO_DISABLE_JAX]forsearches/MultiStartAdam. ItsPYAUTO_TEST_MODE=2bypasses the sampler before_fit, so the script passed without ever executing its JAX path. Running it costs ~6s. Scoped toMultiStartAdam; the nested samplers stay bypassed under this profile on cost grounds.Verification
All run on this branch with the release-profile env (
PYAUTO_TEST_MODE=0 PYAUTO_DISABLE_JAX=0 JAX_ENABLE_X64=True):MultiStartAdam.pyDynesty_jax.pyNautilus_jax.pyMultiStartAdam.py(smoke-resolved env, both vars unset)No bug was hiding behind the two vacuous passes, so all three release overrides are safe to ship.
Resolver check.
_pattern_matchessubstring-matches against the full path including extension, so an under-specified pattern silently over-matches (searches/Nautiluswould also catchNautilus_jax.py). Droveautobuild.env_config.build_env_for_scriptover the real configs for everyscripts/searches/*.py:Nautilus.pyandDynestyStatic/Dynamic.pycorrectly stay atDISABLE_JAX=1— no over-match.Ship-gate legs
smoke (3.12/3.13)checks pass but do not exerciseMultiStartAdam(it is not insmoke_tests.txt), so they are not evidence for this change; the direct runs above are.Human signed off on the ship in-session (autonomy:
supervised, thebugcap). Merge stays human.🤖 Generated with Claude Code