Skip to content

Commit 84876af

Browse files
committed
merge: bring origin/main into claude/test-mode-bypass-assertion-ties-zl8yv6
Conflicts were confined to the three generated files (complete/index.md, dashboard.md, dashboard.html). Resolved by regenerating from the merged source of truth rather than by hand: python3 scripts/lifecycle.py index --apply pyauto-brain intake --apply dashboard lifecycle check + lifecycle index --check both OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018nDAxBEavkzb6Zkz1cYHef
2 parents 18ccb54 + 19311ef commit 84876af

9 files changed

Lines changed: 451 additions & 98 deletions
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
## local-pixel-scale-vs-dataset-pixel-scales
2+
- completed: 2026-08-24
3+
- issue: https://github.com/PyAutoLabs/autolens_workspace/issues/501
4+
- workspace-pr: https://github.com/PyAutoLabs/autolens_workspace/pull/502 (merged 85027bbb)
5+
- repos: autolens_workspace
6+
- notes: |
7+
Sweep fix for the literal-vs-dataset pixel-scale divergence found while validating
8+
PyAutoArray#430 / PR#431. A module-level `pixel_scale` literal was escaping its
9+
`from_fits` argument into arithmetic that ALSO read the loaded dataset. Under
10+
PYAUTO_SMALL_DATASETS=1 the loader (correctly) relabels capped data to 0.6, so the
11+
literal and dataset.pixel_scales disagreed and the arithmetic was silently wrong.
12+
Invisible in a normal run, because there the two values coincide.
13+
14+
THE PROMPT SAID "not a one-off" AND IT WAS RIGHT: 8 scripts, not 1. Three usage
15+
classes sharing one root cause:
16+
1. geometry — image_half_width = 0.5 * min(dataset_full.shape_native) * pixel_scale
17+
2. luminosity — / pixel_scale**2, per-pixel to per-arcsec^2, on a model fitted to
18+
the loaded dataset, so the conversion must use the dataset's scale
19+
3. mesh resolution — hilbert_pixels_from_pixel_scale, documented as scaling "with
20+
data quality", which under a cap IS 0.6
21+
22+
FIX: one rebind per file, `pixel_scale = float(dataset.pixel_scales[0])` immediately
23+
after the load. The literal keeps its correct and only role as the `from_fits`
24+
argument and as documentation of the real scale. The idiom was NOT invented here — it
25+
already existed at group/features/scaling_relation/modeling_for_luminosities.py:88,
26+
and multi_dataset/features/imaging_and_point_source/modeling.py:95 is a second
27+
precedent (explicit cap_array_2d_for_small_datasets call for its Array2D).
28+
29+
ONE FILE DELIBERATELY DIFFERENT: imaging/features/multi_gaussian_expansion/modeling.py
30+
had its literal never reaching from_fits, with its sole consumer one end of a sigma
31+
prior range whose OTHER end already read dataset.pixel_scales[0] — the two ends of one
32+
np.linspace, on adjacent lines, reading different scales. Removed the literal and
33+
inlined the value, making the disagreement unrepresentable rather than corrected.
34+
Matches line 566 of the same file, which already passed pixel_scales=dataset.pixel_scales[0].
35+
36+
PROMPT DRIFT, worth the pattern: the prompt cited slam.py:863 and a 0.1 literal. The
37+
file had moved to pixel_scale = 0.05 at line 834, arithmetic at 872. The 0.05 is what
38+
makes the prompt's own evidence exact — 0.5*16*0.05 - 0.1 = 0.30, the reported
39+
"Enlarged mask radius: 0.30". Under 0.1 it would have printed 0.70. Same class as the
40+
PyAutoArray#430 record's "two prompt claims proved wrong": a prompt written weeks
41+
before it runs drifts, and its line numbers are the first thing to go. Its ARGUMENT
42+
survived intact; only its coordinates rotted.
43+
44+
EXCLUSIONS, each checked rather than assumed (this was most of the work):
45+
- interferometer/features/advanced/potential_correction/start_here.py simulates its
46+
dataset in-memory via SimulatorInterferometer and never calls from_fits. Its literal
47+
BUILDS real_space_mask, so it is the source of truth. Untouched.
48+
- The Array2D.from_fits callers (imaging/data_preparation/{gui,examples/optional}/*,
49+
cluster/plot.py) are NOT affected: cap_array_2d_for_small_datasets is reached only
50+
from autoarray/dataset/imaging/dataset.py:339,344 (data + noise_map). Array2D.from_fits
51+
never routes through it. Verified against PyAutoArray main via raw fetch, not assumed —
52+
this is the single fact that kept the sweep from doubling in size.
53+
- guides/results/database/start_here.py: literal reaches from_fits only, mask already
54+
reads dataset.pixel_scales. Correct as-is.
55+
- Six multi_galaxy scripts carry the literal but never let it leave from_fits.
56+
57+
VERIFICATION GAP, SHIPPED KNOWINGLY — the important part of this record:
58+
The capped run was NEVER EXECUTED. The authoring session was web-github with no numpy
59+
and no autolens. Worse, and not obvious: green CI did not cover it either, because none
60+
of the 8 scripts appear in smoke_tests.txt. All 7 checks passed (3 workflow runs,
61+
pull_request event only) and told us nothing about the geometry. That gap was written
62+
into the PR body, the merge commit, and the closing issue comment rather than being
63+
allowed to read as validated.
64+
Merging ahead of it was judged acceptable because the rebind is EXACTLY a no-op in
65+
uncapped operation — float(dataset.pixel_scales[0]) returns the same value just passed
66+
to from_fits — so the blast radius for real users is nil, and the one script that
67+
exercises the capped path stays parked.
68+
Also no PyAutoHeart verdict: pyauto-heart was unreachable, so the ship gate's readiness
69+
leg never ran. /prm's note that "the gate ran at ship time" did not hold here.
70+
71+
STILL PARKED: multi_galaxy/features/scaling_relation/slam stays in no_run.yaml, its
72+
NEEDS_FIX reason rewritten to name this cause instead of the 0.0-luminosity one that
73+
PR#431 fixed. Un-parking is filed as
74+
draft/maintenance/workspaces/unpark_multi_galaxy_scaling_relation_slam.md and must wait
75+
on a capped run exiting 0. This is the direct lesson of PR#312, which un-parked
76+
group/slam as "PriorException fixed" without re-running it and cost a full cycle — the
77+
same trap recorded in the small-datasets-loader-pixel-scales record. Not repeating it.
78+
79+
ENVIRONMENT NOTES: no gh CLI (GitHub MCP tools throughout). ipynb-py-convert would not
80+
install — Debian-patched setuptools raises AttributeError: install_layout on its
81+
setup.py — so the genuine upstream module was installed by hand into user site-packages
82+
with a matching console script. Notebooks were then regenerated through the real
83+
PyAutoHands per-script pipeline (py_to_notebook + inject_colab_setup) scoped to the 8
84+
scripts, NOT via generate.py, which rmtree's the whole notebooks/ tree. Every notebook
85+
diff mirrored its script diff line-for-line, which incidentally proved no committed
86+
notebook was stale.
87+
88+
GOTCHA for future web-github sessions: a --depth 1 clone pins remote.origin.fetch to
89+
main only, so `git push -u` creates the remote branch and writes branch.*.merge but no
90+
refs/remotes/origin/<branch> ever exists locally. @{u} then fails and tooling reports
91+
"unpushed commits / no remote branch" for work that is fully pushed. Fix is to add the
92+
branch's refspec and refetch, not to re-push.
93+
94+
## Original prompt
95+
96+
# Scripts derive geometry from a hardcoded pixel_scale while the dataset carries a corrected one
97+
98+
Type: bug
99+
Target: autolens_workspace
100+
Repos:
101+
- autolens_workspace
102+
Difficulty: small
103+
Autonomy: supervised
104+
Priority: normal
105+
Status: issued
106+
Filed: 2026-08-03 (backfilled from git)
107+
Issued: 2026-08-24
108+
109+
Found while validating PyAutoArray#430 / PR#431 (the small-datasets loader fix), 2026-08-03.
110+
111+
## The bug
112+
113+
Workspace scripts declare a module-level `pixel_scale` literal (the dataset's true
114+
scale in normal operation, e.g. `0.1`) and then use it in geometry arithmetic
115+
*alongside* values read from the loaded dataset. Under `PYAUTO_SMALL_DATASETS=1`
116+
the loader now correctly relabels capped data to `0.6`, so the script's literal
117+
and `dataset.pixel_scales` disagree and the arithmetic silently produces nonsense.
118+
119+
Concrete instance — `scripts/multi_galaxy/features/scaling_relation/slam.py:863`:
120+
121+
image_half_width = 0.5 * min(dataset_full.shape_native) * pixel_scale
122+
123+
mask_radius_larger = min(
124+
max(mask_radius, float(galaxy_distances.max()) + 0.5), image_half_width - 0.1
125+
)
126+
127+
`shape_native` comes from the capped dataset (16) but `pixel_scale` is the script's
128+
`0.1` literal, while the mask a few lines later is built from
129+
`dataset_full.pixel_scales` (now `0.6`). The run prints:
130+
131+
Standard mask radius: 3.0
132+
Enlarged mask radius: 0.30
133+
134+
— the "enlarged" mask is an order of magnitude *smaller* than the standard one. The
135+
resulting mask has no unmasked pixels, and the failure surfaces as:
136+
137+
File autoarray/operators/convolver.py:112, in ConvolverState.__init__
138+
y_min, y_max = ys.min(), ys.max()
139+
ValueError: zero-size array to reduction operation minimum which has no identity
140+
141+
## Not a regression
142+
143+
Control-tested on unpatched `main`: the same script fails *earlier*, with the
144+
documented `Measured luminosity is 0.0` ValueError. PR#431 fixes that root cause and
145+
this latent bug is what lies behind it. The script is already parked in
146+
`config/build/no_run.yaml` as `multi_galaxy/features/scaling_relation/slam` and must
147+
stay parked until this is fixed — update its NEEDS_FIX reason, which currently names
148+
only the 0.0-luminosity cause.
149+
150+
## Scope: this is a class, not a one-off
151+
152+
Do NOT fix only line 863. Sweep the workspace for scripts that mix a local
153+
`pixel_scale` literal with dataset-derived geometry (`shape_native`,
154+
`pixel_scales`, mask radii, `image_half_width`-style arithmetic). The fix is to
155+
derive geometry from `dataset.pixel_scales` rather than the literal — the literal
156+
stays as the `from_fits` argument, which is its correct and only role.
157+
158+
Verification must include a capped-run pass, since the two values coincide in
159+
normal runs and the bug is invisible there.
160+
161+
## Do not
162+
163+
Do not "fix" this by reverting the loader to keep the caller's uncapped scale — that
164+
is PyAutoArray#430, and it mislabels the frame 6x. The loader is right; the scripts
165+
are inconsistent.

complete/2026/08/smoke-surface-retime-sweep.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,12 @@ had shipped that morning as `complete/2026/08/smoke-timings-dataset.md`.
7272

7373
- `mge_group` higher-cap retime (the one surviving SLOW marker).
7474
- The two filed bug prompts above.
75-
- Trim the 900 s `jax_grad/` cap override in autolens `profile_smoke.yaml`
76-
(measured worst case 61 s; ~15× oversized).
75+
- ~~Trim the 900 s `jax_grad/` cap override in autolens `profile_smoke.yaml`
76+
(measured worst case 61 s; ~15× oversized).~~ **Withdrawn 2026-08-24 (same
77+
day):** the 61 s figure was one script; the cap's measured basis is the
78+
weekly workspace-smoke channel, where `point_source/jax_grad/gradient.py`
79+
runs at 568.2 s (63 % of the budget, run 30938311069) and two more family
80+
members exceed 250 s — all live and unskipped. The cap stays.
7781
- `draft/maintenance/pyautoheart/weekly_smoke_timings_artifact_naming.md`
7882
the weekly validation legs' timings land only inside `results-*` zips.
7983

complete/index.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Token-light navigation over the finished-work records (schema:
66
only then grep a dated bucket. Curators: edit the band between the CURATED
77
markers; everything below GENERATED is rebuilt.
88

9-
1101 records across 7 buckets.
9+
1102 records across 7 buckets.
1010

1111
<!-- CURATED:START -->
1212
## Highlights
@@ -109,6 +109,7 @@ _(curate hard-won records here — survives regeneration.)_
109109
- [latex-raw-string-docstrings](2026/08/latex-raw-string-docstrings.md) — one issue, six PRs
110110
- [lazy-heavy-imports](2026/08/lazy-heavy-imports.md) — Deferred all heavy non-essential imports to first use. `import autolens` 4.07s → 1.2–1.3s
111111
- [llms-txt-census-fixes](2026/08/llms-txt-census-fixes.md)
112+
- [local-pixel-scale-vs-dataset-pixel-scales](2026/08/local-pixel-scale-vs-dataset-pixel-scales.md)
112113
- [markdown-renderings-2a-leftovers](2026/08/markdown-renderings-2a-leftovers.md)
113114
- [mask1d-shape-native-scalar-widening](2026/08/mask1d-shape-native-scalar-widening.md)
114115
- [memory-surfaces-stale-names](2026/08/memory-surfaces-stale-names.md) — auto-closed on merge

0 commit comments

Comments
 (0)