From 3c8c652bb2e9db4b3ecb4e005ddadcbb2d603260 Mon Sep 17 00:00:00 2001 From: Jammy2211 Date: Sat, 16 May 2026 15:16:04 +0100 Subject: [PATCH] =?UTF-8?q?fix:=20build=5Freadme.py=20=E2=80=94=20probe=20?= =?UTF-8?q?correct=20JIT-time=20keys=20+=20handle=20NaN?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 4 follow-up bug surfaced when running the dashboard generator against real artifacts produced today on this machine. Bug 1 — key-probe mismatch -------------------------- The shipped likelihood scripts emit `full_pipeline_single_jit` (no `_s` suffix) and the datacube script emits `full_pipeline_cube_single_jit`, but `_likelihood_headline_seconds` was only probing for `_s`-suffixed variants nested under `summary` / `aggregate`. Result: every cell in every auto-table rendered `—` even when fresh artifacts were present. Fix: prepend `("full_pipeline_single_jit",)` and `("full_pipeline_cube_single_jit",)` to the probe path list. The older `_s`-suffixed and nested-under-`summary` variants stay in the list for forward-compat with any historic artifacts that might land later. Bug 2 — NaN renders as `nan s` ------------------------------ Datacube scripts emit `full_pipeline_cube_single_jit = NaN` when the JIT-compiled cube pipeline doesn't converge (real signal, not a bug in the dashboard). Python's `json.loads` parses that as `float('nan')`, which slipped through `_likelihood_headline_seconds` unchanged and rendered as `nan s` in the table. Fix: explicit `math.isnan` guard returning None, so `_format_time` renders the cell as `—`. Matches the semantic of "no data" while preserving the signal that the artifact exists but the measurement didn't land. Verification ------------ Ran the 4 known-clean scripts in the canonical autolens_profiling repo today (Intel i9-10885H, CPU-only JAX, PyAutoLens 2026.5.14.2). With this fix, the headline auto-table renders: | likelihood/imaging | mge.py | hst | 106.8 ms | | likelihood/interferometer| mge.py | sma | 38.5 ms | | likelihood/datacube | delaunay.py | hannah | — | (NaN -> `—`) | (simulators table) | imaging.py | — | 3.12 s | `build_readme.py --check` exits 0 on a second run — idempotence is preserved by this fix. Co-Authored-By: Claude Opus 4.7 (1M context) --- scripts/build_readme.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/scripts/build_readme.py b/scripts/build_readme.py index e6bbaff..9ce91d1 100644 --- a/scripts/build_readme.py +++ b/scripts/build_readme.py @@ -169,11 +169,19 @@ def _likelihood_headline_seconds(art: Artifact) -> Optional[float]: Robust to the slight key-shape variation across the imaging / interferometer / point_source / datacube JSON layouts. """ + import math + data = art.data - # Imaging mge/pixelization/delaunay JSON shape: top-level key per-step - # plus aggregates at end; the full-pipeline number is under "summary" - # in some scripts and at top-level in others. Try several keys. + # Top-level keys observed in shipped artifacts: + # imaging/{mge,pixelization,delaunay} -> "full_pipeline_single_jit" + # interferometer/{mge,pix,delaunay} -> "full_pipeline_single_jit" + # point_source/{image_plane,source_pl} -> "full_pipeline_single_jit" + # datacube/delaunay -> "full_pipeline_cube_single_jit" + # Older internal-_developer artifacts also used a "_s" suffix or + # nested under "summary" / "aggregate" — kept here for forward-compat. for path in ( + ("full_pipeline_single_jit",), + ("full_pipeline_cube_single_jit",), ("summary", "full_pipeline_single_jit_s"), ("summary", "full_pipeline_s"), ("aggregate", "full_pipeline_single_jit_s"), @@ -189,7 +197,12 @@ def _likelihood_headline_seconds(art: Artifact) -> Optional[float]: ok = False break if ok and isinstance(node, (int, float)): - return float(node) + value = float(node) + # NaN signals "the JIT didn't converge / not measurable" — render + # as `—` rather than `nan s` in the dashboard. + if math.isnan(value): + return None + return value return None