You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Three autolens_workspace_test JAX-gradient scripts TIMEOUT at the 300s per-script
smoke cap (PyAutoHeart workspace-smoke run 30858578587, 2026-08-03T22:25Z): imaging/jax_grad/pixelization.py, imaging/jax_grad/regularization.py, point_source/jax_grad/gradient.py. They are killed, not errored.
The question asked was whether this is a real slowdown (JIT compile regression, lost
caching) or a cap that was always marginal. The answer is mixed, and the current
tooling cannot fully settle it — which is itself the primary defect to fix.
What is established
point_source/jax_grad/gradient.py is definitively a budget problem. Run locally
under the resolved smoke profile it PASSES in 665.9s — 2.2x the cap, with no hang
and no correctness failure. Nothing about it fits in 300s.
Its stored baseline describes a different script. Heart's 39.24s entry is slugged autolens_test__scripts__jax_grad__point_source.json, i.e. the pre-#216 path,
measured 2026-07-30. Commit 50f1c33 (2026-07-31) then added solver blocks C-F: a pixel_scale_precision=1e-5 solver (100x finer than production) and 6-step FD sweeps
across four further models (+281 lines). It grew by design.
regularization.py has never completed in any recorded run. Its earlier
FAIL (103.5s) was the tfp-nightly/bessel_kve import gap
(workspace-validation.yml:247-254), i.e. time-to-failure, not time-to-success. It
loops over 4 mesh/regularization variants; a local partial run reached an early
variant at 131.5s, extrapolating to ~310-560s in CI. There is no passing baseline to
regress from.
Root cause of the cap mismatch. These scripts declare ENV: jax full_datasets.
Precisely: full_datasets unsets PYAUTO_SMALL_DATASETS and jax unsets PYAUTO_DISABLE_JAX; PYAUTO_TEST_MODE remains 2 (verified by resolving the
profile, not by reading docs). But PYAUTO_TEST_MODE=2 only bypasses AbstractSearch.fit, and these scripts run no search — they build Fitness and call jax.value_and_grad/finite differences directly. So test mode reduces nothing here:
they do full-resolution FD work in smoke exactly as in release, where the cap is
already 1800s with a written rationale (workspace-validation.yml:319-326). Smoke was
left at 300s on the premise that smoke work is reduced; for this class that premise
does not hold.
What is NOT established (deliberately not overclaimed)
Timings across the two runs that day:
script
06:31Z
22:25Z
delta
lp.py
40.0s
39.6s
-1%
mge.py
42.1s
41.8s
-0.7%
delaunay.py
84.6s
92.4s
+9%
knn.py
175.8s
200.0s
+14%
pixelization.py
244.8s
>300s
>= +23%
The slowdown scales monotonically with runtime. That is compatible with runner
contention — but equally with a mesh/inversion/XLA compile regression whose effect
grows with graph size, under which flat lp.py/mge.py timings are exactly what
you would expect. So the flat cheap scripts do not discriminate between the two
hypotheses, and the earlier claim that they did was too strong.
An earlier draft cited the profiling prompt's ">400s on 2026-07-13" as corroboration
that pixelization.py was always marginal. Withdrawn: commit 74673c8
(2026-07-23) retired variants and rewrote both gradient scripts, so that figure
describes an ancestor, not the current script. pixelization.py therefore has exactly
one successful observation (244.8s), which cannot establish a distribution.
No library change explains a targeted slowdown: the only inversion-adjacent commit in
the window, PyAutoArray #431 (5006f347), is gated behind PYAUTO_SMALL_DATASETS=1,
which these scripts unset — a no-op for them.
The blocker is that the evidence to settle this does not exist.build_util.py
discards subprocess.TimeoutExpired.stdout/stderr, recording only "Timed out after Ns". A timed-out script therefore reveals nothing about which
variant or block was executing. Raising the budget is not symptom-suppression here: a
process killed at 300s produces no measurement at all, so a realistic budget plus
preserved output is the instrument that makes the regression question answerable.
Plan
Preserve timeout stdout/stderr so a TIMEOUT says where it died.
Add parent-side per-script timeout resolution (the value is already reachable).
Give the jax_grad class a realistic budget, from measured durations.
Re-run and compare pixelization.py against its 244.8s baseline to settle the
regression question with data.
Leave smoke's 300s default untouched for every other script.
Preserve timeout output.build_util.py:391 (execute_script) and the
notebook path (execute_notebook, ~line 246) catch subprocess.TimeoutExpired
and drop e.stdout/e.stderr. Capture them into ScriptResult.error_message
(truncated tail). Do this FIRST — it is what makes the next measurement legible.
Per-script timeout, parent-side.build_util.py:12 reads TIMEOUT_SECS = int(os.environ.get("BUILD_SCRIPT_TIMEOUT", "300")) once at import
in the parent and applies it as subprocess.run(..., timeout=TIMEOUT_SECS), while
the per-script env from env_config.build_env_for_script is passed only to the
child — so a per-script value is silently ignored today.
Resolve the effective timeout from the env dict execute_script / execute_notebook already receive. Use the existing set: syntax, not a new schema key — validate_env_profiles.py:60
defines ALLOWED_OVERRIDE_KEYS = {"pattern", "set", "unset"}, so a timeout: key
would be rejected by profile validation. set: {BUILD_SCRIPT_TIMEOUT: "1800"}
validates today and needs no validator change.
Precedence. Because apply_profile writes over the copied ambient env, the
per-script value wins over the ambient global. Document this explicitly:
per-script profile value > ambient BUILD_SCRIPT_TIMEOUT > 300 default.
Note the trap that motivates it: run_all.py:256 exports BUILD_SCRIPT_TIMEOUT unconditionally, even when 300 was only the implicit CLI default — so an
"explicit global always wins" rule would make per-script values work under Heart's
workflow but be silently ignored under local run_all. Reject that rule for this
reason and record it.
Keep the SLOW banner honest.slow_skip_check.py:198 quotes build_util.TIMEOUT_SECS as "the" cap in the mega-run report. With per-script
budgets that figure is wrong for overridden scripts — the same
understated-cap failure that previously biased park/un-park decisions
(the "60s cap myth"). Surface the in-force per-script value or qualify the text.
Record provenance. Include the effective timeout in the result JSON so a future
TIMEOUT is self-describing.
Tests. Matching vs non-matching path; script AND notebook paths; malformed /
zero / negative values; precedence vs ambient global; that release's 1800s export
still applies where no override matches.
Phase 2 — measure, then set the budget (after phase 1 lands)
Run the three scripts with a generous provisional budget and record ACTUAL CI
durations. Local reference: gradient.py 665.9s PASS; calibration knn.py local
141.6s vs CI 200.0s (CI/local ~1.41), so gradient.py projects to ~940s in CI.
autolens_workspace_test/config/build/profile_smoke.yaml — add the override with
the measured basis in a comment.
Compare pixelization.py's completed duration against its 244.8s baseline. A
result near 245-300s indicates contention plus an inadequate cap; substantially
above indicates a genuine mesh/inversion regression, which then routes to draft/feature/profiling/profiling_agent_jax_compile_time_scope.md rather than
being absorbed here.
PyAutoHeart/.github/workflows/workspace-validation.yml:319-326 — correct the
"smoke mode is unchanged (still 300s)" comment.
Scope decision — pattern breadth
_pattern_matches (env_config.py:413) substring-matches patterns containing /, so jax_grad/ matches 8 scripts: the 6 imaging ones, point_source/jax_grad/gradient.py,
and interferometer/jax_grad/gradient.py (scripts/weak/jax_grad.py does NOT match —
no trailing slash). Family-wide is chosen deliberately over three explicit patterns: knn.py is already at 200.0s (67% of cap and rising) and would be the next failure.
Noted: interferometer/jax_grad/gradient.py is SLOW-skipped in no_run.yaml:47 for
flaking at the 1800s cap, so it will not run regardless — but it is direct evidence
that this family genuinely needs release-scale budgets.
Other failures in the same run: autolens_test, interferometer; autofit_test, jax_assertions; howtogalaxy, chapter_4_pixelizations. The durable speed-up remains
the Profiling Agent prompt; this task does not duplicate it.
Follow-ups found while investigating (file separately)
Every stored timing history is one value repeated 7x (a rolling-window fill, not 7
observations), so the "median of 7" regression ratio is a single-observation compare.
Local runs of lp.py fail assertions that pass in CI (identical JAX 0.10.2; numpy
2.2.6 local vs 2.4.6 CI). Local jax_grad assertion failures are therefore NOT
trustworthy evidence of source defects — worth its own investigation.
Original Prompt
Click to expand starting prompt
Original request (verbatim)
Three JAX-gradient script timeouts
In the PyAutoLabs workspace, three scripts TIMEOUT at the 300s smoke cap:
Evidence: PyAutoHeart workspace-smoke run 30858578587
(2026-08-03T22:25Z), jobs "smoke / run_scripts (3.12, autolens_test,
imaging)" and "(3.12, autolens_test, point_source)". All three are
TIMEOUT, not error — they never finished.
Work out whether this is real slowdown (JIT compile-time regression,
lost caching) or just a cap that was always marginal for these three:
check whether they ever passed in smoke and how close they were. Compare
against Heart's script_timing baselines if there's history. Fix the
cause, or — with an explicit reason — reclassify them; don't just raise
the cap silently. Route through start_dev.
Overview
Three
autolens_workspace_testJAX-gradient scripts TIMEOUT at the 300s per-scriptsmoke cap (PyAutoHeart workspace-smoke run 30858578587, 2026-08-03T22:25Z):
imaging/jax_grad/pixelization.py,imaging/jax_grad/regularization.py,point_source/jax_grad/gradient.py. They are killed, not errored.The question asked was whether this is a real slowdown (JIT compile regression, lost
caching) or a cap that was always marginal. The answer is mixed, and the current
tooling cannot fully settle it — which is itself the primary defect to fix.
What is established
point_source/jax_grad/gradient.pyis definitively a budget problem. Run locallyunder the resolved smoke profile it PASSES in 665.9s — 2.2x the cap, with no hang
and no correctness failure. Nothing about it fits in 300s.
Its stored baseline describes a different script. Heart's 39.24s entry is slugged
autolens_test__scripts__jax_grad__point_source.json, i.e. the pre-#216 path,measured 2026-07-30. Commit
50f1c33(2026-07-31) then added solver blocks C-F: apixel_scale_precision=1e-5solver (100x finer than production) and 6-step FD sweepsacross four further models (+281 lines). It grew by design.
regularization.pyhas never completed in any recorded run. Its earlierFAIL (103.5s) was the
tfp-nightly/bessel_kveimport gap(
workspace-validation.yml:247-254), i.e. time-to-failure, not time-to-success. Itloops over 4 mesh/regularization variants; a local partial run reached an early
variant at 131.5s, extrapolating to ~310-560s in CI. There is no passing baseline to
regress from.
Root cause of the cap mismatch. These scripts declare
ENV: jax full_datasets.Precisely:
full_datasetsunsetsPYAUTO_SMALL_DATASETSandjaxunsetsPYAUTO_DISABLE_JAX;PYAUTO_TEST_MODEremains2(verified by resolving theprofile, not by reading docs). But
PYAUTO_TEST_MODE=2only bypassesAbstractSearch.fit, and these scripts run no search — they buildFitnessand calljax.value_and_grad/finite differences directly. So test mode reduces nothing here:they do full-resolution FD work in smoke exactly as in release, where the cap is
already 1800s with a written rationale (
workspace-validation.yml:319-326). Smoke wasleft at 300s on the premise that smoke work is reduced; for this class that premise
does not hold.
What is NOT established (deliberately not overclaimed)
Timings across the two runs that day:
lp.pymge.pydelaunay.pyknn.pypixelization.pyThe slowdown scales monotonically with runtime. That is compatible with runner
contention — but equally with a mesh/inversion/XLA compile regression whose effect
grows with graph size, under which flat
lp.py/mge.pytimings are exactly whatyou would expect. So the flat cheap scripts do not discriminate between the two
hypotheses, and the earlier claim that they did was too strong.
An earlier draft cited the profiling prompt's ">400s on 2026-07-13" as corroboration
that
pixelization.pywas always marginal. Withdrawn: commit74673c8(2026-07-23) retired variants and rewrote both gradient scripts, so that figure
describes an ancestor, not the current script.
pixelization.pytherefore has exactlyone successful observation (244.8s), which cannot establish a distribution.
No library change explains a targeted slowdown: the only inversion-adjacent commit in
the window, PyAutoArray #431 (
5006f347), is gated behindPYAUTO_SMALL_DATASETS=1,which these scripts unset — a no-op for them.
The blocker is that the evidence to settle this does not exist.
build_util.pydiscards
subprocess.TimeoutExpired.stdout/stderr, recording only"Timed out after Ns". A timed-out script therefore reveals nothing about whichvariant or block was executing. Raising the budget is not symptom-suppression here: a
process killed at 300s produces no measurement at all, so a realistic budget plus
preserved output is the instrument that makes the regression question answerable.
Plan
pixelization.pyagainst its 244.8s baseline to settle theregression question with data.
Detailed implementation plan
Affected Repositories
Branch Survey
Suggested branch:
feature/jax-grad-smoke-timeout-budgetPhase 1 — PyAutoHands
build_util.py:391(execute_script) and thenotebook path (
execute_notebook, ~line 246) catchsubprocess.TimeoutExpiredand drop
e.stdout/e.stderr. Capture them intoScriptResult.error_message(truncated tail). Do this FIRST — it is what makes the next measurement legible.
build_util.py:12readsTIMEOUT_SECS = int(os.environ.get("BUILD_SCRIPT_TIMEOUT", "300"))once at importin the parent and applies it as
subprocess.run(..., timeout=TIMEOUT_SECS), whilethe per-script env from
env_config.build_env_for_scriptis passed only to thechild — so a per-script value is silently ignored today.
Resolve the effective timeout from the
envdictexecute_script/execute_notebookalready receive.Use the existing
set:syntax, not a new schema key —validate_env_profiles.py:60defines
ALLOWED_OVERRIDE_KEYS = {"pattern", "set", "unset"}, so atimeout:keywould be rejected by profile validation.
set: {BUILD_SCRIPT_TIMEOUT: "1800"}validates today and needs no validator change.
apply_profilewrites over the copied ambient env, theper-script value wins over the ambient global. Document this explicitly:
per-script profile value > ambient
BUILD_SCRIPT_TIMEOUT> 300 default.Note the trap that motivates it:
run_all.py:256exportsBUILD_SCRIPT_TIMEOUTunconditionally, even when 300 was only the implicit CLI default — so an
"explicit global always wins" rule would make per-script values work under Heart's
workflow but be silently ignored under local
run_all. Reject that rule for thisreason and record it.
slow_skip_check.py:198quotesbuild_util.TIMEOUT_SECSas "the" cap in the mega-run report. With per-scriptbudgets that figure is wrong for overridden scripts — the same
understated-cap failure that previously biased park/un-park decisions
(the "60s cap myth"). Surface the in-force per-script value or qualify the text.
TIMEOUT is self-describing.
zero / negative values; precedence vs ambient global; that release's 1800s export
still applies where no override matches.
Phase 2 — measure, then set the budget (after phase 1 lands)
durations. Local reference:
gradient.py665.9s PASS; calibrationknn.pylocal141.6s vs CI 200.0s (CI/local ~1.41), so
gradient.pyprojects to ~940s in CI.autolens_workspace_test/config/build/profile_smoke.yaml— add the override withthe measured basis in a comment.
pixelization.py's completed duration against its 244.8s baseline. Aresult near 245-300s indicates contention plus an inadequate cap; substantially
above indicates a genuine mesh/inversion regression, which then routes to
draft/feature/profiling/profiling_agent_jax_compile_time_scope.mdrather thanbeing absorbed here.
PyAutoHeart/.github/workflows/workspace-validation.yml:319-326— correct the"smoke mode is unchanged (still 300s)" comment.
Scope decision — pattern breadth
_pattern_matches(env_config.py:413) substring-matches patterns containing/, sojax_grad/matches 8 scripts: the 6 imaging ones,point_source/jax_grad/gradient.py,and
interferometer/jax_grad/gradient.py(scripts/weak/jax_grad.pydoes NOT match —no trailing slash). Family-wide is chosen deliberately over three explicit patterns:
knn.pyis already at 200.0s (67% of cap and rising) and would be the next failure.Noted:
interferometer/jax_grad/gradient.pyis SLOW-skipped inno_run.yaml:47forflaking at the 1800s cap, so it will not run regardless — but it is direct evidence
that this family genuinely needs release-scale budgets.
Key Files
PyAutoHands/autohands/build_util.py—TIMEOUT_SECS:12,execute_script:367,execute_notebook:219PyAutoHands/autohands/env_config.py—build_env_for_script:293,apply_profile:327,_pattern_matches:413PyAutoHands/autohands/validate_env_profiles.py—ALLOWED_OVERRIDE_KEYS:60PyAutoHands/autohands/run_all.py:256— unconditional exportPyAutoHands/autohands/slow_skip_check.py:198— banner figureautolens_workspace_test/config/build/profile_smoke.yamlPyAutoHeart/.github/workflows/workspace-validation.yml:319-326Out of scope
Other failures in the same run:
autolens_test, interferometer;autofit_test, jax_assertions;howtogalaxy, chapter_4_pixelizations. The durable speed-up remainsthe Profiling Agent prompt; this task does not duplicate it.
Follow-ups found while investigating (file separately)
script_timingslugs are path-derived, so the fix: validate the project before generate.py deletes notebooks/ #216 restructure orphaned everyjax_gradbaseline; no new-layout slug exists, so Heart accumulates no history.observations), so the "median of 7" regression ratio is a single-observation compare.
lp.pyfail assertions that pass in CI (identical JAX 0.10.2; numpy2.2.6 local vs 2.4.6 CI). Local jax_grad assertion failures are therefore NOT
trustworthy evidence of source defects — worth its own investigation.
Original Prompt
Click to expand starting prompt
Original request (verbatim)