RED reason (verbatim, pyauto-brain health assess, 2026-08-01)
✗ [validate] release validation FAILED (stage integrate)
Stage reports: guides/modeling/advanced/hierarchical.py TIMEOUT (1800s) in both
run 30672739606 (manual Stage 3, 2026-07-31 23:23 UTC)
and run 30686136529 (nightly, 2026-08-01 05:35 UTC).
The same script passed at 76.0s in the 2026-07-31 05:43 UTC run — a deterministic 2/2 regression from changes merged 2026-07-31 daytime.
Authorization
Human instruction, quoted verbatim from the live CLI session (2026-08-01 evening), which launched this release push:
"can you do a wake up and then do a release, fine if any blockers need sorting, a paper goes live on monday and i want the latest version to be out"
Recorded here as the authorization for this corrective PR against the RED reason above. (Given at session launch for "any blockers" rather than after the specific reason string was surfaced; noted for the calibration log.)
Root cause
e6279c5 (#1439, merged 2026-07-31) changed Nautilus.fit_multiprocessing from passing pool=self.number_of_cores (an int) to always constructing fork_context().Pool(self.number_of_cores) and passing the pool object — including when number_of_cores == 1.
nautilus itself treats an int specially (nautilus/sampler.py:286):
if pool[i] in [None, 1]:
pool[i] = None # fully serial, in-process
A real Pool(1) object bypasses that guard, so every likelihood evaluation is shipped to a single forked worker process. Under the release profile (JAX enabled), the autolens likelihood touches JAX (log_likelihood_penalty_from → jnp.array), and a forked child of a JAX-initialized parent deadlocks in XLA backend_compile_and_load — the classic fork-after-JAX-init hang.
py-spy evidence (local repro under the release env, PYAUTO_TEST_MODE=1 PYAUTO_DISABLE_JAX=0):
- main process:
nautilus … evaluate_likelihood → pool.map → wait (blocked forever)
- forked worker:
log_likelihood_penalty_from → jnp.array → … → backend_compile_and_load (stuck)
Why only hierarchical.py: it is the one release-set script that fits a FactorGraphModel(use_jax=False) with Nautilus — analysis._use_jax=True scripts route to fit_x1_cpu (pool=None) and JAX-vectorized likelihoods never touch the pool. expectation_propagation.py fits node-by-node through the EP optimiser, not this path.
Fix (this PR, narrow)
In fit_multiprocessing, construct the fork-context pool only when number_of_cores > 1; pass pool=None for a single core — restoring the pre-#1439 serial behaviour while keeping the fork pinning (the actual Python 3.14 forkserver fix) for genuine multi-core runs. One file + one test.
Tests / evidence
- Unit test:
Nautilus at number_of_cores=1 builds no multiprocessing pool (fork context not entered).
- Existing
test_fork_context.py suite still passes.
- Control-vs-patched under the release-profile env:
hierarchical.py hangs on current main (control, reproduced locally) and completes patched.
Validation plan
Merge → dispatch Stage 2 rehearsal (PyAutoHands) + Stage 3 release-integrate (PyAutoHeart) → pyauto-brain release validate --ingest → Heart re-verdict → scheduled nightly performs the release on green under the standing grant (PyAutoBuild#127).
Not claimed by this PR
autolens_test multi_dataset/jax_likelihood/delaunay.py intermittent TIMEOUT (07-30✗? no — 07-31 ✗, 08-01 ✗, passed 23:23 run at 18.2s; occurs across different library SHAs) is a separate pre-existing compile-side flake and is not cleared by this fix.
RED reason (verbatim,
pyauto-brain health assess, 2026-08-01)Stage reports:
guides/modeling/advanced/hierarchical.pyTIMEOUT (1800s) in bothrun 30672739606 (manual Stage 3, 2026-07-31 23:23 UTC)
and run 30686136529 (nightly, 2026-08-01 05:35 UTC).
The same script passed at 76.0s in the 2026-07-31 05:43 UTC run — a deterministic 2/2 regression from changes merged 2026-07-31 daytime.
Authorization
Human instruction, quoted verbatim from the live CLI session (2026-08-01 evening), which launched this release push:
Recorded here as the authorization for this corrective PR against the RED reason above. (Given at session launch for "any blockers" rather than after the specific reason string was surfaced; noted for the calibration log.)
Root cause
e6279c5 (#1439, merged 2026-07-31) changed
Nautilus.fit_multiprocessingfrom passingpool=self.number_of_cores(an int) to always constructingfork_context().Pool(self.number_of_cores)and passing the pool object — including whennumber_of_cores == 1.nautilus itself treats an int specially (
nautilus/sampler.py:286):A real
Pool(1)object bypasses that guard, so every likelihood evaluation is shipped to a single forked worker process. Under the release profile (JAX enabled), the autolens likelihood touches JAX (log_likelihood_penalty_from→jnp.array), and a forked child of a JAX-initialized parent deadlocks in XLAbackend_compile_and_load— the classic fork-after-JAX-init hang.py-spy evidence (local repro under the release env,
PYAUTO_TEST_MODE=1 PYAUTO_DISABLE_JAX=0):nautilus … evaluate_likelihood → pool.map → wait(blocked forever)log_likelihood_penalty_from → jnp.array → … → backend_compile_and_load(stuck)Why only
hierarchical.py: it is the one release-set script that fits aFactorGraphModel(use_jax=False)with Nautilus —analysis._use_jax=Truescripts route tofit_x1_cpu(pool=None) and JAX-vectorized likelihoods never touch the pool.expectation_propagation.pyfits node-by-node through the EP optimiser, not this path.Fix (this PR, narrow)
In
fit_multiprocessing, construct the fork-context pool only whennumber_of_cores > 1; passpool=Nonefor a single core — restoring the pre-#1439 serial behaviour while keeping the fork pinning (the actual Python 3.14 forkserver fix) for genuine multi-core runs. One file + one test.Tests / evidence
Nautilusatnumber_of_cores=1builds no multiprocessing pool (fork context not entered).test_fork_context.pysuite still passes.hierarchical.pyhangs on current main (control, reproduced locally) and completes patched.Validation plan
Merge → dispatch Stage 2 rehearsal (PyAutoHands) + Stage 3 release-integrate (PyAutoHeart) →
pyauto-brain release validate --ingest→ Heart re-verdict → scheduled nightly performs the release on green under the standing grant (PyAutoBuild#127).Not claimed by this PR
autolens_test multi_dataset/jax_likelihood/delaunay.pyintermittent TIMEOUT (07-30✗? no — 07-31 ✗, 08-01 ✗, passed 23:23 run at 18.2s; occurs across different library SHAs) is a separate pre-existing compile-side flake and is not cleared by this fix.